沉浸式学习PostgreSQL|PolarDB 8: 电商|短视频|新闻|内容推荐业务(根据用户行为推荐相似内容)、监控预测报警系统(基于相似指标预判告警)、音视图文多媒体相似搜索、人脸|指纹识别|比对 - 向量搜索应用

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 1、在电商业务中, 用户浏览商品的行为会构成一组用户在某个时间段的特征, 这个特征可以用向量来表达(多维浮点数组), 同时商品、店铺也可以用向量来表达它的特征. 那么为了提升用户的浏览体验(快速找到用户想要购买的商品), 可以根据用户向量在商品和店铺向量中进行相似度匹配搜索. 按相似度来推荐商品和店铺给用户.2、在短视频业务中, 用户浏览视频的行为, 构成了这个用户在某个时间段的兴趣特征, 这个特征可以用向量来表达(多维浮点数组), 同时短视频也可以用向量来表达它的特征. 那么为了提升用户的观感体验(推荐他想看的视频), 可以在短视频向量中进行与用户特征向量的相似度搜索.

作者

digoal

日期

2023-08-29

标签

PostgreSQL , PolarDB , 数据库 , 教学


背景

欢迎数据库应用开发者参与贡献场景, 在此issue回复即可, 共同建设《沉浸式数据库学习教学素材库》, 帮助开发者用好数据库, 提升开发者职业竞争力, 同时为企业降本提效.

  • 系列课程的核心目标是教大家怎么用好数据库, 而不是怎么运维管理数据库、怎么开发数据库内核. 所以面向的对象是数据库的用户、应用开发者、应用架构师、数据库厂商的产品经理、售前售后专家等角色.

本文的实验可以使用永久免费的阿里云云起实验室来完成.

如果你本地有docker环境也可以把镜像拉到本地来做实验:

x86_64机器使用以下docker image:

ARM机器使用以下docker image:

业务场景1 介绍: 电商|短视频|新闻|内容推荐业务(根据用户行为推荐相似内容)、监控预测报警系统(基于相似指标预判告警)、音视图文多媒体相似搜索、人脸|指纹识别|比对 - 向量搜索应用

1、在电商业务中, 用户浏览商品的行为会构成一组用户在某个时间段的特征, 这个特征可以用向量来表达(多维浮点数组), 同时商品、店铺也可以用向量来表达它的特征. 那么为了提升用户的浏览体验(快速找到用户想要购买的商品), 可以根据用户向量在商品和店铺向量中进行相似度匹配搜索. 按相似度来推荐商品和店铺给用户.

2、在短视频业务中, 用户浏览视频的行为, 构成了这个用户在某个时间段的兴趣特征, 这个特征可以用向量来表达(多维浮点数组), 同时短视频也可以用向量来表达它的特征. 那么为了提升用户的观感体验(推荐他想看的视频), 可以在短视频向量中进行与用户特征向量的相似度搜索. 按相似度来推荐短视频给用户.

3、内容网站、新闻网站等, 和上面有类似的场景. 根据用户浏览行为、搜索词等, 生成特征向量, 根据特征向量的相似度匹配, 快速找到用户想要的内容.

4、监控系统, 例如应用软件的健康度监控, 根据多个维度的监控指标值+故障事件, 训练出一套向量值和故障事件对应的数据作为预判依据. 当新的监控数据到达后, 转换为特征向量, 然后到前面训练好的向量库中搜索相似度达到阈值的向量对应的故障事件, 进行故障预判.

5、人脸识别, 指纹识别. 存储录入的人脸、指纹向量, 未来可以通过向量数据库来进行指纹比对和人脸比对.

6、在音频、视频、图片网站中, 存储了音、视、图的特征向量, 同时根据用户的浏览行为生成用户的特征向量, 使用用户特征向量搜索推荐相似的音频、视频、图片, 提升用户的观感体验.

7、在股市预测中, 也可以有类似的应用. 类似上面说的监控系统.

实现和对照

传统方法 设计和实验

传统数据库没有数组类型, 只能使用text表达, 或者使用多个数值字段的组合来表达向量.

传统数据库没有向量距离搜索的操作符, 无法实现向量特征相似搜索.

传统数据库没有办法在text或者多个数值字段组合上建立向量索引, 因此即使实现了计算2个向量距离的函数, 也无法实现高效率的向量相似检索.

PolarDB|PG新方法1 设计和实验

PolarDB|PG 支持向量类型、向量距离计算操作符和函数、向量索引. 可以存储向量、进行向量距离计算、快速检索相似向量(向量距离相近).

