VastbaseG100

基于openGauss内核开发的企业级关系型数据库。

Menu

pgvector插件

背景信息

数据向量化

数据向量化指的是使用机器学习技术将各类非结构化数据转化为固定长度的数字向量的过程。这些数字向量也称为嵌入向量(Embedding Vector)。嵌入(Embedding)指的是AI将词汇、文本、语句、段落、图片、音频等各种对象转换为数学向量(Vector)的过程。向量化后的数据在数学上可以表示为一个定长的数字列表(多维数组)。

向量化数据库

向量化数据库是一种专门用于存储和处理向量化数据的数据库。当AI应用程序将普通的结构化或非结构化数据转换为多维度的数学向量后,会以 ARRAY 的形式存在向量数据库中,后续利用向量数据库所特有的函数和索引,可以对向量数据进行高效地比较和计算。

相似性搜索

在介绍相似性搜索之前,我们需要先了解特征和向量的关系。

当区分同类型下的不同物体时,往往需要通过区分各物体之间不同的特征来识别其种类。为了量化这个判断过程,假设我们将两个判断维度视为同一平面内的两条坐标轴,那么在二者构成的平面直角坐标系中,每个参与判断的物体都按照其在两个维度上的符合情况而占据了平面的一点。它的横纵坐标值分别代表了对两个特征的吻合程度。对于越复杂的物体,在区分它们时所需要的特征维度也越多。实际上,只要维度够多,我们就能够将所有的事物区分开来。

那这和相似性搜索(Similarity Search)有什么关系呢?在上述示例的二维坐标系中,我们可以很容易地知道,在坐标系中越接近的两个点,其具有的特征越相似,代表两个物品的相似度越高。我们都知道向量是具有大小和方向的数学结构,所以可以将这些特征用向量来表示,这样就能够通过计算向量之间的距离来判断它们的相似度,这就是相似性搜索。

功能描述

pgvector是一个开源的扩展插件,用于高效存储和查询向量数据。它提供了一种方便的方式来处理和操作高维向量,以支持各种应用场景,如相似性搜索、聚类分析、推荐系统等。

pgvector引入了专用的向量数据类型、运算符和函数,可以直接在 Vastbase数据库中高效存储、操作和分析矢量数据。可以基于向量字段创建IVFFlat和HNSW类型的索引,以在高维向量空间内进行有效快速的搜索。

  • 创建插件:

    CREATE EXTENSION vector;
    
  • 删除插件:

    DROP EXTENSION vector;
    

注意事项

  • 不支持查询索引构建进度。

  • 不支持生成插件日志文件。

  • 不支持创建超过16000个维度的向量字段。

  • 不支持在超过2000维度的向量字段上建立IVFFlat或HNSW索引。

  • 不支持在没有指定维度的向量字段上建立IVFFlat或HNSW索引。

  • 不支持主备同步。备机上暂不支持使用HNSW和IVFFLAT索引。

  • 构建索引需要的内存较多,设置较大的maintenance_work_mem值会显著加快索引构建速度,但是注意不要将该值设置的过高,以免耗尽服务器的内存。

使用指南

pgvector引入了专用的向量数据类型、运算符和函数,可以直接在 Vastbase数据库中高效存储、操作和分析矢量数据。

数据类型

支持数据类型vector[(n)],能够存储多维数据(n表示维度,n≤16000)。

只支持定义数值类型的向量,其他类型会报错。

向量类型的定义方式:

CREATE TABLE table_name(col vector(3));  --建表时定义字段为三维向量类型
INSERT INTO table_name VALUES('[1,2,3]'); --插入向量数据
INSERT INTO table_name VALUES(array[1,2,3]);  --数组类型转换为向量类型

函数

