最近发的文章有AI的重度参与, 马上就有人下面留言评论有AI味了, AI味咋了? 用AI咋了? 用AI遭人嫌弃?
真的别看不上AI, 我的态度: 所有人都能用AI提效, 但是能把AI发挥到极致的人, 本身肯定也是这个领域的半个专家. 不信你等着瞧
就举个简单的例子吧:因为最近的大学生实数据库实践课教学需要, 需生成一些符合正态分布的向量数据(不能纯随机, 否则就失去了现实意义, 例如群体的聚集性、语义相似排序的意义).
用 AI 一下就搞定了, 我只提供了话术, 以及后续的稍作修改, 搞出一个适合的版本. 并行的话就不劳烦函数了, pgbench 开启压测模式即可.
(不过重点是你得懂业务啊, 你不懂业务怎么也不可能生成复合业务的数据, 至少得和AI高低多几轮对话, 走弯路对吧!)
prompt :
我要在PostgreSQL中创建一个存储16维向量的表, 需要生成测试数据, 写一个PostgreSQL函数, 生成1000个(可变量输入)离散随机的向量, 然后再以这1000个向量为中心, 生成2000个(可变量输入)离散向量, 离中心点距离越近出现概率越高, 越远概率越低.
在 PostgreSQL 中处理向量数据,通常推荐安装 pgvector 插件(目前已经是向量数据库的事实标准)。为了满足你“中心点聚合”和“概率分布”的需求,我们需要结合高斯分布(正态分布)的逻辑来编写函数。
首先,确保你的数据库已经安装了 pgvector 插件。
CREATE EXTENSION IFNOTEXISTS vector;
-- 创建存储 16 维向量的表
CREATETABLEIFNOTEXISTS vector_test (
idSERIAL PRIMARY KEY,
embedding vector(16),
is_center BOOLEAN-- 标记是否为中心点,方便后续查询
);
我们需要利用 PostgreSQL 的内置函数 random()。为了实现“离中心点越近概率越高”,最科学的方法是使用Box-Muller 变换来生成符合 正态分布(Normal Distribution) 的随机数。
generate_vector_dataCREATE ORREPLACEFUNCTION generate_vector_data(
center_count INT, -- 中心点数量 (例如 1000)
points_per_center INT-- 每个中心点周围生成的点数 (例如 2, 总计 2000)
) RETURNSTEXTAS $$
DECLARE
center_id INT;
center_vec FLOAT8[];
new_vec FLOAT8[];
std_dev FLOAT8 := 0.1; -- 标准差,值越小点越密集,越大离散度越高
i INT;
j INT;
u1 FLOAT8;
u2 FLOAT8;
z0 FLOAT8;
BEGIN
-- 1. 生成原始的离散随机中心点
FOR i IN1..center_count LOOP
center_vec := ARRAY(SELECT random() FROM generate_series(1, 16));
INSERTINTO vector_test (embedding, is_center)
VALUES (center_vec::vector, TRUE)
RETURNINGidINTO center_id;
-- 2. 以该中心点为基准,生成服从正态分布的周边点
FOR j IN 1..points_per_center LOOP
new_vec := '{}';
-- 对 16 个维度分别进行高斯扰动
FOR k IN 1..16 LOOP
-- Box-Muller 变换生成正态分布随机数
u1 := random();
u2 := random();
-- 核心公式:z0 是均值为0,标准差为1的随机数
z0 := sqrt(-2.0 * ln(u1)) * cos(2.0 * pi() * u2);
-- 将扰动叠加到中心点的对应维度上
new_vec := array_append(new_vec, center_vec[k] + (z0 * std_dev));
ENDLOOP;
INSERTINTO vector_test (embedding, is_center)
VALUES (new_vec::vector, FALSE);
ENDLOOP;
ENDLOOP;
RETURN 'Successfully generated ' || (center_count + center_count * points_per_center) || ' vectors.';
END;
$$ LANGUAGE plpgsql;
执行该函数生成数据:
-- 生成 1000 个中心点,每个中心点生成 2 个周边点(共 1000 + 2000 = 3000 条数据)
SELECT generate_vector_data(1000, 2);
验证数据分布:
-- 查看数据总量
SELECT is_center, count(*) FROM vector_test GROUP BY is_center;
-- 查询距离某个中心点最近的 5 个点,看看是不是刚才生成的“追随点”
SELECT * FROM vector_test
ORDER BY embedding <=> (SELECT embedding FROM vector_test WHERE is_center = true LIMIT 1)
LIMIT 5;
std_dev(标准差)控制了点的“紧凑程度”。std_dev = 0.01,点会非常贴近中心点。std_dev = 0.5,点会显得非常散乱。很多初学者对标准差的概念不理解,我们可以用一个 “射击/打靶” 的比喻让你瞬间秒懂:
想象你在打靶,靶心就是平均值(Mean) 。
这些百分比是 “覆盖率” ,也就是你“子弹落在这个范围内”的概率。
假设你生成向量时,某一个维度的平均值是 0.5 (例子中使用random()函数生成的数据, 平均值就是0.5, 因为random()返回的是0到1之间随机分布的值.),你设置的标准差 std_dev 是 0.1。
概念 | 到底是什么 | 形象理解 |
|---|---|---|
平均值 (Mean) | 数据的中心点 | 靶心 |
标准差 ( ) | 单位长度 | 尺子上的“一格”有多长 |
68% / 95%... | 概率/面积 | 这个圈里能装下多少个数据点 |
所以,当你看到“3个标准差”时,把它想成“3倍距离”,而不是“3%”。
在工业界(比如“六西格玛”管理),追求的就是 的精度,意味着 100 万个产品里只有 3.4 个次品,这就是把“圈子”拉得极大,让错误发生的概率变得极小。
我故意留了个维度/标准差可调, 总要东东过脑子, 否则全让AI嘎了, 一点意思都没有.
1、维度可调整, 标准差可调整
CREATE ORREPLACEFUNCTION generate_vector_data(
center_count INT, -- 中心点数量 (例如 1000)
points_per_center INT, -- 每个中心点周围生成的点数 (例如 2, 总计 2000)
dims int, -- 维度
i_std_dev float8 default0.1-- 标准差,值越小点越密集,越大离散度越高
) RETURNSTEXTAS $$
DECLARE
center_id INT;
center_vec FLOAT8[];
new_vec FLOAT8[];
std_dev FLOAT8 := i_std_dev; -- 标准差,值越小点越密集,越大离散度越高
i INT;
j INT;
u1 FLOAT8;
u2 FLOAT8;
z0 FLOAT8;
BEGIN
-- 1. 生成原始的离散随机中心点
FOR i IN1..center_count LOOP
center_vec := ARRAY(SELECT random() FROM generate_series(1, dims));
INSERTINTO vector_test (embedding, is_center)
VALUES (center_vec::vector, TRUE)
RETURNINGidINTO center_id;
-- 2. 以该中心点为基准,生成服从正态分布的周边点
FOR j IN 1..points_per_center LOOP
new_vec := '{}';
-- 对每个维度分别进行高斯扰动
FOR k IN 1..dims LOOP
-- Box-Muller 变换生成正态分布随机数
u1 := random();
u2 := random();
-- 核心公式:z0 是均值为0,标准差为1的随机数
z0 := sqrt(-2.0 * ln(u1)) * cos(2.0 * pi() * u2);
-- 将扰动叠加到中心点的对应维度上
new_vec := array_append(new_vec, center_vec[k] + (z0 * std_dev));
ENDLOOP;
INSERTINTO vector_test (embedding, is_center)
VALUES (new_vec::vector, FALSE);
ENDLOOP;
ENDLOOP;
RETURN 'Successfully generated ' || (center_count + center_count * points_per_center) || ' vectors.';
END;
$$ LANGUAGE plpgsql;
创建插件和测试表
CREATE EXTENSION IFNOTEXISTS vector;
-- 创建存储 8 维向量的表
CREATETABLEIFNOTEXISTS vector_test (
idSERIAL PRIMARY KEY,
embedding vector(8),
is_center BOOLEAN-- 标记是否为中心点,方便后续查询
);
接下来 pgbench 登场
2、并行插入
pgbench 并行写入脚本 1.sql
SELECT generate_vector_data(:center_count, :points_per_center, :dims, :i_std_dev);
例如, 开10个并行, 每个负责300个中心点, 共3000个中心点. 每个中心点周围100条记录. 一共30万条记录.
pgbench -M prepared -n -r -f 1.sql -D center_count=300 -D points_per_center=100 -D dims=8 -D i_std_dev=0.1 -c 10 -j 10 -t 1
返回结果类似这样
pgbench (18.1 (Debian 18.1-1.pgdg12+2))
transaction type: 1.sql
scaling factor: 1
query mode: prepared
number of clients: 10
number of threads: 10
maximum number of tries: 1
number of transactions per client: 1
number of transactions actually processed: 10/10
number of failed transactions: 0 (0.000%)
latency average = 1194.165 ms
initial connection time = 6.721 ms
tps = 8.374052 (without initial connection time)
statement latencies in milliseconds and failures:
1173.833 0 SELECT generate_vector_data(:center_count, :points_per_center, :dims, :i_std_dev);
数据样本如下
postgres=# select * from vector_test limit 10;
id | embedding | is_center
----+--------------------------------------------------------------------------------------------+-----------
1 | [0.49148703,0.6685635,0.1687298,0.45180625,0.9960631,0.4571475,0.0034939128,0.13861603] | t
2 | [0.5323792,0.5659391,0.12151991,0.4286459,1.0758449,0.6219371,0.004077115,0.034979522] | f
3 | [0.47398087,0.7543278,0.4328688,0.5329106,0.986699,0.43134648,-0.052911315,-0.08437831] | f
4 | [0.64157313,0.600284,0.10245401,0.31865734,0.8698451,0.3226676,0.08320826,0.22981888] | f
5 | [0.47341624,0.7114847,0.17963693,0.40590957,0.94509363,0.51783043,-0.018367931,0.2058961] | f
6 | [0.4226046,0.74574995,0.030126082,0.44892085,0.9216737,0.6136254,0.047382228,0.07710782] | f
7 | [0.44220188,0.7145569,0.26640612,0.5712415,0.9839118,0.4472589,0.09518536,0.104707085] | f
8 | [0.43854782,0.73702663,0.13283436,0.55481553,0.96476346,0.3992915,-0.054782305,0.15327796] | f
9 | [0.59758496,0.687787,0.16371523,0.55891865,1.13443,0.5273249,0.040264796,0.10090528] | f
10 | [0.6344181,0.44873625,0.16037185,0.49058086,1.0713346,0.23812866,-0.092897125,0.16163382] | f
(10 rows)
3、索引创建
使用并行创建
set maintenance_work_mem ='1GB';
set max_parallel_workers=4;
set max_parallel_workers_per_gather =4;
set parallel_leader_participation =off;
set parallel_setup_cost =0;
set parallel_tuple_cost =0;
set min_parallel_index_scan_size =0;
set min_parallel_table_scan_size =0;
alter table vector_test set (parallel_workers =4);
create index on vector_test using hnsw (embedding vector_ip_ops) with (m=16, ef_construction=64);
注意: 不同ops对应的order by op不同.
4、查询性能
set enable_seqscan=off;
postgres=# explain SELECT * FROM vector_test
ORDER BY embedding <#> (SELECT embedding FROM vector_test WHERE id = 1)
LIMIT 10;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Limit (cost=142.56..144.77 rows=10 width=50)
InitPlan 1
-> Index Scan using vector_test_pkey on vector_test vector_test_1 (cost=0.42..8.44 rows=1 width=37)
Index Cond: (id = 1)
-> Index Scan using vector_test_embedding_idx on vector_test (cost=134.12..133984.20 rows=607010 width=50)
Order By: (embedding <#> (InitPlan 1).col1)
(6 rows)
效果如下
postgres=# SELECT * FROM vector_test
ORDER BY embedding <#> (SELECT embedding FROM vector_test WHERE id = 4000)
LIMIT 10;
id | embedding | is_center
--------+--------------------------------------------------------------------------------------+-----------
406227 | [0.82450694,1.2055361,1.0173812,0.18316184,0.9584693,0.9418835,0.55990416,1.1273926] | f
201201 | [1.2767193,0.80783665,1.140189,0.8567347,-0.045661494,1.161669,0.92515004,0.9140229] | f
201944 | [1.1149577,0.7975786,1.1849692,0.9560142,0.20817277,1.0397915,1.1407607,0.9614646] | f
489547 | [0.9052291,1.0715504,1.093908,0.5560693,0.69307494,1.1439734,0.86572605,0.7646792] | f
200394 | [1.1373323,0.8256339,1.1670817,0.8769953,0.062202193,1.1290536,1.1055098,0.7922026] | f
495815 | [0.7111623,1.0081569,0.9748361,0.20044677,0.53446907,1.0939667,0.6770205,1.2081655] | f
295982 | [1.1235836,0.93014675,1.0391827,0.6902082,0.61107963,0.8564477,0.3975433,1.0953082] | f
406741 | [0.77345675,1.1682146,1.1521189,0.3500558,0.9883157,0.794485,0.49730656,1.0099597] | f
221776 | [1.1425776,0.89666414,0.6612843,0.7402642,0.8535777,0.975557,0.9979798,1.0486325] | f
489642 | [0.8964323,1.1836767,0.8508141,0.70250076,0.7395261,1.2460623,0.9538984,0.67182827] | f
(10 rows)
Time: 2.982 ms
> 我要在PostgreSQL中创建一个存储向量的表, 写一个PostgreSQL函数, 生成测试数据, 需求如下:
每个维度的取值区间为[0,1), 经过扰动得到的值也必须落在这个区间, 如果不能落在这个区间, 截取为上界或下界.
16维(可变量输入).
生成1000个(可变量输入)完全离散随机的向量.
然后再以这1000个向量为中心, 生成2000个(可变量输入)离散向量.
每个中心点周围数据的聚集性用标准差(通过下面的方法计算得出, 均值+扰动, 且必须为正值)来表示, 离中心点距离越近出现概率越高, 越远概率越低.
每个中心点聚集起来的数据看作一类, 不同类的聚集性强弱也呈现正态分布. 代表聚集强弱的标准差的均值可变量输入(例如 0.1), 分布强弱可变量输入(例如0.01);
下面是模板, 基于它修改
```sql
CREATE OR REPLACE FUNCTION generate_vector_data(
center_count INT, -- 中心点数量 (例如 1000)
points_per_center INT, -- 每个中心点周围生成的点数 (例如 2, 总计 2000)
dims int, -- 维度
i_std_dev float8 default 0.1 -- 标准差,值越小点越密集,越大离散度越高
) RETURNS TEXT AS $$
DECLARE
center_id INT;
center_vec FLOAT8[];
new_vec FLOAT8[];
std_dev FLOAT8 := i_std_dev; -- 标准差,值越小点越密集,越大离散度越高
i INT;
j INT;
u1 FLOAT8;
u2 FLOAT8;
z0 FLOAT8;
BEGIN
-- 1. 生成原始的离散随机中心点
FOR i IN 1..center_count LOOP
center_vec := ARRAY(SELECT random() FROM generate_series(1, dims));
INSERT INTO vector_test (embedding, is_center)
VALUES (center_vec::vector, TRUE)
RETURNING id INTO center_id;
-- 2. 以该中心点为基准,生成服从正态分布的周边点
FOR j IN 1..points_per_center LOOP
new_vec := '{}';
-- 对每个维度分别进行高斯扰动
FOR k IN 1..dims LOOP
-- Box-Muller 变换生成正态分布随机数
u1 := random();
u2 := random();
-- 核心公式:z0 是均值为0,标准差为1的随机数
z0 := sqrt(-2.0 * ln(u1)) * cos(2.0 * pi() * u2);
-- 将扰动叠加到中心点的对应维度上
new_vec := array_append(new_vec, center_vec[k] + (z0 * std_dev));
END LOOP;
INSERT INTO vector_test (embedding, is_center)
VALUES (new_vec::vector, FALSE);
END LOOP;
END LOOP;
RETURN 'Successfully generated ' || (center_count + center_count * points_per_center) || ' vectors.';
END;
$$ LANGUAGE plpgsql;
```
AI 又一把过了:
你的需求涉及以下几个关键点:
std_dev_mean(如 0.1)std_dev_sigma(如 0.01)vector 类型(需安装 pgvector 扩展)。std_dev_mean 和 std_dev_sigma。local_std_dev。GREATEST(0, LEAST(1 - 1e-9, value)) 确保严格在 [0,1)。vector 类型是否存在(否则会报错)。-- 确保已安装 pgvector 扩展(如未安装,请先执行:CREATE EXTENSION IF NOT EXISTS vector;)
-- 表结构示例(请先创建):
-- CREATE TABLE vector_test (
-- id SERIAL PRIMARY KEY,
-- embedding VECTOR,
-- is_center BOOLEAN,
-- center_id INT
-- );
CREATEORREPLACEFUNCTION generate_vector_data(
center_count INT, -- 中心点数量 (例如 1000)
points_per_center INT, -- 每个中心点周围生成的点数 (例如 2 → 总计 2000)
dims INT, -- 向量维度(例如 16)
std_dev_mean FLOAT8 DEFAULT0.1, -- 类内标准差的均值
std_dev_sigma FLOAT8 DEFAULT0.01 -- 类内标准差的分布标准差(即“聚集性强弱”的波动)
) RETURNSTEXTAS $$
DECLARE
center_id INT;
center_vec FLOAT8[];
new_vec FLOAT8[];
local_std_dev FLOAT8; -- 每个中心点自己的类内标准差
perturbed_val FLOAT8;
i INT;
j INT;
k INT;
u1 FLOAT8;
u2 FLOAT8;
z0 FLOAT8;
z_std FLOAT8; -- 用于生成 local_std_dev 的正态扰动
BEGIN
-- 1. 生成 center_count 个完全离散随机的中心点
FOR i IN1..center_count LOOP
-- 生成 d 维 [0,1) 随机向量作为中心
center_vec := ARRAY(SELECT random() FROM generate_series(1, dims));
-- 为当前中心点生成其“类内标准差”:N(std_dev_mean, std_dev_sigma),但必须 > 0
LOOP
u1 := random();
u2 := random();
-- 避免除零
IF u1 = 0 THEN u1 := 1e-10; ENDIF;
z_std := sqrt(-2.0 * ln(u1)) * cos(2.0 * pi() * u2);
local_std_dev := std_dev_mean + z_std * std_dev_sigma;
EXIT WHEN local_std_dev > 0; -- 确保标准差为正
ENDLOOP;
-- 插入中心点
INSERTINTO vector_test (embedding, is_center)
VALUES (center_vec::vector, TRUE)
RETURNINGidINTO center_id;
-- 2. 围绕该中心点生成 points_per_center 个聚集点
FOR j IN 1..points_per_center LOOP
new_vec := '{}';
FOR k IN 1..dims LOOP
-- 生成标准正态扰动
u1 := random();
u2 := random();
IF u1 = 0 THEN u1 := 1e-10; ENDIF;
z0 := sqrt(-2.0 * ln(u1)) * cos(2.0 * pi() * u2);
-- 扰动 = 中心值 + N(0, local_std_dev)
perturbed_val := center_vec[k] + z0 * local_std_dev;
-- 截断到 [0, 1)
-- 使用 1 - 1e-9 避免等于 1(因 random() 本身 <1,但扰动可能 >=1)
perturbed_val := GREATEST(0.0, LEAST(1.0 - 1e-9, perturbed_val));
new_vec := array_append(new_vec, perturbed_val);
ENDLOOP;
-- 插入非中心点,并可选记录 center_id(便于后续分析)
INSERTINTO vector_test (embedding, is_center, center_id)
VALUES (new_vec::vector, FALSE, center_id);
ENDLOOP;
ENDLOOP;
RETURN 'Successfully generated ' ||
(center_count + center_count * points_per_center)::TEXT ||
' vectors (' || center_count || ' centers + ' ||
(center_count * points_per_center) || ' neighbors).';
END;
$$ LANGUAGE plpgsql;
-- 生成 1000 个中心点,每个中心生成 2 个邻居(共 3000 条记录)
-- 16 维,类内标准差均值=0.1,波动=0.01
SELECT generate_vector_data(
center_count => 1000,
points_per_center => 2,
dims => 16,
std_dev_mean => 0.1,
std_dev_sigma => 0.01
);
pgvector 扩展必须安装:
CREATE EXTENSION IF NOT EXISTS vector;
表结构需包含 center_id 字段(用于追踪每个点属于哪个中心):
CREATE TABLE vector_test (
id SERIAL PRIMARY KEY,
embedding VECTOR,
is_center BOOLEAN,
center_id INT
);
性能提示:生成 3000 条记录很快,但若数量极大(如 100 万),建议分批或使用更高效方法(如 generate_series + CROSS JOIN LATERAL),但当前函数结构清晰,适合中小规模测试数据。
截断处理:使用 1 - 1e-9 确保最终值严格小于 1,符合 [0,1) 要求。
假设以上函数和vector插件都已安装.
1、建表
drop table if exists vector_test;
-- 创建存储 8 维向量的表
CREATE TABLE vector_test (
id SERIAL PRIMARY KEY,
embedding VECTOR(8),
is_center BOOLEAN,
center_id INT
);
接下来 pgbench 登场
2、并行插入
pgbench 并行写入脚本 1.sql
SELECT generate_vector_data(
:center_count,
:points_per_center,
:dims,
:std_dev_mean,
:std_dev_sigma
);
例如, 开10个并行, 每个负责300个中心点, 共3000个中心点. 每个中心点周围100条记录. 一共30万条记录.
pgbench -M prepared -n -r -f 1.sql -D center_count=300 -D points_per_center=100 -D dims=8 -D std_dev_mean=0.1 -D std_dev_sigma=0.01 -c 10 -j 10 -t 1
返回结果类似这样, 又是1秒, 完成30万写入.
pgbench (18.1 (Debian 18.1-1.pgdg12+2))
transaction type: 1.sql
scaling factor: 1
query mode: prepared
number of clients: 10
number of threads: 10
maximum number of tries: 1
number of transactions per client: 1
number of transactions actually processed: 10/10
number of failed transactions: 0 (0.000%)
latency average = 1275.373 ms
initial connection time = 7.123 ms
tps = 7.840843 (without initial connection time)
statement latencies in milliseconds and failures:
1254.682 0 SELECT generate_vector_data(
数据样本如下
postgres=# select * from vector_test limit 10;
id | embedding | is_center | center_id
----+--------------------------------------------------------------------------------------------+-----------+-----------
1 | [0.17105481,0.111848384,0.9117258,0.5306894,0.11807599,0.14844997,0.46155128,0.30024847] | t |
11 | [0.03813838,0.16296498,0.8372399,0.54524916,0.028416384,0.12848008,0.32547304,0.1947173] | f | 1
12 | [0,0.044231616,1,0.58943826,0.22524321,0,0.41637287,0.48733392] | f | 1
13 | [0.18737471,0,0.9368977,0.54700387,0,0.18523008,0.43912503,0.40527853] | f | 1
14 | [0.076122984,0.07140395,0.9845732,0.42619815,0.05465484,0.45531052,0.34961346,0.31409928] | f | 1
15 | [0.11690144,0.0030454656,0.89362085,0.4849689,0.2529286,0.19872168,0.48759928,0.39344427] | f | 1
17 | [0.090135045,0.19393651,1,0.62053615,0.1905218,0.005123274,0.5673879,0.24511307] | f | 1
19 | [0.25191787,0.29603916,0.914537,0.5292521,0,0.10356969,0.4150836,0.2541691] | f | 1
20 | [0.22760004,0.22169718,1,0.3778331,0,0.21047452,0.29598284,0.29152873] | f | 1
22 | [0.013735059,0.12628518,0.7749661,0.44492537,0.13536552,0.065305255,0.48517403,0.25436395] | f | 1
(10 rows)
3、索引创建
使用并行创建
set maintenance_work_mem ='1GB';
set max_parallel_workers=4;
set max_parallel_workers_per_gather =4;
set parallel_leader_participation =off;
set parallel_setup_cost =0;
set parallel_tuple_cost =0;
set min_parallel_index_scan_size =0;
set min_parallel_table_scan_size =0;
alter table vector_test set (parallel_workers =4);
create index on vector_test using hnsw (embedding vector_l2_ops) with (m=16, ef_construction=64);
注意: 不同ops对应的order by op不同.
4、查询性能
set enable_seqscan=off;
explainSELECT * FROM vector_test
ORDERBY embedding <-> (SELECT embedding FROM vector_test WHEREid = 11)
LIMIT10;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------
Limit (cost=136.12..138.32 rows=10 width=54)
InitPlan 1
-> Index Scan using vector_test_pkey on vector_test vector_test_1 (cost=0.42..8.44 rows=1 width=37)
Index Cond: (id = 11)
-> Index Scan using vector_test_embedding_idx on vector_test (cost=127.68..66880.00 rows=303000 width=54)
Order By: (embedding <-> (InitPlan 1).col1)
(6 rows)
效果如下, 符合预期, 有一些外围的点可能离其他中心点更近, 例如11明显离3057中心点的值更近.
SELECT * FROM vector_test
ORDERBY embedding <-> (SELECT embedding FROM vector_test WHEREid = 11)
LIMIT10;
id | embedding | is_center | center_id
------+--------------------------------------------------------------------------------------------+-----------+-----------
11 | [0.03813838,0.16296498,0.8372399,0.54524916,0.028416384,0.12848008,0.32547304,0.1947173] | f | 1
3196 | [0,0.09366788,0.836875,0.58805025,0,0.21278407,0.35584888,0.20035924] | f | 3057
3307 | [0.04267441,0.15442768,0.78668106,0.651847,0,0.19336444,0.26290196,0.24046999] | f | 3057
216 | [0.11530078,0.17141855,0.97688466,0.53638417,0.05041965,0.078720815,0.3156914,0.19801213] | f | 1
3335 | [0.047988825,0.11678319,0.83546025,0.65561557,0.13624333,0.12582546,0.27382517,0.27172136] | f | 3057
3321 | [0,0.14111617,0.85898143,0.71950036,0.04036658,0.17692095,0.32247683,0.1792223] | f | 3057
3107 | [0.057837497,0.03539711,0.82344323,0.6507534,0,0.052208096,0.2913429,0.18517697] | f | 3057
3475 | [0.09501218,0.2220129,0.81840885,0.61479205,0.15981476,0.18752795,0.38180515,0.18915245] | f | 3057
3327 | [0.13987818,0.21751888,0.702564,0.58499944,0,0.19195952,0.33919933,0.1812846] | f | 3057
3083 | [0.035972517,0.28071767,0.77004033,0.61820525,0.15739723,0.12367443,0.3413193,0.2037563] | f | 3057
(10 rows)
SELECT * FROM vector_test
ORDERBY embedding <-> (SELECT embedding FROM vector_test WHEREid = 1)
LIMIT10;
id | embedding | is_center | center_id
-----+-------------------------------------------------------------------------------------------+-----------+-----------
1 | [0.17105481,0.111848384,0.9117258,0.5306894,0.11807599,0.14844997,0.46155128,0.30024847] | t |
193 | [0.16777094,0.1642298,0.901199,0.44624943,0.12807207,0.16980569,0.4750887,0.31381938] | f | 1
166 | [0.120463744,0.07280951,0.89771175,0.43667313,0.055246145,0.1371449,0.46776408,0.3631755] | f | 1
152 | [0.2367722,0.14152765,1,0.5200618,0.1269453,0.085524425,0.40181518,0.2423237] | f | 1
158 | [0.14158644,0.22342859,0.955126,0.6240514,0.14849429,0.114813514,0.4535238,0.33608654] | f | 1
148 | [0.25239626,0.1525642,0.8130709,0.5330656,0.19565046,0.1114626,0.42059937,0.27454346] | f | 1
163 | [0.23277406,0.093285546,0.9140603,0.60804856,0.11022406,0.06361267,0.522467,0.38165015] | f | 1
199 | [0.24088658,0.25373772,0.88065875,0.52698815,0.06798484,0.13525315,0.4353099,0.28811255] | f | 1
188 | [0.18140465,0,1,0.5817445,0.13569641,0.15472418,0.5248301,0.352165] | f | 1
165 | [0.13854088,0.083053984,1,0.5690327,0,0.07870037,0.4946139,0.31971732] | f | 1
(10 rows)