创建向量索引插件

create extension vector;

设计一张向量特征表, 存储已知特征向量, 例如商品、视频、图文、人脸、指纹、监控事件等的特征.

create unlogged table tbl_vector (  
  id serial primary key,  -- 内容ID  
  vec vector(1024)    -- 内容ID对应的向量, 例子使用了1024维度  
);

创建一个生成随机N维向量的函数

create or replace function gen_rand_vector(int) returns vector as $$  
  select array_to_vector(array_agg((random()*1000)::int), $1, true) from generate_series(1,$1);  
$$ language sql strict;  
postgres=# select gen_rand_vector(10);  
             gen_rand_vector  
-----------------------------------------  
 [841,286,91,478,961,965,99,132,315,125]  
(1 row)

写入测试特征向量数据100万条.

insert into tbl_vector(vec) select gen_rand_vector(1024) from generate_series(1,1000000);

创建向量索引 (支持3种距离算法, 本例使用cosine. PGVECTOR 0.5.0开始支持ivfflat和hnsw两种索引算法, 本例使用hnsw.)

-- 尽量和表一样大, 创建索引可以快一点  
set maintenance_work_mem='4096MB';  
CREATE INDEX ON tbl_vector USING hnsw (vec vector_cosine_ops) WITH (m = 12, ef_construction=40);  -- 可以设置不同的参数, 对比一下性能.

在另一个会话中可以观测索引创建过程:

SELECT phase, tuples_done, tuples_total FROM pg_stat_progress_create_index;  
             phase              | tuples_done | tuples_total  
--------------------------------+-------------+--------------  
 building index: loading tuples |      311336 |            0  
(1 row)

测试数据占用空间如下:

postgres=# \dt+  
                                      List of relations  
 Schema |    Name    | Type  |  Owner   | Persistence | Access method |  Size   | Description  
--------+------------+-------+----------+-------------+---------------+---------+-------------  
 public | tbl_vector | table | postgres | unlogged    | heap          | 4979 MB |  
(1 row)  
postgres=# \di+  
                                                 List of relations  
 Schema |        Name        | Type  |  Owner   |   Table    | Persistence | Access method |  Size   | Description   
--------+--------------------+-------+----------+------------+-------------+---------------+---------+-------------  
 public | tbl_vector_pkey    | index | postgres | tbl_vector | unlogged    | btree         | 21 MB   |   
 public | tbl_vector_vec_idx | index | postgres | tbl_vector | unlogged    | hnsw          | 7813 MB |   
(2 rows)

根据特征向量进行搜索

