跳至主要内容

pgvector 教程:将向量搜索集成到 PostgreSQL

了解如何使用 pgvector 为 PostgreSQL 增强向量搜索能力。本教程将引导您完成安装、基础操作与与 AI 工具的集成。
· 10分钟 阅读

使用 AI 探索

得益于生成式 AI 和大型语言模型生态的进步,向量搜索在近年愈发流行。

向量搜索是一种信息检索方法,将文档与查询表示为向量而非纯文本。通过大型、已训练的神经网络,可以把文本、图像、视频等非结构化数据转换为向量,从而获得这种数字化表示。

传统关系型数据库并未针对大规模向量数据进行优化。因此,过去几年出现了许多开源与商用的向量数据库。然而,对许多公司而言,为向量单独部署一套与主数据库分离的系统并不理想。

这就是 pgvector 的用武之地——它是 PostgreSQL 的强大扩展,将向量相似度搜索能力引入这一最受欢迎的关系型数据库之一。

在本教程中,我们将探索 pgvector 的特性,并演示它如何助您开展工作。

什么是 pgvector?

pgvector 是一款面向 PostgreSQL 的开源扩展,新增了对向量操作与相似度搜索的支持。它允许您在 PostgreSQL 数据库中直接存储、索引并查询向量数据。

这种集成将向量操作的能力带入您现有的 PostgreSQL 基础设施,非常适合涉及嵌入、推荐系统与相似度检索的应用。

pgvector 的功能包括:

  • 高效存储稠密向量数据
  • 使用多种距离度量进行快速相似度搜索
  • 与 PostgreSQL 现有查询规划与索引机制集成
  • 支持精确与近似的最近邻搜索

pgvector 与向量数据库的重要性

向量数据库是专门为存储与查询多维向量数据而设计的数据库。这种能力在现代机器学习应用中尤为重要,包括推荐系统、图像检索与自然语言处理等场景。

一张展示不同类型非关系型数据库的图片,标题为

向量需要一种全新的数据库——图片来源。

传统的关系型数据库难以高效处理高维数据并执行相似度搜索。而向量数据库针对这些任务进行了优化,能够基于向量的接近度或相似性快速而准确地检索数据。

这种方法让搜索能够基于语义或上下文相关性,从而比传统数据库的精确匹配更能提供有意义的结果。

例如,向量数据库可以:

  • 基于旋律与节奏,搜索与某段曲调相契合的歌曲。
  • 发现与某篇文章在主题与视角上相近的其他文章。
  • 识别在特性与评价上与某款设备相似的电子产品。

那么,如何将文本或图像等非结构化数据转换成数字?答案是嵌入(embeddings)。

嵌入是将非结构化数据转换为固定长度数值向量的过程,能够捕捉数据中固有的语义与关系。这通过大型神经网络实现:网络学习在连续向量空间中表示数据,使相似项彼此更接近。

展示向量数据库如何工作的图片

向量数据库如何工作?图片来源。

如何使用 pgvector:分步指南

本节将带您完成 pgvector 的设置、基础功能使用,并通过与 OpenAI 的集成搭建一个简单应用。

我们将涵盖安装、基础操作、索引,以及与 Python 和 LangChain 的集成。

1. 先决条件

要跟进本教程,您应具备 SQL 与 PostgreSQL 的基础知识,并熟悉 Python 编程。

在开始之前,请确保具备以下条件:

  • 已在系统上安装 PostgreSQL 11 或更高版本
  • Python 3.7 或更高版本(用于集成部分)
  • 一个 OpenAI API 密钥(用于语义搜索应用)

2. 如何安装 pgvector

1. 首先,确保已安装PostgreSQL 开发文件。在 Ubuntu 或 Debian 上,您可以通过以下命令安装:

sudo apt-get install postgresql-server-dev-all

如果您使用 Windows,可从官网下载 PostgreSQL 安装包。

2. 克隆 pgvector 的 GitHub 仓库:

git clone https://github.com/pgvector/pgvector.git

3. 构建并安装 pgvector 扩展:

cd pgvector
make
sudo make install

如果您是 Windows 用户,请确保在 Visual Studio Code 中安装了 C++ 支持。官方安装文档提供了分步指引。

4. 连接到您的 PostgreSQL 数据库:

连接与操作 PostgreSQL 数据库有多种方式:pgAdmin 是最常用的图形界面之一。或者,您也可以使用 pSQL(PostgreSQL 命令行界面)或 VS Code 的 PostgreSQL 扩展。

5. 连接数据库后,创建扩展:

