使用 PolarDB 开源版 smlar 插件进行高效率相似文本搜索、自助选药、相似人群圈选等业务

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: 背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力。本文将介绍使用 PolarDB 开源版 smlar 插件进行高效率相似文本搜索、自助...

背景

PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力。

本文将介绍使用 PolarDB 开源版 smlar 插件进行高效率相似文本搜索、自助选药、相似人群圈选等业务

测试环境为macOS+docker, PolarDB部署请参考如何用 PolarDB 证明巴菲特的投资理念 - 包括PolarDB简单部署

场景

  1. 自助匹配药品, 例如用户根据病情描述, 自动匹配相关的药品. 这个属于文本相似范畴. 文本相似性:

注意有语义的情况:

  • 感冒,不发烧,咳嗽,无痰,流清涕,肌肉酸痛

  • 感冒,发烧,咳嗽,有痰,无鼻涕

将药品主治症状的文本向量化, 存储为文本数组.

根据病人描述, 将文本向量化, 在药品库中进行文本向量的相似匹配, 快速找到最匹配的药品.

  1. 根据特征进行人群扩选, 例如在数据库中存储了每个用户的特征(使用数组表示)

根据输入的数组(画像)搜索相似人群, 即人群扩选, 业务上进行精准推送.

  1. 文章相似性搜索, 因为文章关键字很多, 每个关键字的权重也不一样, 不能只按命中多少关键字来决定相似性. 可以借助tfidf, 结合总文本数, 关键字在所有文本中出现的次数, 命中关键字等进行计算.

在所有文本中出现次数越多的关键字, 根据算法其权重可能越低. 具体算法可参考:

设计与算法

以上需求实际上都是多值列的相似计算, 使用smlar插件即可实现.

数据存储: 多值列(例如数组)

