PG Vector 入门教程

项目介绍

PG Vector 是 PostgreSQL 的一个开源扩展,专注于在PostgreSQL数据库中存储和查询向量数据。它提供了高效的向量相似度搜索功能,使PostgreSQL能够处理机器学习和AI应用中的向量数据。

主要功能

  • 向量存储:在PostgreSQL中存储向量数据
  • 向量相似度搜索:支持余弦相似度、欧氏距离和曼哈顿距离等多种相似度计算
  • 索引支持:为向量数据创建索引,提高查询性能
  • 与PostgreSQL集成:无缝集成到PostgreSQL生态系统
  • 多语言支持:支持多种编程语言的客户端库

项目特点

  • 开源免费:完全开源,可自由使用和定制
  • 高性能:针对向量搜索进行了优化
  • 易于集成:与PostgreSQL无缝集成
  • 可靠性:基于PostgreSQL的稳定性和可靠性
  • 灵活性:支持多种向量相似度计算方法

安装与配置

安装步骤

  1. 安装PostgreSQL(如果尚未安装)
# Ubuntu/Debian
sudo apt update
sudo apt install postgresql postgresql-contrib

# CentOS/RHEL
sudo yum install postgresql-server postgresql-contrib
sudo postgresql-setup --initdb
sudo systemctl start postgresql

# macOS
brew install postgresql
brew services start postgresql
  1. 安装PG Vector扩展
# 从源码编译安装
git clone https://github.com/pgvector/pgvector.git
cd pgvector
make
make install

# 或者使用包管理器(某些系统)
sudo apt install postgresql-15-pgvector
  1. 启用PG Vector扩展
-- 连接到PostgreSQL
psql -U postgres

-- 创建扩展
CREATE EXTENSION vector;

基本配置

  1. 创建包含向量列的表
-- 创建产品表,包含向量列
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    description TEXT,
    price DECIMAL(10, 2),
    embedding VECTOR(1536) -- 1536维向量
);
  1. 为向量列创建索引
-- 创建余弦相似度索引
CREATE INDEX products_embedding_idx ON products USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

-- 或者创建欧氏距离索引
CREATE INDEX products_embedding_idx ON products USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);

核心概念

1. 向量类型(Vector Type)

PG Vector提供了vector数据类型,用于存储向量数据。向量的维度在创建表时指定。

2. 相似度函数(Similarity Functions)

  • vector_cosine_distance(a, b):计算两个向量的余弦距离
  • vector_l2_distance(a, b):计算两个向量的欧氏距离
  • vector_dot_product(a, b):计算两个向量的点积

3. 操作符(Operators)

  • <->:计算欧氏距离
  • <#>:计算负点积(用于排序)
  • <=>:计算余弦距离

4. 索引(Index)

PG Vector支持使用ivfflat索引类型为向量列创建索引,提高查询性能。

5. 列表参数(Lists Parameter)

创建索引时的lists参数控制索引的粒度,影响查询性能和内存使用。

基本使用

插入向量数据

-- 插入产品数据
INSERT INTO products (name, description, price, embedding)
VALUES
('Smartphone', 'A high-end smartphone with advanced features', 999.99, '[0.1, 0.2, 0.3, ..., 0.9]'),
('Laptop', 'A powerful laptop for gaming and productivity', 1499.99, '[0.2, 0.3, 0.4, ..., 0.8]'),
('Headphones', 'Noise-canceling headphones with excellent sound quality', 299.99, '[0.3, 0.4, 0.5, ..., 0.7]');

向量相似度搜索

-- 余弦相似度搜索
SELECT id, name, description, price, embedding <=> '[0.15, 0.25, 0.35, ..., 0.85]' AS similarity
FROM products
ORDER BY similarity ASC
LIMIT 3;

-- 欧氏距离搜索
SELECT id, name, description, price, embedding <-> '[0.15, 0.25, 0.35, ..., 0.85]' AS distance
FROM products
ORDER BY distance ASC
LIMIT 3;