vacuum analyze tbl_vector;  
-- alter role postgres SET enable_seqscan = off;  
-- alter role postgres SET hnsw.ef_search = 10;  -- 可以设置不同的参数, 对比一下性能.  
alter function gen_rand_vector(int) immutable; -- 为了测试索引的性能, immutable让这个函数产生常数, 强制使用vector索引.  
explain select id,vec <=> gen_rand_vector(1024) from tbl_vector order by vec <=> gen_rand_vector(1024) limit 1;  
 Limit  (cost=94.13..94.67 rows=1 width=12)  
   ->  Index Scan using tbl_vector_vec_idx on tbl_vector  (cost=94.13..540741.53 rows=1000000 width=12)  
         Order By: (vec <=> '[694,866,463,132,749,862,809,779,486,650,525,550,821,944,99,194,640,720,147,582,58,186,525,345,237,673,907,694,721,46,315,781,250,840,533,994,80,956,574,128,616,399,815,847,746,764,336,171,344,458,66,155,514,276,604,446,86,953,59,922,737,888,675,333,605,694,754,291,105,809,935,451,651,747,865,500,175,844,86,107,771,604,280,105,926,48,208,666,718,286,631,370,133,802,396,940,265,583,846,954,363,52,735,158,350,149,349,889,944,479,242,616,734,53,686,363,383,393,25,858,533,680,742,25,266,975,315,118,266,609,393,353,888,300,209,809,349,186,387,138,491,281,955,17,287,39,479,271,224,232,328,359,161,711,372,849,685,300,200,31,395,916,814,80,163,384,723,566,213,667,256,562,511,512,624,653,622,664,876,334,933,846,987,327,253,886,385,491,806,629,583,990,893,290,953,273,90,415,201,25,77,884,838,262,777,873,695,202,685,201,713,758,327,298,438,681,106,401,541,418,993,722,663,196,121,783,809,3,509,182,743,904,387,502,335,421,614,248,787,465,30,668,418,298,525,431,78,157,643,803,28,976,557,411,766,211,706,862,884,203,750,377,937,90,245,608,730,756,535,908,625,154,379,169,868,897,203,954,616,984,242,33,986,874,156,467,883,673,654,570,668,651,711,162,360,556,836,386,507,658,539,669,295,161,413,505,624,635,635,102,853,661,904,377,537,597,112,680,768,753,942,209,752,504,988,559,776,641,475,951,120,502,568,509,311,816,286,554,43,478,13,387,412,361,276,796,827,244,134,635,98,841,77,45,62,879,520,173,514,188,728,822,718,634,625,143,6,638,357,923,772,317,566,922,906,436,21,168,562,287,954,707,214,978,128,529,735,994,287,753,551,50,150,539,627,538,50,53,729,69,651,368,114,825,948,836,45,543,33,911,549,763,372,755,911,524,737,541,113,347,532,77,775,459,107,926,81,669,458,476,368,699,537,479,785,600,424,263,192,881,2,506,750,388,209,27,806,562,592,147,368,458,23,678,948,754,207,501,711,472,836,846,684,476,131,145,537,113,331,417,849,40,824,415,330,96,676,769,770,544,885,388,262,653,849,891,854,979,817,520,284,74,303,199,958,412,920,280,165,964,334,253,596,967,362,892,211,506,645,45,922,673,232,572,530,401,250,745,142,837,190,184,198,145,26,32,469,267,116,317,399,930,958,199,966,540,52,187,635,812,340,261,695,523,571,602,391,709,984,174,361,516,676,469,233,443,798,116,269,730,220,984,166,313,912,481,758,261,857,651,225,602,927,895,466,397,532,809,693,52,730,70,681,867,546,120,51,535,778,771,787,581,319,831,733,99,694,526,299,554,74,227,51,104,523,941,254,930,781,816,185,374,21,663,814,456,897,274,955,184,889,95,750,349,600,47,232,407,983,944,141,190,474,840,205,348,113,547,979,416,831,916,414,620,218,734,617,974,171,240,398,925,374,653,911,952,594,26,64,746,316,598,702,310,312,183,373,769,873,376,795,389,833,468,756,334,16,162,897,509,760,913,746,307,19,116,102,827,629,219,675,564,551,249,352,570,661,394,912,720,409,159,983,931,834,817,74,799,989,299,894,187,212,340,802,313,530,368,100,52,23,750,221,613,612,291,431,900,612,131,939,426,402,969,917,227,15,231,506,230,662,680,970,668,538,929,571,460,570,560,810,948,483,293,605,596,20,61,717,370,813,536,912,850,166,688,587,846,387,358,877,522,627,568,977,15,112,798,791,69,962,626,265,679,241,736,392,630,718,236,834,676,856,603,224,994,615,194,202,277,478,702,249,39,190,820,827,417,668,776,712,216,545,757,940,333,401,98,111,3,663,806,98,734,13,427,293,123,137,745,342,188,483,619,90,966,53,600,741,281,905,540,628,851,198,325,884,996,18,224,425,730,722,140,307,893,820,864,667,413,884,75,192,931,381,333,579,701,530,412,705,187,173,405,669,606,513,777,173,308,391,749,692,416,340,619,969,253,9,69,622,527,970,699,337,785,539,471,537,808,806,972,601,204,771,253,338,764,642,970,167,18,86,830,391,916,502,365,479,607,286,442,767,617,75,917,617,437,276,618,486,6,717,406,543,69,336,107,309,912,792,477,100,15,178,145,940,292,472,544,731,485,456,459,160,249,966,37,559,197,906,389,341,729,580,289,896,733,829,854,979,769,889,341,470,357,217,671,383,580,824,753,669,820,402,906,414,759,424,291,869,457,753,527,224,716,548,6,490,766,623,605,266,693,893,791,759,779,415,715,465,850,255,987,289,724,400,995,324,528,78,970,491,887]'::vector)  
(3 rows)  
postgres=# select id,vec <=> gen_rand_vector(1024) from tbl_vector order by vec <=> gen_rand_vector(1024) limit 1;  
    id    |      ?column?        
----------+--------------------  
 10836124 | 0.2136536819090169  
(1 row)  
Time: 50.547 ms

性能压测