CREATE EXTENSION vector;

pgvector 的 pgAdmin 界面

pgAdmin 界面

3. pgvector 的基础用法

现在我们已经安装了 pgvector,来看看它的基本用法。

1. 要在 PostgreSQL 中使用 pgvector 扩展搭建首个向量库,让我们创建一张用于存储向量数据的表:

CREATE TABLE items (
  id SERIAL PRIMARY KEY,
  embedding vector(3)
);

这会创建名为 items 的表,包含 id 列与类型为 vector(3) 的 embedding 列,用于存储三维向量。

2. 接下来,往表中插入一些数据:

INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[1,1,1]');

3. 现在可以执行向量操作。例如,查找与向量 [2,3,4] 最近的邻居:

SELECT * FROM items ORDER BY embedding <-> '[2,3,4]' LIMIT 1;

该查询使用 <-> 运算符来计算向量间的欧氏距离。

4. 我们也可以使用其他距离度量,例如余弦距离:

SELECT * FROM items ORDER BY embedding <=> '[2,3,4]' LIMIT 1;

<=> 运算符用于计算向量间的余弦距离。

4. 使用 pgvector 为向量数据建立索引

在包括 pgvector 在内的向量数据库中,索引对于提升搜索性能至关重要,尤其是在数据集不断扩大的情况下。

索引的重要性不言而喻,主要体现在以下几方面:

  • 其一,显著提升速度。没有索引时,每次相似度搜索都需要全表扫描,将查询向量与库中每个向量比较。随着数据增长,这会愈发耗时。索引通过建立结构,大幅加速检索。
  • 其二,提升可扩展性,使数据库能够高效管理更大的数据集。随着向量数量增加,建立良好的索引可以保持搜索性能稳定。
  • 其三,提升资源效率,在搜索过程中降低 CPU 与 I/O 负载。对于高并发或资源受限的系统尤为重要,确保在压力场景下依然平稳运行。

pgvector 提供两类索引:ivfflat 与 hnsw。二者各有侧重:

  • IVFFlat(倒排文件平面)索引:
    • 适用于精确最近邻搜索
    • 将向量空间划分为多个簇,先定位相关簇以加速搜索
    • 在速度与准确性之间有良好平衡
  • HNSW(分层可导航小世界)索引:
    • 专为近似最近邻搜索设计
    • 创建图结构以在向量间快速导航
    • 速度极快,但偶尔可能错过绝对最近邻

使用建议:

  • 当需要精确结果且能接受稍慢的搜索时,使用 IVFFlat
  • 当需要更快的搜索且能接受轻微不准确时,使用 HNSW

1. 创建一个 ivfflat 索引:

CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

这会使用 IVFFlat 算法创建索引,适用于精确最近邻搜索。

2. 对于近似最近邻搜索,可以使用 hnsw 索引:

CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);

创建索引后,查询会在合适的情况下自动使用索引。

5. pgvector 与其他工具的集成

pgvector 支持与若干框架集成,使我们更易于操作向量数据库。下面介绍两个常用选项:Python 与 LangChain。

在 Python 中使用 pgvector

可借助 psycopg2 库轻松将 pgvector 集成到 Python。我们来搭建 Python 环境并完成一些基础操作。

1. 首先,安装所需库:

!pip install psycopg2-binary numpy

2. 然后,编写一个 Python 脚本与向量数据库交互:

import psycopg2
import numpy as np

# Connect to the database
conn = psycopg2.connect("dbname=your_database user=your_username")
cur = conn.cursor()

# Insert a vector
embedding = np.array([1.5, 2.5, 3.5])
cur.execute("INSERT INTO items (embedding) VALUES (%s)", (embedding.tolist(),))

# Perform a similarity search
query_vector = np.array([2, 3, 4])
cur.execute("SELECT * FROM items ORDER BY embedding <-> %s LIMIT 1", (query_vector.tolist(),))
result = cur.fetchone()
print(f"Nearest neighbor: {result}")

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

此脚本演示了如何插入向量并在 Python 中执行相似度搜索。

在 LangChain 中使用 pgvector

pgvector 也可与 LangChain 集成,这是一个用于构建大语言模型应用的流行框架。

下面是将 pgvector 用作 LangChain 向量存储的简单示例:

from langchain_postgres.vectorstores import PGVector
from langchain.embeddings.openai import OpenAIEmbeddings

# Set up the connection string and embedding function
connection_string = "postgresql://user:pass@localhost:5432/db_name"
embedding_function = OpenAIEmbeddings()

