2023-AI 大模型与向量数据库PGVECTOR
AI 大模型与向量数据库PGVECTOR
AI 是怎么工作的
对于
例如

人工智能大模型的“思考过程”,在数学上就是一系列向量与矩阵之间的加乘正逆运算。这种向量对于人类来说过于抽象,无法理解。但这种形式很适合使用
语言大模型解决的是 编码

所有的概念都可以用向量来表示,而向量空间有一些很好的数学性质,比如可以计算两个向量的“距离”。这意味着任意两个抽象概念之间的“相关性”,都可以用对应编码向量的距离来衡量。这个看上去简单的功能却有着非常强大的效果,例如最经典的应用场景就是搜索。比如,您可以预处理你的知识库,将每个文档都是用模型转换成抽象向量存储在向量数据库中,当你想要检索时,只需要将您的问题也用模型编码成为一个一次性的查询向量,并在数据库中找到与此查询向量“距离最近“的文档作为回答返回给用户即可。

通过这种方式,一个模糊而困难的自然语言处理问题,转换成为了一个简单清晰的数学问题。而向量数据库,就可以用来高效地解决这个数学问题。
向量数据库能干什么?
数据库有事务处理(OLTP)与数据分析(OLAP)两大核心场景,向量数据库自然也不例外。典型的事务处理场景包括:知识库,问答,推荐系统,人脸识别,图片搜索,等等等等。知识问答:给出一个自然语言描述的问题,返回与这些输入最为接近的结果;以图搜图:给定一张图片,找出与这张图片在逻辑上最接近的其他相关图片。
这些功能说到底都是一个共同的数学问题:向量最近邻检索(KNN

PG 向量插件PGVECTOR
市面上有许多向量数据库产品,商业的有

一个合格的向量数据库,首先得是一个合格的数据库,而从零开始做到这一点并不容易。比起使用一种全新的独立数据库品类,为现有数据库加装向量搜索的能力显然是一个更为务实,简单,经济的选择。
PGVECTOR 知识检索案例
下面我们通过一个具体的例子演示
模型
from text2vec import SentenceModel # 自动下载并加载模型
model = SentenceModel('shibing624/text2vec-base-chinese')
sentence = '这里是你想编码的文本输入'
vec = model.encode(sentence)
使用以上代码片段即可将任意长度在
存储
编码后的结果,在
CREATE EXTENSION vector;
CREATE TABLE sentences
(
id BIGINT PRIMARY KEY, -- 标识
txt TEXT NOT NULL, -- 文本
vec VECTOR(768) NOT NULL -- 向量
);
这张表和普通的数据库表并没有任何区别,你可以用一模一样的增删改查语句。特殊的地方在于
查询
这里我们只需要用一个简易的
# !/usr/bin/env python3
from text2vec import SentenceModel
from psycopg2 import connect
model = SentenceModel('shibing624/text2vec-base-chinese')
def query(question, limit=64):
vec = model.encode(question) # 生成一个一次性的编码向量,默认查找最接近的64条记录
item = 'ARRAY[' + ','.join([str(f) for f in vec.tolist()]) + ']::VECTOR(768)'
cursor = connect('postgres:///').cursor()
cursor.execute("""SELECT id, txt, vec <-> %s AS d FROM sentences ORDER BY 3 LIMIT %s;""" % (item, limit))
for id, txt, distance in cursor.fetchall():
print("%-6d [%.3f]\t%s" % (id, distance, txt))

PGVECTOR 的性能
当功能、正确性、安全性满足需求后,用户的目光就会转向性能。

为了对
-- 1M 个 1536 维向量,随机取 TOP1~50,余弦距离, 单核:插入与索引耗时均为5~6分钟,大小8GB左右。随机向量最近邻 Top1 召回:8ms
DROP TABLE IF EXISTS vtest; CREATE TABLE vtest ( id BIGINT, v VECTOR(1536) ); TRUNCATE vtest;
INSERT INTO vtest SELECT i, random_array(1536)::vector(1536) FROM generate_series(1, 1000000) AS i;
CREATE INDEX ON vtest USING ivfflat (v vector_cosine_ops) WITH(lists = 1000);
WITH probe AS (SELECT random_array(1536)::VECTOR(1536) AS v) SELECT id FROM vtest ORDER BY v <=> (SELECT v FROM probe) limit 1;
-- 简易SIFT ,1亿个128维向量,测试L2距离,召回1个最近向量, 5 ms, 召回最近100个向量:21ms
DROP TABLE IF EXISTS vtest; CREATE TABLE vtest( id BIGINT, v VECTOR(128) ); TRUNCATE vtest;
INSERT INTO vtest SELECT i, random_array(128)::vector(128) FROM generate_series(1, 100000000) AS i;
CREATE INDEX ON vtest USING ivfflat (v vector_l2_ops) WITH(lists = 10000);
WITH probe AS (SELECT random_array(128)::VECTOR(128) AS v) SELECT id FROM vtest ORDER BY v <-> (SELECT v FROM probe) limit 1; -- LIMIT 100
使用真实的
-- SIFT 1M 数据集,128维embedding,使用ivfflat索引, L2距离,10K测试向量集。
DROP TABLE IF EXISTS sift_base; CREATE TABLE sift_base (id BIGINT PRIMARY KEY , v VECTOR(128));
DROP TABLE IF EXISTS sift_query; CREATE TABLE sift_query (id BIGINT PRIMARY KEY , v VECTOR(128));
CREATE INDEX ON sift_base USING ivfflat (v vector_l2_ops) WITH(lists = 1000);
-- 一次性寻找 sift_query 表中 10000 条向量在 sift_base 表中的最近邻 Top1: 单进程 18553ms / 10000 Q = 1.8ms
explain analyze SELECT q.id, s.id FROM sift_query q ,
LATERAL (SELECT id FROM sift_base ORDER BY v <-> q.v limit 1) AS s;
-- 单次随机查询耗时在 个位数毫秒
WITH probe AS (SELECT v AS query FROM sift_query WHERE id = (random() * 999)::BIGINT LIMIT 1)
SELECT id FROM sift_base ORDER BY v <-> (SELECT query FROM probe) limit 1;
如何获取PGVECTOR ?
最后,我们来聊一聊,如何快速获取一个可用的yum install pgvector_15
完成安装。在安装了
CREATE EXTENSION vector;
CREATE TABLE items (vec vector(2));
INSERT INTO items (vec) VALUES ('[1,1]'), ('[-2,-2]'), ('[-3,4]');
SELECT *, vec <=> '[0,1]' AS d FROM items ORDER BY 2 LIMIT 3;
更简单的选择是本地优先的开源