vi t1.sql  
select id,vec <=> gen_rand_vector(1024) from tbl_vector order by vec <=> gen_rand_vector(1024) limit 1;  
pgbench -M prepared -n -r -P 1 -f ./t1.sql -c 10 -j 10 -T 120

压测结果

hnsw.ef_search = 10;   
transaction type: ./t1.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 10  
number of threads: 10  
duration: 120 s  
number of transactions actually processed: 1659482  
latency average = 0.723 ms  
latency stddev = 0.329 ms  
initial connection time = 20.194 ms  
tps = 13831.040378 (without initial connection time)  
statement latencies in milliseconds:  
         0.723  select id,vec <=> gen_rand_vector(1024) from tbl_vector order by vec <=> gen_rand_vector(1024) limit 1;  
hnsw.ef_search = 1;   
transaction type: ./t1.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 10  
number of threads: 10  
duration: 120 s  
number of transactions actually processed: 5841138  
latency average = 0.205 ms  
latency stddev = 0.112 ms  
initial connection time = 22.311 ms  
tps = 48685.030555 (without initial connection time)  
statement latencies in milliseconds:  
         0.205  select id,vec <=> gen_rand_vector(1024) from tbl_vector order by vec <=> gen_rand_vector(1024) limit 1;

hnsw.ef_search = 10; 时 TPS: 13831.040378

hnsw.ef_search = 1; 时 TPS: 48685.030555

对照

传统数据库不支持向量类型、向量距离计算、向量类型索引.

PolarDB|PG 支持向量类型、向量距离计算操作符和函数、向量索引. 可以存储向量、进行向量距离计算、快速检索相似向量(向量距离相近).

  • macbook m2 机器上, 4核的docker资源, TPS可以达到数万.

知识点

1 什么是向量类型

2 什么是向量索引

3 向量距离搜索操作符有哪些?

4 向量搜索算法ivfflat、hnsw

5 向量搜索算法ivfflat、hnsw 支持哪些向量调参?

/* IVFFlat parameters */  
#define IVFFLAT_DEFAULT_LISTS 100  // lists个数越大, 性能越好.  相当于每个list桶内的向量记录更少.  每个桶的向量记录数 = 总条数/lists  
#define IVFFLAT_MIN_LISTS   1  
#define IVFFLAT_MAX_LISTS   32768  
#define IVFFLAT_DEFAULT_PROBES  1   // probe越大, 精准度越高, 性能越差. 相当于搜索时从所有lists对应的若干个中心点中选出N个最近的中心点, 进入对应的这N个桶中进行继续过滤.
/* HNSW parameters */  
#define HNSW_DEFAULT_M  16  // the max number of connections per layer (16 by default)  
#define HNSW_MIN_M  2  
#define HNSW_MAX_M    100  
#define HNSW_DEFAULT_EF_CONSTRUCTION  64  // the size of the dynamic candidate list for constructing the graph (64 by default)  
#define HNSW_MIN_EF_CONSTRUCTION  4  
#define HNSW_MAX_EF_CONSTRUCTION    1000  
#define HNSW_DEFAULT_EF_SEARCH  40  // Specify the size of the dynamic candidate list for search (40 by default). SET hnsw.ef_search = 100;  
#define HNSW_MIN_EF_SEARCH    1  
#define HNSW_MAX_EF_SEARCH    1000
postgres=# load 'vector' ;  
LOAD  
postgres=# show ivfflat.probes ;  
 ivfflat.probes  
----------------  
 1  
(1 row)  
postgres=# show hnsw.ef_search ;  
 hnsw.ef_search  
----------------  
 40  
(1 row)

6 ivfflat和hnsw两种向量索引应该如何选择? 和向量数据量有关吗?

7 为什么说使用 ivfflat 向量搜索是近似结果, 那么结果的精准度和什么有关? 如何配置?

8 k-means

9 向量检索有没有标准或流行的benchmark工具?

10 还有哪些支持向量搜索的数据库? 各自的产品特性如何? 我们的数据库选型标准是什么? 综合哪些因素来进行选择?

11 还有哪些支持向量搜索的插件?

  • hnsw, embedding, cube, imgsmlr, ...

思考

1 如何将非结构化的业务数据转换成向量?

2 如果训练向量和事件的相关性?

3 如何高效过滤已读内容?

4 除了应用报警, 还有什么业务能使用类似的方法进行预测?

  • 气象、地震灾害、地质灾害? 市场预测?

5 向量特征相似搜索的性能取决于什么?