# Create a PGVector instance
vector_store = PGVector.from_documents(
    documents,
    embedding_function,
    connection_string=connection_string
)

# Perform a similarity search
query = "Your query here"
results = vector_store.similarity_search(query)

该示例假设您已设置 OpenAI 的嵌入,并准备好要嵌入的文档列表。

6. 使用 pgvector 与 OpenAI 构建示例应用

现在,让我们用 pgvector 与 OpenAI 嵌入一起构建一个简单的语义搜索引擎!

该应用允许用户使用自然语言查询在一组文本文档中进行搜索。

import openai
import psycopg2
import numpy as np

# Set up OpenAI API (replace with your actual API key)
openai.api_key = "your_openai_api_key"

# Connect to the database
conn = psycopg2.connect("dbname=your_database user=your_username")
cur = conn.cursor()

# Create a table for our documents
cur.execute("""
    CREATE TABLE IF NOT EXISTS documents (
        id SERIAL PRIMARY KEY,
        content TEXT,
        embedding vector(1536)
    )
""")

# Function to get embeddings from OpenAI
def get_embedding(text):
    response = openai.embeddings.create(input=text, model="text-embedding-ada-002")
    return response['data'][0]['embedding']

# Function to add a document
def add_document(content):
    embedding = get_embedding(content)
    cur.execute("INSERT INTO documents (content, embedding) VALUES (%s, %s)", (content, embedding))
    conn.commit()

# Function to search for similar documents
def search_documents(query, limit=5):
    query_embedding = get_embedding(query)
    cur.execute("""
        SELECT content, embedding <-> %s AS distance
        FROM documents
        ORDER BY distance
        LIMIT %s
    """, (query_embedding, limit))
    return cur.fetchall()

# Add some sample documents
sample_docs = [
    "The quick brown fox jumps over the lazy dog.",
    "Python is a high-level programming language.",
    "Vector databases are essential for modern AI applications.",
    "PostgreSQL is a powerful open-source relational database.",
]
for doc in sample_docs:
    add_document(doc)

# Perform a search
search_query = "Tell me about programming languages"
results = search_documents(search_query)
print(f"Search results for: '{search_query}'")
for i, (content, distance) in enumerate(results, 1):
    print(f"{i}. {content} (Distance: {distance:.4f})")

# Clean up
cur.close()
conn.close()

这个简单的应用展示了如何使用 pgvector 构建语义搜索引擎。

它使用 OpenAI 的文本嵌入模型对文档进行嵌入,并配合 pgvector 将其存储在 PostgreSQL 数据库中。搜索函数通过余弦相似度查找与给定查询最相似的文档。

面向高流量优化 pgvector

随着应用规模扩大,您需要优化 pgvector。以下是一些高层次建议:

连接池

实施连接池以降低开销。可使用 PgBouncer 或 PgPool-II。这些工具通过复用数据库连接来提升效率。

查询性能调优

在运行时调整索引参数。您可以根据需求在速度与准确性之间取得平衡。

  • 对于IVFFlat 索引,设置 probes 参数。取 1–5 以追求速度,取 10–20 以获得均衡表现。

  • 对于HNSW 索引,调优 ef_search。取 20–40 以追求速度,取 100–200 以追求准确性。

此外,您可以使用 EXPLAIN ANALYZE 验证索引是否被使用。查询中务必包含 LIMIT 子句。

缓存

使用 Redis 或 Memcached 实现缓存。缓存高频查询的向量,以查询向量作为缓存键,并设置合理的过期时间。

只读副本

为读密集型负载配置 PostgreSQL 只读副本。将写入路由到主库,将向量搜索路由到副本,使用负载均衡器进行自动分发。

PostgreSQL 配置

为向量负载调优关键参数:

  • shared_buffers:设置为物理内存的 25%

  • work_mem:向量操作建议设置为 64–128MB

  • random_page_cost:对于 SSD 存储适当调低

  • effective_cache_size:设置为物理内存的 50–75%

索引维护

在低流量时段定期重建索引。运行 VACUUM 与 ANALYZE。启用 autovacuum 以自动维护。

监控

跟踪查询延迟与每秒查询数。监控连接池利用率。检查缓存命中率。关注资源使用情况。为性能问题设置告警。启用 pg_stat_statements 识别慢查询。

pgvector 及其替代方案

现在,让我们将 pgvector 与其他流行的向量数据库进行比较。此对比将帮助您理解 pgvector 与其他方案在功能、部署方式、可扩展性、集成方式与成本等方面的差异。

pgvector vs. Pinecone