-- 点积搜索
SELECT id, name, description, price, vector_dot_product(embedding, '[0.15, 0.25, 0.35, ..., 0.85]') AS dot_product
FROM products
ORDER BY dot_product DESC
LIMIT 3;

更新和删除向量数据

-- 更新向量数据
UPDATE products
SET embedding = '[0.12, 0.22, 0.32, ..., 0.92]'
WHERE id = 1;

-- 删除向量数据
DELETE FROM products
WHERE id = 1;

高级特性

1. 批量插入向量数据

import psycopg2
import numpy as np

# 连接到PostgreSQL
conn = psycopg2.connect(
    host="localhost",
    database="postgres",
    user="postgres",
    password="your-password"
)
cur = conn.cursor()

# 生成随机向量
def generate_vector(dim):
    return np.random.rand(dim).tolist()

# 批量插入数据
products = []
for i in range(1000):
    name = f"Product {i}"
    description = f"Description for product {i}"
    price = 100 + i * 10
    embedding = generate_vector(1536)
    products.append((name, description, price, embedding))

# 执行批量插入
cur.executemany(
    "INSERT INTO products (name, description, price, embedding) VALUES (%s, %s, %s, %s)",
    products
)

conn.commit()
cur.close()
conn.close()

2. 使用索引提高性能

-- 创建索引(在数据插入后)
CREATE INDEX products_embedding_idx ON products USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

-- 验证索引是否使用
EXPLAIN ANALYZE
SELECT id, name, description, price, embedding <=> '[0.15, 0.25, 0.35, ..., 0.85]' AS similarity
FROM products
ORDER BY similarity ASC
LIMIT 3;

3. 结合其他PostgreSQL功能

-- 结合全文搜索
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT,
    embedding VECTOR(1536)
);

-- 创建全文搜索索引
CREATE INDEX documents_content_idx ON documents USING gin(to_tsvector('english', content));

-- 结合向量搜索和全文搜索
SELECT id, title, content, embedding <=> '[0.1, 0.2, 0.3, ..., 0.9]' AS similarity
FROM documents
WHERE to_tsvector('english', content) @@ to_tsquery('english', 'machine learning')
ORDER BY similarity ASC
LIMIT 5;

实际应用案例

案例1:产品推荐系统

场景:基于用户偏好推荐相关产品。

实现步骤

  1. 创建产品表和用户表
  2. 为产品和用户生成向量嵌入
  3. 使用向量相似度计算推荐产品
  4. 部署推荐系统

示例

-- 创建用户表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    preferences TEXT,
    embedding VECTOR(1536)
);

-- 插入用户数据
INSERT INTO users (name, preferences, embedding)
VALUES ('John Doe', 'I like high-quality electronics with good sound quality', '[0.1, 0.2, 0.3, ..., 0.9]');

-- 基于用户向量推荐产品
SELECT p.id, p.name, p.description, p.price, p.embedding <=> u.embedding AS similarity
FROM products p, users u
WHERE u.id = 1
ORDER BY similarity ASC
LIMIT 3;

案例2:语义搜索引擎

场景:构建基于语义的文档搜索引擎。

实现步骤

  1. 创建文档表
  2. 为文档生成向量嵌入
  3. 实现语义搜索接口
  4. 部署搜索引擎

示例

import psycopg2
from sentence_transformers import SentenceTransformer

# 加载嵌入模型
model = SentenceTransformer('all-MiniLM-L6-v2')

# 连接到PostgreSQL
conn = psycopg2.connect(
    host="localhost",
    database="postgres",
    user="postgres",
    password="your-password"
)
cur = conn.cursor()

# 创建文档表
cur.execute("""
CREATE TABLE IF NOT EXISTS documents (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT,
    embedding VECTOR(384)
);
""")

# 插入文档数据
documents = [
    ("Introduction to Machine Learning", "Machine learning is a subset of artificial intelligence that focuses on building systems that can learn from data."),
    ("Deep Learning Fundamentals", "Deep learning is a branch of machine learning that uses neural networks with many layers."),
    ("Natural Language Processing", "Natural language processing is a field of AI that focuses on the interaction between computers and human language.")
]