函数 描述 示例
l2_distance(vector, vector) 用于计算两个向量之间的L2范数距离。L2范数距离也称为欧氏距离,表示两个向量之间的直线距离。
SELECT l2_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
inner_product(vector, vector) 用于计算两个向量的内积。内积是两个向量对应元素乘积的和。
SELECT inner_product('[1,2,3]'::vector, '[4,5,6]'::vector);
cosine_distance(vector, vector) 用于计算两个向量之间的余弦距离。余弦距离是通过计算两个向量之间的夹角余弦值来衡量它们之间的相似度。
SELECT cosine_distance('[1,0,0]'::vector, '[0,1,0]'::vector);
l1_distance(vector, vector) 用于计算两个向量之间的L1范数距离。L1范数距离是向量元素绝对值之差的和。
SELECT l1_distance('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_dims(vector) 用于返回给定向量的维度(即向量中元素的数量)。
SELECT vector_dims('[1, 2, 3, 4]'::vector);
vector_norm(vector) 用于计算给定向量的范数,通常是向量元素的平方和的平方根。
SELECT vector_norm('[3, 4]'::vector);
vector_add(vector, vector) 用于计算两个向量的元素级相加,返回一个新的向量,其中每个元素是对应位置上两个向量元素的和。
SELECT vector_add('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_sub(vector, vector) 用于计算两个向量的元素级相减,返回一个新的向量,其中每个元素是对应位置上两个向量元素的差。
SELECT vector_sub('[4, 5, 6]'::vector, '[1, 2, 3]'::vector);
vector_mul(vector, vector) 用于计算两个向量的元素级相乘,返回一个新的向量,其中每个元素是对应位置上两个向量元素的乘积。
SELECT vector_mul('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_lt(vector, vector) 用于比较两个向量,如果第一个向量的所有元素都小于第二个向量对应位置的元素,则返回true,否则返回false。
SELECT vector_lt('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_le(vector, vector) 用于比较两个向量,如果第一个向量的所有元素都小于或等于第二个向量对应位置的元素,则返回true,否则返回false。
SELECT vector_le('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_eq(vector, vector) 用于比较两个向量,如果两个向量的所有元素都相等,则返回true,否则返回false。
SELECT vector_eq('[1, 2, 3]'::vector, '[1, 2, 3]'::vector);
vector_ne(vector, vector) 用于比较两个向量,如果两个向量的任意元素不相等,则返回true,否则返回false。
SELECT vector_ne('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_ge(vector, vector) 用于比较两个向量,如果第一个向量的所有元素都大于或等于第二个向量对应位置的元素,则返回true,否则返回false。
SELECT vector_ge('[4, 5, 6]'::vector, '[1, 2, 3]'::vector);
vector_gt(vector, vector) 用于比较两个向量,如果第一个向量的所有元素都大于第二个向量对应位置的元素,则返回true,否则返回false。
SELECT vector_gt('[4, 5, 6]'::vector, '[1, 2, 3]'::vector);
vector_cmp(vector, vector) 用于比较两个向量,返回一个整数值表示比较结果。如果第一个向量小于第二个向量,返回-1;如果两个向量相等,返回0;如果第一个向量大于第二个向量,返回1。
SELECT vector_cmp('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_l2_squared_distance(vector, vector) 用于计算两个向量之间的L2范数的平方距离。L2范数距离是向量元素差的平方和。
SELECT vector_l2_squared_distance('[1, 2]'::vector, '[4, 6]'::vector);
vector_negative_inner_product(vector, vector) 用于计算两个向量的负内积(negative inner product),即两个向量对应位置上的元素相乘后求和并取负值。
SELECT vector_negative_inner_product('[1, 2, 3]'::vector, '[4, 5, 6]'::vector);
vector_spherical_distance(vector, vector) 用于计算两个向量之间的球面距离(spherical distance),即两个向量之间的夹角的余弦值。
SELECT vector_spherical_distance('[1, 0, 0]'::vector, '[0, 1, 0]'::vector);
vector_accum(double precision[], vector) 用于将一个向量添加到一个double precision类型的数组中,返回一个新的数组,其中包含原始数组的元素以及新增向量的元素。
SELECT vector_accum(ARRAY[1.0, 2.0, 3.0], '[4, 5]'::vector);
vector_avg(double precision[]) 用于计算一个double precision类型数组中所有元素的平均值,并返回一个包含平均值的向量。
SELECT vector_avg(ARRAY[1.0, 2.0, 3.0]);
vector_combine(double precision[], double precision[]) 用于将两个double precision类型的数组合并成一个新的数组,返回一个包含两个数组所有元素的数组。
SELECT vector_combine(ARRAY[1.0, 2.0, 3.0], ARRAY[4.0, 5.0, 6.0]);
vector(vector, integer, boolean) RETURNS vector 用于对输入的向量进行某种操作,并返回一个新的向量。
SELECT vector('[1,2,3,4]'::vector, 4, true);
array_to_vector(integer[], integer, boolean) RETURNS vector 用于将整数数组转换为一个向量。
SELECT array_to_vector(array[1,2,3,4], 4, false);
array_to_vector(real[], integer, boolean) RETURNS vector 用于将实数数组转换为一个向量。
SELECT array_to_vector(array[1.1,2.2,3.3,4.4], 4, true);
array_to_vector(double precision[], integer, boolean) RETURNS vector 用于将双精度浮点数数组转换为一个向量。
SELECT array_to_vector(array[1.1,2.2,3.3,4.4], 4, false);
array_to_vector(numeric[], integer, boolean) RETURNS vector 用于将数值数组转换为一个向量。
SELECT array_to_vector(array[1.1,2.2,3.3,4.4], 4, true);
vector_to_float4(vector, integer, boolean) RETURNS real[] 用于将向量转换为实数数组。
SELECT vector_to_float4('[1,2,3,4]'::vector, 4, false);

运算符

pgvector提供了像<->用于计算欧几里德距离和<=>用于计算余弦距离的运算符,以计算向量之间的相似性。

操作符 描述 示例
<-> 计算两个向量之间的欧几里德距离。欧几里德距离是多维空间中向量表示的点之间的直线距离。较小的欧几里德距离表示向量之间的相似性较大,因此该运算符在查找和排序相似项目时非常有用。
SELECT array[1,1,1,1]::vector <-> array[2,2,2,2]::vector AS value;
<#> 计算两个向量之间的曼哈顿距离(也称为 L1 距离或城市街区距离)。曼哈顿距离是每个维度对应坐标差的绝对值之和。相对于欧几里德距离而言,曼哈顿距离更加强调沿着维度的较小移动。
SELECT array[1,1,1,1]::vector <#> array[2,2,2,2]::vector AS value;
<=> 计算两个向量之间的余弦相似度。余弦相似度比较两个向量的方向而不是它们的大小。余弦相似度的范围在 -1 到 1 之间,1 表示向量相同,0 表示无关,-1 表示向量指向相反方向。
SELECT array[1,1,1,1]::vector <=>array[2,2,2,2]::vector AS value;
+ 将两个向量相加。
SELECT array[1,1,1,1]::vector + array[2,2,2,2]::vector AS value;
- 将两个向量相减。
SELECT array[1,1,1,1]::vector - array[2,2,2,2]::vector AS value;
* 将两个向量相乘。
SELECT array[1,1,1,1]::vector * array[2,2,2,2]::vector AS value;
< 向量之间的小于比较。
SELECT array[1,1,1,1]::vector < array[2,2,2,2]::vector AS value;
<= 向量之间的小于等于比较。
SELECT array[1,1,1,1]::vector <= array[2,2,2,2]::vector AS value;
= 向量之间的相等比较。
SELECT array[1,1,1,1]::vector = array[2,2,2,2]::vector AS value;
<> 向量之间的不等比较。
SELECT array[1,1,1,1]::vector <> array[2,2,2,2]::vector AS value;
>= 向量之间的大于等于比较。
SELECT array[1,1,1,1]::vector >= array[2,2,2,2]::vector AS value;
> 向量之间的大于比较。
SELECT array[1,1,1,1]::vector > array[2,2,2,2]::vector AS value;

索引

pgvector通过索引实现了两种近似搜索算法:IVFFlat和HNSW,以在高维向量空间内进行有效快速的搜索。

  • IVFFlat是一种基于倒排索引的近似最近邻搜索算法,可以用于高效地查询向量之间的相似度。它将向量空间分为若干个划分区域,每个区域都包含一些向量,并创建倒排索引,用于快速地查找与给定向量相似的向量。

  • IVFFlat索引构建速度快,相比于无任何索引能够提升一定的查询性能,但召回率表现一般,也会消耗一定的内存。HNSW索引在召回率和性能上都有更加优秀的表现,但索引构建速度更慢,内存使用量更高。

在使用向量索引来查询向量数据时,往往需要在性能与召回率两个维度上权衡利弊。

  • 在以下情况下考虑使用IVFFlat索引:

    • 可以容忍搜索准确性略有下降。
    • 没有严格的内存限制。
    • 数据更新不频繁。
    • 如果希望索引构建快速且占用空间较小。
  • 在以下情况下考虑使用HNSW索引:

    • 需要高召回率速度时。
    • 数据正在快速变化。
    • 想要存储高维数据。
    • 可以容忍召回率的准确性。

提高搜索效率的主要思路:

  • 减少向量大小:通过降维或减少表示向量值的长度。
  • 缩小搜索范围:将向量数据分成多个聚类,通过聚类或将向量组织成基于树形、图形结构来实现,并限制搜索范围仅在最接近的簇中进行,或者通过最相似的分支进行过滤。

以下介绍两种索引的配置方法。

IVFFlat

参数信息

  • lists

    参数说明: lists参数确定索引构建期间创建的簇的数量(称为列表,因为每个质心在其区域中都有一个向量列表)。增加此参数会减少每个列表中的向量数量并导致区域更小。

    取值范围: 1~32768之间的整数

    默认值: 100

    设置lists值时有以下因素需要考虑:

    • 较高的lists值可通过缩小查询的搜索空间来加快查询速度。
    • 减小区域可能会因排除某些点导致产生更大的召回误差。
    • 此外,在查询过程的第一步(空间划分)中,需要进行更多距离比较才能找到最近质心。

    以下是设置lists参数的一些建议:

    • 对于少于一百万行的数据集,建议lists =  rows / 1000
    • 对于超过一百万行的数据集,建议lists = sqrt(rows)
    • 通常建议至少有 10 个簇。
  • probes

    参数说明: probes是一个查询时的会话级参数,用于确定查询期间要搜索的列表数量。默认情况下,仅搜索与最近质心对应的列表。通过增加probes参数,可以搜索更多区域来提高召回率,但是查询的速度会降低。推荐设置probes = sqrt(lists)

    默认值: 1

如果ivfflat.probes的值与创建索引时指定的lists值相等时,查询将会忽略向量索引并进行全表扫描。在这种情况下,索引不会被使用,而是直接对整个表进行搜索,可能会降低查询性能。

使用说明

1、在 pgvector 中,上述参数是在两个不同的时刻选择的。首先,在创建索引时选择列表的数量,例如:

CREATE INDEX ON items USING IVFFLAT (embedding vector_cosine_ops) WITH (lists = 1000);

然后,在执行期间确定要探索的列表的数量,例如:

SET IVFFLAT.probes = 32;

2、在创建IVFFlat索引的过程中,需要进行K-means聚类训练过程,因此IVFFlat索引需要在表中已经有了数据之后再创建,这样才能更好地发挥出索引的搜索效果。如果先创建了IVFFlat索引,后续又插入了大量的向量数据,则需要对索引进行重建操作,才可以更好地发挥出IVFFlat索引的搜索效果。

3、对于不同的距离操作符,需要单独创建IVFFlat索引:

  • 指定L2 Distance的IVFflat索引,指定100个聚类:

    CREATE INDEX ON table_name USING ivfflat(col_name vector_12_ops) WITH (lists=100);
    
  • 指定Inner Product的IVFflat索引,指定100个聚类:

    CREATE INDEX ON table_name USING ivfflat(col_name vector_ip_ops) WITH (lists=100);
    
  • 指定Cosine Distance的IVFflat索引,指定100个聚类:

    CREATE INDEX ON table_name USING ivfflat(col_name vector_cosine_ops) WITH (lists=100);
    

HNSW

参数信息

  • m

    构建参数m表示在每个索引元素之间存在多少双向链接(或路径)。将该值设置为一个较高的数量,可以增加召回量。但也会显著增加索引生成时间,可能影响查询性能。

    取值范围: 2~100之间的整数

    默认值: 16

    设置建议: 在HNSW图中,参数m指定每个顶点/节点与其最近邻居的最大连接数。它影响图的连通性,较高的值表示更密集的连接。增加m意味着每个点将连接到更多的邻居,并使图更密集,这可以加快搜索查询速度,但代价是更长的索引构建时间和更高的内存使用量。相反,较低的m减少了探索选项,可能会减慢搜索速度,特别是在到达远距离邻居时。较低的m值可能通过迫使搜索探索更广泛的范围来提高准确性(召回率),增加找到相关邻居的机会。

  • ef_construction

    ef_construction参数控制索引构建过程中使用的候选列表的大小。该列表暂时保存算法遍历图表时找到的最接近的候选者。一旦对特定点完成遍历,列表就会被排序,并且前m个最接近的点将被保留为邻居。较高的ef_construction值允许算法考虑更多候选者,从而有可能提高索引的质量。然而,它也会减慢索引构建过程,因为更多的候选者意味着更多的距离计算。

    取值范围: 4~1000之间的整数

    默认值: 64

  • ef_search

    查询参数。这个参数定义了HNSW索引搜索操作期间搜索算法将考虑的最大候选邻居数,即决定了使用HNSW索引返回元组的上限。

    取值范围: 1~1000之间的整数

    默认值: 40

    设置建议: 较高的值可能导致搜索速度变慢,因为需要评估更多的候选项,进行更多的比较和搜索时间。然而,它们提供了更高的召回率,通过探索更多的邻居,增加了找到相关邻居的机会,即使它们不是绝对最近的。相反,较低的值可以通过评估较少的候选项来加快搜索速度,可能导致更快的搜索时间。然而,它们也可能由于探索较少而导致召回率降低,可能会错过一些相关邻居,影响召回率。

使用说明

1、在 pgvector 中,这三个参数是在两个不同的时刻选择的。首先,在创建索引时选择m和ef_construction的值,例如:

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

然后,在执行期间确定要探索的列表的数量,例如:

SET hnsw.ef_search= 100;

2、在创建HNSW索引的过程中,不需要K-means的学习过程,因此无论先插入数据还是先创建索引,有关数据都可以被HNSW索引充分利用。

3、对于不同的距离操作符,需要单独创建HNSW索引:

  • 指定L2 Distance的HNSW索引:

    CREATE INDEX ON table_name USING hnsw(col_name vector_12_ops);
    
  • 指定Inner Product的HNSW索引:

    CREATE INDEX ON table_name USING hnsw(col_name vector_ip_ops);
    
  • 指定Cosine Distance的HNSW:

    CREATE INDEX ON table_name USING hnsw(col_name vector_cosine_ops);
    

关于索引和更多的参数方法介绍请点击此处

示例

示例1: 表存储向量类型数据,对向量类型数据进行DDL/DML操作。

1、创建插件。

CREATE EXTENSION vector;

2、创建一个含向量列的新表。

create table t_1194513(c1 int unique);

3、向己存在的表中添加一个向量列。

ALTER TABLE t_1194513 ADD COLUMN c2 vector (3);

4、查看测试表结构。

\d t_1194513

返回结果如下:

    Table "public.t_1194513"
 Column |   Type    | Modifiers
--------+-----------+-----------
 c1     | integer   |
 c2     | vector(3) |
Indexes:
    "t_1194513_c1_key" UNIQUE CONSTRAINT, btree (c1) TABLESPACE pg_default

5、向测试表插入向量类型数据。

insert into t_1194513 values(1,'[1,2,3]');
insert into t_1194513 values(2,'[4,5,6]'),(3,'[7,8,9]');
insert into t_1194513 value(4,null);

6、查看表数据。

select * from t_1194513;

返回结果如下:

 c1 |   c2
----+---------
  1 | [1,2,3]
  2 | [4,5,6]
  3 | [7,8,9]
  4 |
(4 rows)

7、对测试表数据进行DML操作。

UPDATE t_1194513 SET c2='[1,1,1]' WHERE c1=1;  --更新
DELETE FROM t_1194513 WHERE c1=3;  --删除
INSERT INTO t_1194513 values(1,'[2,2,2]') on duplicate key UPDATE c2='[1,2,4]';   --UPSERT

8、查看测试表数据。

SELECT * FROM t_1194513 order by c1;

返回结果如下:

 c1 |   c2
----+---------
  1 | [1,2,4]
  2 | [4,5,6]
  4 |
(3 rows)

9、清理环境。

DROP TABLE t_1194513;
DROP EXTENSION vector CASCADE;

示例2: 向量数据检索实例。

示例2的向量数据集采用公开的(包含23个省、5个自治区、4个直辖市)32个省会城市位置信息。将经纬度作为向量维度存储。通过欧几里德距离计算向量数据间距离(即城市间距离)。

1、创建插件。

CREATE EXTENSION IF NOT EXISTS vector;

2、创建记录省份_省会城市信息的表,并插入经纬度信息作为向量数据。

CREATE TABLE province_city_locations (
id SERIAL PRIMARY KEY,
province_name TEXT NOT NULL,
city_name TEXT NOT NULL,
location vector(2)
);
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('北京', '北京', '[116.4074, 39.9042]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('天津', '天津', '[117.2008, 39.0842]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('河北', '石家庄', '[114.5149, 38.0428]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('山西', '太原', '[112.5489, 37.8706]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('内蒙古', '呼和浩特', '[111.751, 40.848]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('辽宁', '沈阳', '[123.4315, 41.8057]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('吉林', '长春', '[125.3235, 43.8171]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('黑龙江', '哈尔滨', '[126.5358, 45.8023]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('上海', '上海', '[121.4737, 31.2304]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('江苏', '南京', '[118.7969, 32.0603]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('浙江', '杭州', '[120.1551, 30.2741]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('安徽', '合肥', '[117.2272, 31.8206]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('福建', '福州', '[119.2965, 26.0745]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('江西', '南昌', '[115.8581, 28.682]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('山东', '济南', '[117.1205, 36.6512]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('河南', '郑州', '[113.6249, 34.7472]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('湖北', '武汉', '[114.3054, 30.5931]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('湖南', '长沙', '[112.9388, 28.2282]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('广东', '广州', '[113.2644, 23.1291]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('广西', '南宁', '[108.320, 22.824]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('海南', '海口', '[110.3312, 20.0311]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('重庆', '重庆', '[106.5516, 29.563]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('台湾', '台北', '[121.50, 25.05]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('四川', '成都', '[104.0655, 30.6595]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('贵州', '贵阳', '[106.6302, 26.647]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('云南', '昆明', '[102.8329, 24.8801]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('西藏', '拉萨', '[91.1409, 29.6456]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('陕西', '西安', '[108.9402, 34.3416]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('甘肃', '兰州', '[103.8343, 36.0611]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('青海', '西宁', '[101.7782, 36.6171]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('宁夏', '银川', '[106.2309, 38.4872]');
INSERT INTO province_city_locations (province_name, city_name, location) VALUES ('新疆', '乌鲁木齐', '[87.6179, 43.8256]');

3、查看上一步创建的数据表样式。

select * from province_city_locations limit 10;

得到一个这样的表:

 id | province_name | city_name |     location
----+---------------+-----------+-------------------
  1 | 北京          | 北京      | [116.407,39.9042]
  2 | 天津          | 天津      | [117.201,39.0842]
  3 | 河北          | 石家庄    | [114.515,38.0428]
  4 | 山西          | 太原      | [112.549,37.8706]
  5 | 内蒙古        | 呼和浩特  | [111.751,40.848]
  6 | 辽宁          | 沈阳      | [123.432,41.8057]
  7 | 吉林          | 长春      | [125.324,43.8171]
  8 | 黑龙江        | 哈尔滨    | [126.536,45.8023]
  9 | 上海          | 上海      | [121.474,31.2304]
 10 | 江苏          | 南京      | [118.797,32.0603]
(10 rows)

4、进行向量数据检索。以下SQL表示查询离北京最近的五个省会城市:

SELECT province_name, city_name, location
FROM province_city_locations
WHERE city_name != '北京'
ORDER BY location <-> (select location from province_city_locations WHERE 	province_name  = '北京' and city_name = '北京')
LIMIT 5;

返回结果如下:

 province_name | city_name |     location
---------------+-----------+-------------------
 天津          | 天津      | [117.201,39.0842]
 河北          | 石家庄    | [114.515,38.0428]
 山东          | 济南      | [117.12,36.6512]
 山西          | 太原      | [112.549,37.8706]
 内蒙古        | 呼和浩特  | [111.751,40.848]
(5 rows)

在上述结果中,通过向量计算可知,离北京最近的五个省会城市分别为天津、石家庄、济南、太原、呼和浩特。

为了提高相似度的查询效率,可执行如下语句,为location字段建立索引。

CREATE INDEX ON province_city_locations USING IVFflat( location vector_l2_ops) with (lists = 10);

相关链接

pgvector