Pinecone 是一款全托管的向量数据库,具备高可扩展性与易用性。

功能

pgvector

Pinecone

数据库类型

PostgreSQL 扩展

全托管向量数据库

部署

自托管

云端

可扩展性

受限于 PostgreSQL

高度可扩展

集成

与现有 PostgreSQL 技术栈协同

需单独集成

成本

免费、开源

按需付费

如果您希望在不增加额外成本的前提下利用现有 PostgreSQL 基础设施,pgvector 是极佳选择;而 Pinecone 则提供了按需付费、上手便捷且高度可扩展的托管方案。

pgvector vs. Milvus

Milvus 是专用的向量数据库,具备高级功能与高可扩展性。

功能

pgvector

Milvus

数据库类型

PostgreSQL 扩展

专用向量数据库

部署

自托管

自托管或云端

可扩展性

受限于 PostgreSQL

高度可扩展

集成

与现有 PostgreSQL 技术栈协同

需单独集成

功能集

基础向量操作

高级功能,如动态模式

pgvector 在熟悉的 PostgreSQL 环境中提供基础向量操作;而 Milvus 面向大规模向量数据处理,提供更丰富的功能与更强的可扩展性。

pgvector vs. Weaviate

Weaviate 是带有对象存储的一体化向量数据库,提供灵活的数据建模与可扩展性。

功能

pgvector

Weaviate

数据库类型

PostgreSQL 扩展

带对象存储的向量数据库

部署

自托管

自托管或云端

可扩展性

受限于 PostgreSQL

面向可扩展设计

集成

与现有 PostgreSQL 技术栈协同

需单独集成

数据模型

仅向量

对象 + 向量与属性

pgvector 简洁且能与 PostgreSQL 无缝集成,适合需要基础向量功能的现有用户;而 Weaviate 更复杂的数据模型与可扩展性,适合需要对象存储与向量并重的复杂应用。

结语

pgvector 为 PostgreSQL 带来了强大的向量相似度搜索能力,非常适合开发者在现有基于 PostgreSQL 的应用中添加 AI 驱动的功能。

在本教程中,我们介绍了它的安装、基础用法、索引能力,以及与 Python 和 LangChain 的集成。

尽管 pgvector 在可扩展性与专用功能方面不及 Pinecone 或 Milvus 等专用向量数据库,但凭借与 PostgreSQL 的无缝集成,它对许多用例依然极具吸引力。

对于已经使用 PostgreSQL、且希望在不引入新数据库系统的前提下添加向量搜索功能的项目,pgvector 尤其合适。

我们鼓励您在自己的项目中尝试 pgvector。无论是构建推荐系统、语义搜索引擎,还是其他需要相似度检索的应用,pgvector 都可以成为您数据科学工具箱中的有力工具。

想要进一步学习,请探索我们的课程:

pgvector 常见问题

使用 pgvector 需要切换整个数据库吗?

不需要。它是对您现有 PostgreSQL 数据库的增补。

除了 Python,我还能用其他语言搭配 pgvector 吗?

可以。任何拥有 PostgreSQL 适配器的语言都能使用。

如何监控 pgvector 查询的性能?

您可以使用 PostgreSQL 内置工具,如 EXPLAIN 与 ANALYZE 监控查询性能。此外,pg_stat_statements 等日志与监控扩展可提供查询性能洞察,帮助识别瓶颈。

能否将向量搜索与传统 SQL 查询结合?

可以。pgvector 允许将向量搜索与传统 SQL 查询结合。您可以在 SQL 中同时包含向量相似度操作与其他条件,从而实现既利用向量又结合关系数据的复杂检索。

除了 OpenAI,pgvector 能与其他机器学习框架配合使用吗?

可以。pgvector 可与多种机器学习框架与库集成。您可以使用 TensorFlow、PyTorch 或 Hugging Face 等框架的模型生成嵌入,并通过 pgvector 在 PostgreSQL 中存储与查询这些嵌入。

如何处理 pgvector 的版本升级?

升级 pgvector 时,请遵循 pgvector 文档提供的官方升级说明。升级前务必备份数据。升级完成后,充分测试您的应用以确保兼容性与性能。

pgvector 能高效处理高维向量吗?

pgvector 可以处理高维向量,但性能可能受 PostgreSQL 能力所限。对于极高维的数据,考虑优化 PostgreSQL 配置,或评估 Milvus、Pinecone 等专用向量数据库。

Moez Ali

作者

Moez Ali

数据科学家,PyCaret 的创始人兼作者

主题