6 当数据库的向量搜索请求并发非常高, 已经达到了数据库性能瓶颈时, 如何解决? 使用PostgreSQL只读实例 还是 PolarDB共享存储|存算分离 更好? 为什么?

7 pgvector目前支持几种向量距离计算方法? 那种性能最好?

8 如何将向量转换为归一化向量? 下面是chatgpt给的方法, 大家思考一下是否正确?

  • 首先,计算向量的长度(模/范数)。对于二维向量 (x, y),长度可以通过以下公式计算:len = sqrt(x^2 + y^2)。对于具有更多维度的向量,需要对每个分量进行平方并求和,然后取平方根。
  • 接下来,将每个向量分量除以其长度,以获得归一化向量的分量。对于二维向量 (x, y),归一化向量可以通过以下公式计算:normalized_vector = (x/len, y/len)。对于具有更多维度的向量,将每个分量除以长度即可。

下面是一个示例代码,演示如何将向量(x, y)归一化为长度为1的向量:

在这个示例中,我们使用CTE(公共表达式)定义了一个包含分量x和y的向量。然后,我们通过计算平方和的平方根来获取向量的长度。最后,我们将每个分量除以长度,得到归一化向量。

WITH my_table AS (  
  SELECT 2 AS x, 3 AS y  
)  
SELECT  
  x / sqrt(x^2 + y^2) AS normalized_x,  
  y / sqrt(x^2 + y^2) AS normalized_y  
FROM my_table;

9 如果数据量特别大, 如何提升创建索引的速度?

  • 使用分区表, 并行创建? 有什么负作用?
  • 提升maintenance_work_mem?
  • 内核是否支持并行创建向量索引?

参考

《标准知识库 + PostgreSQL或PolarDB + 向量插件 + openai(或其他大模型) 提升通用ai机器人在专业领域的精准度》

《ChatGPT背后的数据库技术体验 - 向量近似搜索之 PostgreSQL+pase(hnsw,ivfflat,ivfpq)》

《ChatGPT背后的数据库技术体验 - 向量近似搜索之 pgvector : 如何用 PolarDB 在不确定世界寻找确定答案 (例如图像相似) - pgvector|pase》

《PostgreSQL 开源 高维向量相似搜索插件 vector - 关联阿里云rds pg pase, cube, 人脸识别》

《PostgreSQL 应用开发解决方案最佳实践系列课程 - 3. 人脸识别和向量相似搜索》

《PostgreSQL 向量相似推荐设计 - pase》

《PostgreSQL+MySQL 联合解决方案 - 第11课视频 - 多维向量相似搜索 - 图像识别、相似人群圈选等》

《PostgreSQL 阿里云rds pg发布高维向量索引,支持图像识别、人脸识别 - pase 插件, 以及ivfflat,hnsw搜索算法说明》

https://github.com/pgvector/pgvector/blob/master/src/hnsw.h

https://github.com/pgvector/pgvector

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
15天前
|
数据库
|
1月前
|
存储 关系型数据库 分布式数据库
使用开源PolarDB和imgsmlr进行高效的图片存储和相似度搜索
使用开源PolarDB和imgsmlr进行高效的图片存储和相似度搜索
|
2月前
|
存储 监控 关系型数据库
监控 PostgreSQL 的性能指标
监控 PostgreSQL 的性能指标
114 3
|
2月前
|
关系型数据库 分布式数据库 数据库
开源云原生数据库PolarDB PostgreSQL 15兼容版本正式发布
PolarDB进行了深度的内核优化,从而实现以更低的成本提供商业数据库的性能。
|
3月前
|
SQL 存储 关系型数据库
新手如何入门学习PostgreSQL?
新手如何入门学习PostgreSQL?
|
3月前
|
SQL 存储 关系型数据库
PostgreSQL核心之SQL基础学习
PostgreSQL核心之SQL基础学习
43 3
|
4月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之如何进行PostgreSQL(简称PG)的全量和增量备份管理
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
4月前
|
SQL 关系型数据库 MySQL
PolarDB产品使用问题之搜索和查询冷数据如何照时间范围进行查询
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
4月前
|
存储 关系型数据库 分布式数据库
PolarDB产品使用问题之如何查看PolarDB for PostgreSQL的备份信息
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
4月前
|
SQL 监控 关系型数据库
实时计算 Flink版操作报错合集之在设置监控PostgreSQL数据库时,将wal_level设置为logical,出现一些表更新和删除操作报错,怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。

热门文章

最新文章

相关产品

  • 云原生数据库 PolarDB