多值列的相似性算法: cosine, overlap, tfidf.

  switch(getSmlType())  
  {  
    case ST_TFIDF:  
      PG_RETURN_FLOAT4( TFIDFSml(sa, sb) );  
      break;  
    case ST_COSINE:  
      {  
        int       cnt;  
        double      power;  
  
        power = ((double)(sa->nelems)) * ((double)(sb->nelems));  
        cnt = numOfIntersect(sa, sb);  
  
        PG_RETURN_FLOAT4(  ((double)cnt) / sqrt( power ) );  
      }  
      break;  
    case ST_OVERLAP:  
      {  
        float4 res = (float4)numOfIntersect(sa, sb);  
  
        PG_RETURN_FLOAT4(res);  
      }  
      break;  

元素去重后计算.

postgres=# set smlar.type='cosine';   
SET  
postgres=# SELECT smlar('{1,4,6}'::int[], '{5,4,6}' );    
  smlar     
----------  
 0.666667  
(1 row)  
postgres=# SELECT smlar('{1,4,6}'::int[], '{5,4,4,6}' );    
  smlar     
----------  
 0.666667  
(1 row)  
-- 2/sqrt(3*3)   
  
postgres=# set smlar.type='overlap';   
SET  
postgres=# SELECT smlar('{1,4,6}'::int[], '{5,4,4,6}' );    
 smlar   
-------  
     2  
(1 row)  
-- 2  
  
postgres=# set smlar.type='tfidf';   
SET  
  
-- 设置tfidf表, 这个表可以用采样文档统计得到, 也可以自由定义其内容  
set smlar.stattable = 'documents_body_stats';   
  
create table documents_body_stats (  -- tfidf权重表.   
  value text unique,  -- value表示的关键字出现在多少篇文档中; value is null的行表示总文档篇数;  
  ndoc int not null    
);   
  
insert into documents_body_stats values ('0', 1); -- 0 出现在了1篇文章中.   
insert into documents_body_stats values ('1', 100); -- 1 出现在了100篇文章中.  
insert into documents_body_stats values ('4', 101), ('6', 201);   
insert into documents_body_stats values ('5', 1001);   
insert into documents_body_stats values (null, 10000);   -- value is null的行表示总文档篇数;  
  
postgres=# SELECT smlar('{1,4,6}'::text[], '{5,4,4,6}' );    
  smlar     
----------  
 0.742594  
(1 row)  
  
postgres=# SELECT smlar('{1,4,6}'::text[], '{5,5,5,6,6}' );    
 smlar    
--------  
 0.4436  
(1 row)  
  
postgres=# SELECT smlar('{0,1,4,5,6}'::text[], '{0,1,5}' );    
  smlar     
----------  
 0.868165  
(1 row)  
  
postgres=# SELECT smlar('{0,1,4,5,6}'::text[], '{1,5,6}' );    
  smlar     
----------  
 0.531762  
(1 row)  

加速原理

smlar 对数组支持gin和gist两个索引接口, 以gin为例, 如何快速筛选相似的记录?

例如, 输入条件的数组长度为6, 使用overlap算法, 要求相似度为4, 那么必须要有4个或4个以上元素命中的记录才符合要求.

  • 在gin索引中搜索元素1, 提取到ctid里的blockid, 每个blockid +1.

  • 在gin索引中搜索元素2, 提取到ctid里的blockid, 每个blockid +1.

  • 在gin索引中搜索元素3, 提取到ctid里的blockid, 每个blockid +1.

  • 在gin索引中搜索元素4, 提取到ctid里的blockid, 每个blockid +1.

  • 在gin索引中搜索元素5, 提取到ctid里的blockid, 每个blockid +1.

  • 在gin索引中搜索元素6, 提取到ctid里的blockid, 每个blockid +1.

在以上blockid中, 数据库只需要回表搜索大于等于4的blockid, recheck是否满足相似条件.

gin,gist支持的operator calss?

GiST/GIN support for % and && operations for:

Array Type

GIN operator class

GiST operator class

bit[]

_bit_sml_ops

bytea[]

_bytea_sml_ops

_bytea_sml_ops

char[]

_char_sml_ops

_char_sml_ops

cidr[]

_cidr_sml_ops

_cidr_sml_ops

date[]

_date_sml_ops

_date_sml_ops

float4[]

_float4_sml_ops

_float4_sml_ops

float8[]

_float8_sml_ops

_float8_sml_ops

inet[]

_inet_sml_ops

_inet_sml_ops

int2[]

_int2_sml_ops

_int2_sml_ops

int4[]

_int4_sml_ops

_int4_sml_ops

int8[]

_int8_sml_ops

_int8_sml_ops

interval[]

_interval_sml_ops

_interval_sml_ops

macaddr[]

_macaddr_sml_ops

_macaddr_sml_ops

money[]

_money_sml_ops

numeric[]

_numeric_sml_ops

_numeric_sml_ops

oid[]

_oid_sml_ops

_oid_sml_ops

text[]

_text_sml_ops

_text_sml_ops

time[]

_time_sml_ops

_time_sml_ops

timestamp[]

_timestamp_sml_ops

_timestamp_sml_ops

timestamptz[]

_timestamptz_sml_ops

_timestamptz_sml_ops

timetz[]

_timetz_sml_ops

_timetz_sml_ops

varbit[]

_varbit_sml_ops

varchar[]

_varchar_sml_ops

_varchar_sml_ops

例子

  1. 部署smlar on PolarDB

git clone --depth 1  git://sigaev.ru/smlar.git  
  
  
cd smlar/  
  
USE_PGXS=1 make  
USE_PGXS=1 make install  
  
  
[postgres@aa25c5be9681 smlar]$ USE_PGXS=1 make installcheck  
/home/postgres/tmp_basedir_polardb_pg_1100_bld/lib/pgxs/src/makefiles/../../src/test/regress/pg_regress --inputdir=./ --bindir='/home/postgres/tmp_basedir_polardb_pg_1100_bld/bin'      --dbname=contrib_regression smlar int2 int4 int8 float4 float8 money oid timestamp timestamptz time timetz date interval macaddr inet cidr text varchar char bytea bit varbit numeric int4g int8g intervalg textg int4i int8i intervali texti composite_int4 composite_text  
(using postmaster on 127.0.0.1, default port)  
============== dropping database "contrib_regression" ==============  
DROP DATABASE  
============== creating database "contrib_regression" ==============  
CREATE DATABASE  
ALTER DATABASE  
============== running regression test queries        ==============  
test smlar                        ... ok  
test int2                         ... ok  
test int4                         ... ok  
test int8                         ... ok  
test float4                       ... ok  
test float8                       ... ok  
test money                        ... ok  
test oid                          ... ok  
test timestamp                    ... ok  
test timestamptz                  ... ok  
test time                         ... ok  
test timetz                       ... ok  
test date                         ... ok  
test interval                     ... ok  
test macaddr                      ... ok  
test inet                         ... ok  
test cidr                         ... ok  
test text                         ... ok  
test varchar                      ... ok  
test char                         ... ok  
test bytea                        ... ok  
test bit                          ... ok  
test varbit                       ... ok  
test numeric                      ... ok  
test int4g                        ... ok  
test int8g                        ... ok  
test intervalg                    ... ok  
test textg                        ... ok  
test int4i                        ... ok  
test int8i                        ... ok  
test intervali                    ... ok  
test texti                        ... ok  
test composite_int4               ... ok  
test composite_text               ... ok  
  
  
===========================================================  
 All 34 tests passed.   
  
 POLARDB:  
 All 34 tests, 0 tests in ignore, 0 tests in polar ignore.   
===========================================================  
  1. 安装插件

postgres=# create extension smlar ;  
CREATE EXTENSION  
  1. 创建测试表, 写入测试数据

create table tbl (id int, propt int[]);  
  
create or replace function gen_arr(normal int, hot int) returns int[] as $$  
  select array(select (100000*random())::int+500 from generate_series(1,$1)) || array(select (500*random())::int from generate_series(1,$2));  
$$ language sql strict;  
  
insert into tbl select id, gen_arr(22, 10) from generate_series(1,2000000) id;  
  
postgres=# select * from tbl limit 5;  
 id |                                                                                     propt                                                                                       
----+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  1 | {1386,57573,55117,44934,83223,3444,77658,49523,85849,62549,99593,40714,53146,32510,68449,33662,45912,70227,64560,78831,86052,56387,157,490,51,484,53,176,273,240,300,277}  
  2 | {15075,100383,88390,18019,77540,37413,3368,39590,36506,43582,92236,68516,11532,25398,13927,81259,89457,92259,66811,45344,23676,64902,275,100,375,451,373,116,251,150,141,324}  
  3 | {16664,82803,7375,53577,85671,46465,89583,28753,38201,57599,39785,63099,71026,20543,52056,62785,86854,96900,85960,51256,51917,5901,129,208,400,244,459,49,386,283,198,467}  
  4 | {47066,46889,24635,93031,35972,52888,30732,93071,92172,93330,63597,12216,44887,25882,98570,41287,11343,49327,92704,16743,75095,34373,481,117,129,30,3,412,228,470,107,461}  
  5 | {46010,85290,76290,98398,15522,68861,90070,8352,31959,1786,52739,57341,99856,93526,68184,48683,85730,84427,23278,19603,80575,46747,224,430,234,136,159,204,243,120,406,471}  
(5 rows)  
  1. 创建索引

create index on tbl using gin (propt _int4_sml_ops);  
  1. 相似度搜索

overlap

postgres=# set smlar.type ='overlap';  
SET  
postgres=# set smlar.threshold=10;  
SET  
  
postgres=# explain analyze select * from tbl where propt % '{157,490,51,484,53,176,273,240,300,277}'::int[];  
                                                         QUERY PLAN                                                            
-----------------------------------------------------------------------------------------------------------------------------  
 Bitmap Heap Scan on tbl  (cost=219.50..6871.30 rows=2000 width=36) (actual time=37.548..37.549 rows=1 loops=1)  
   Recheck Cond: (propt % '{157,490,51,484,53,176,273,240,300,277}'::integer[])  
   Heap Blocks: exact=1  
   ->  Bitmap Index Scan on tbl_propt_idx  (cost=0.00..219.00 rows=2000 width=0) (actual time=37.514..37.515 rows=1 loops=1)  
         Index Cond: (propt % '{157,490,51,484,53,176,273,240,300,277}'::integer[])  
 Planning Time: 0.161 ms  
 Execution Time: 37.593 ms  
(7 rows)  
  
Time: 38.683 ms  
postgres=# select * from tbl where propt % '{157,490,51,484,53,176,273,240,300,277}'::int[];  
 id |                                                                                   propt                                                                                     
----+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  1 | {1386,57573,55117,44934,83223,3444,77658,49523,85849,62549,99593,40714,53146,32510,68449,33662,45912,70227,64560,78831,86052,56387,157,490,51,484,53,176,273,240,300,277}  
(1 row)  
  
Time: 38.794 ms  
  
关闭索引, 性能直线下降:  
postgres=# set enable_bitmapscan =off;  
SET  
Time: 0.510 ms  
postgres=# select * from tbl where propt % '{157,490,51,484,53,176,273,240,300,277}'::int[];  
 id |                                                                                   propt                                                                                     
----+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  1 | {1386,57573,55117,44934,83223,3444,77658,49523,85849,62549,99593,40714,53146,32510,68449,33662,45912,70227,64560,78831,86052,56387,157,490,51,484,53,176,273,240,300,277}  
(1 row)  
  
Time: 12553.942 ms (00:12.554)  

采用smlar提速100倍以上.

cosine

postgres=# set smlar.type ='cosine';  
SET  
  
postgres=# set smlar.threshold=0.55;  
SET  
Time: 1.107 ms  
postgres=# select * from tbl where propt % '{157,490,51,484,53,176,273,240,300,277}'::int[];  
 id |                                                                                   propt                                                                                     
----+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  1 | {1386,57573,55117,44934,83223,3444,77658,49523,85849,62549,99593,40714,53146,32510,68449,33662,45912,70227,64560,78831,86052,56387,157,490,51,484,53,176,273,240,300,277}  
(1 row)  
  
Time: 42.701 ms  

tfidf

  • 例如将所有的药品说明书进行文本向量处理, 提取关键字, 生成tfidf表.

  • 请自行测试

参考

https://github.com/jirutka/smlar

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
3天前
|
SQL 数据挖掘 数据安全/隐私保护
即席查询结果交互体验大升级,好用到爆
Dataphin v4.0提升了即席查询体验,新增支持多条SQL语句同时执行并查看独立日志,允许用户移动或隐藏列,以及全屏查看结果。此外,为增强数据安全,引入了禁止数据复制的功能。新版本还优化了细节,如单行详细信息查看和更灵活的列管理,旨在提高数据分析效率并保障数据安全。
|
8月前
|
关系型数据库 分布式数据库 PolarDB
|
8月前
|
关系型数据库 分布式数据库 数据库
沉浸式学习PostgreSQL|PolarDB 8: 电商|短视频|新闻|内容推荐业务(根据用户行为推荐相似内容)、监控预测报警系统(基于相似指标预判告警)、音视图文多媒体相似搜索、人脸|指纹识别|比对 - 向量搜索应用
1、在电商业务中, 用户浏览商品的行为会构成一组用户在某个时间段的特征, 这个特征可以用向量来表达(多维浮点数组), 同时商品、店铺也可以用向量来表达它的特征. 那么为了提升用户的浏览体验(快速找到用户想要购买的商品), 可以根据用户向量在商品和店铺向量中进行相似度匹配搜索. 按相似度来推荐商品和店铺给用户. 2、在短视频业务中, 用户浏览视频的行为, 构成了这个用户在某个时间段的兴趣特征, 这个特征可以用向量来表达(多维浮点数组), 同时短视频也可以用向量来表达它的特征. 那么为了提升用户的观感体验(推荐他想看的视频), 可以在短视频向量中进行与用户特征向量的相似度搜索.
236 0
|
8月前
|
关系型数据库 分布式数据库 数据库
沉浸式学习PostgreSQL|PolarDB 10: 社交、刑侦等业务, 关系图谱搜索
业务场景1 介绍: 社交、刑侦等业务, 关系图谱搜索 - 营销、分销、流量变现、分佣、引爆流行、裂变式传播、家谱、选课、社交、人才库、刑侦、农产品溯源、药品溯源 图式搜索是PolarDB | PostgreSQL在(包括流计算、全文检索、图式搜索、K-V存储、图像搜索、指纹搜索、空间数据、时序数据、推荐等)诸多特性中的一个。 采用CTE语法,可以很方便的实现图式搜索(N度搜索、最短路径、点、边属性等)。 其中图式搜索中的:层级深度,是否循环,路径,都是可表述的。
211 0
沉浸式学习PostgreSQL|PolarDB 10: 社交、刑侦等业务, 关系图谱搜索
|
9月前
|
搜索推荐 关系型数据库 数据库
沉浸式学习PostgreSQL|PolarDB 3: 营销场景, 根据用户画像的相似度进行目标人群圈选, 实现精准营销
业务场景1 介绍: 营销场景, 根据用户画像的相似度进行目标人群圈选, 实现精准营销 在营销场景中, 通常会对用户的属性、行为等数据进行统计分析, 生成用户的标签, 也就是常说的用户画像. 标签举例: 男性、女性、年轻人、大学生、90后、司机、白领、健身达人、博士、技术达人、科技产品爱好者、2胎妈妈、老师、浙江省、15天内逛过手机电商店铺、... ... 有了用户画像, 在营销场景中一个重要的营销手段是根据条件选中目标人群, 进行精准营销. 例如圈选出包含这些标签的人群: 白领、科技产品爱好者、浙江省、技术达人、15天内逛过手机电商店铺 .
256 0
|
搜索推荐 算法 数据处理
OpenSearch上线实时热搜、个性化底纹功能
热搜和底纹处于搜索整个流程的最上游,通过推荐热门、优质、多样化的查询词,对用户搜索意图起到重要的引导作用。OpenSearch上线实时热搜和个性化底纹功能,满足企业多样化搜索引导需求。
980 1
OpenSearch上线实时热搜、个性化底纹功能
|
3天前
|
算法 关系型数据库 分布式数据库
如何用 PolarDB 整合age算法插件, 实现图式搜索加速 - 刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍PolarDB结合图式算法, 实现高效率的刑侦、社交、风控、族谱、推荐等业...
61 0
|
3天前
|
搜索推荐 关系型数据库 分布式数据库
使用 PolarDB 开源版 采用array数组和gin索引高效率解决用户画像、实时精准营销类业务需求
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍使用 PolarDB 开源版高效率解决用户画像、实时精准营销类业务需求测试...
42 0
|
存储 算法 搜索推荐
使用 PolarDB 开源版 smlar 插件进行高效率相似文本搜索、自助选药、相似人群圈选等业务
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍使用 PolarDB 开源版 smlar 插件进行高效率相似文本搜索、自助选药、相似人群圈选等业务
351 0
|
存储 SQL 并行计算
如何用 PolarDB 整合age算法插件, 实现图式搜索加速 - 刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍PolarDB结合图式算法, 实现高效率的刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索.
319 0