for title, content in documents:
    # 生成嵌入
    embedding = model.encode(content).tolist()
    # 插入数据
    cur.execute(
        "INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s)",
        (title, content, embedding)
    )

conn.commit()

# 语义搜索
query = "What is deep learning?"
query_embedding = model.encode(query).tolist()

cur.execute("""
SELECT id, title, content, embedding <=> %s AS similarity
FROM documents
ORDER BY similarity ASC
LIMIT 2;
""", (query_embedding,))

results = cur.fetchall()
print("Search results:")
for row in results:
    id, title, content, similarity = row
    print(f"Title: {title}")
    print(f"Content: {content[:100]}...")
    print(f"Similarity: {similarity}")
    print()

cur.close()
conn.close()

案例3:图像相似性搜索

场景:基于图像相似性搜索相关图片。

实现步骤

  1. 创建图像表
  2. 为图像生成向量嵌入
  3. 实现图像相似性搜索接口
  4. 部署图像搜索系统

示例

import psycopg2
from PIL import Image
import numpy as np
from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
from tensorflow.keras.preprocessing import image

# 加载图像嵌入模型
model = ResNet50(weights='imagenet', include_top=False, pooling='avg')

# 连接到PostgreSQL
conn = psycopg2.connect(
    host="localhost",
    database="postgres",
    user="postgres",
    password="your-password"
)
cur = conn.cursor()

# 创建图像表
cur.execute("""
CREATE TABLE IF NOT EXISTS images (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    description TEXT,
    embedding VECTOR(2048)
);
""")

# 生成图像嵌入
def get_image_embedding(img_path):
    img = image.load_img(img_path, target_size=(224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    embedding = model.predict(x)[0].tolist()
    return embedding

# 插入图像数据
images = [
    ("cat.jpg", "A photo of a cat"),
    ("dog.jpg", "A photo of a dog"),
    ("car.jpg", "A photo of a car")
]

for name, description in images:
    # 生成嵌入
    embedding = get_image_embedding(name)
    # 插入数据
    cur.execute(
        "INSERT INTO images (name, description, embedding) VALUES (%s, %s, %s)",
        (name, description, embedding)
    )

conn.commit()

# 图像相似性搜索
query_image = "query_cat.jpg"
query_embedding = get_image_embedding(query_image)

cur.execute("""
SELECT id, name, description, embedding <-> %s AS distance
FROM images
ORDER BY distance ASC
LIMIT 2;
""", (query_embedding,))

results = cur.fetchall()
print("Similar images:")
for row in results:
    id, name, description, distance = row
    print(f"Name: {name}")
    print(f"Description: {description}")
    print(f"Distance: {distance}")
    print()

cur.close()
conn.close()

总结与展望

PG Vector作为PostgreSQL的一个强大扩展,为在PostgreSQL中存储和查询向量数据提供了全面的工具和功能。通过本文的介绍,你应该已经了解了PG Vector的核心概念、基本使用方法和高级特性。

关键优势

  • 开源免费,可自由使用和定制
  • 高性能,针对向量搜索进行了优化
  • 易于集成,与PostgreSQL无缝集成
  • 可靠性,基于PostgreSQL的稳定性和可靠性
  • 灵活性,支持多种向量相似度计算方法

应用前景

  • 产品推荐系统
  • 语义搜索引擎
  • 图像相似性搜索
  • 自然语言处理应用
  • 个性化推荐系统

未来发展

PG Vector团队持续改进扩展,未来可能会:

  • 支持更多的向量相似度计算方法
  • 优化索引性能,支持更大规模的向量数据
  • 提供更多的向量处理函数
  • 增强与机器学习框架的集成
  • 提供更多行业特定的解决方案

通过不断学习和实践,你可以利用PG Vector构建更加智能、高效的向量搜索和推荐系统,为各种场景提供有价值的AI解决方案。