PostgreSQL - 全文检索内置及自定义ranking算法介绍 与案例

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:
 

标签

PostgreSQL , 全文检索 , ranking


背景

《用PostgreSQL 做实时高效 搜索引擎 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询》

《排序算法》这个章节实际上介绍了PostgreSQL的ranking算法。

tsvector将文档分为4层结构:标题、作者、摘要、内容。对这四个层级,用户可以设定对应的weight,用于ranking的计算。同时用户可以设定ranking的修正掩码。

但是只有四个层级,远远不能满足业务需求,那么PostgreSQL实现更多层级,更精细的ranking算法呢?

如何自定义ranking呢?

例如在电商行业中,我们可能存储了每个店铺的标签,每个标签旁边可能是一个系数,这个系数可能是动态调整的。在搜索的时候,商店的某些标签被命中了,可能搜索到了几百万个店铺,但是最后要根据权重算出应该如何排序,并得到其中的1万个店铺。

这种情况,如何精细化排序就体现出来了。

例子1 - tsvector向量

1、店铺标签表:

create table tbl (    
  shop_id int8 primary key,   -- 店铺 ID    
  tags text                   -- 多值类型,标签1:评分1,标签2:评分2,.....       
);    

对tags字段,使用UDF索引,存储标签的数组或tsvector索引。

如果使用tsvector,主要是便于使用PostgreSQL的全文检索的语法,包含、不包含、距离等。

tags例如

国民_足浴:0.99,国民_餐饮:0.1,娱乐_KTV:0.45  

2、标签权值表:

create table tbl_weight (    
  tagid int primary key,   -- 标签ID     
  tagname name,            -- 标签名    
  desc text,               -- 标签描述    
  weight float8            -- 标签权值    
);    
  
create index idx_tbl_weight_1 on tbl_weight (tagname);  

3、文本转标签数组、tsvector的UDF

create or replace function text_to_tsvector(text) returns tsvector as $$    
  select array_to_tsvector(array_agg(substring(id,'(.+):'))) from unnest(regexp_split_to_array($1, ',')) as t(id);    
$$ language sql strict immutable;    
    
postgres=# select text_to_tsvector('abc:1.1,bc:100,c:293');    
 text_to_tsvector     
------------------    
 'abc' 'bc' 'c'    
(1 row)    

创建TSVECTOR表达式索引

create index idx_tbl_1 on tbl using gin (text_to_tsvector(tags));  

4、取出命中标签权值的UDF

postgres=# select substring('bc:1.1,abc:100,c:293','[^,]?abc:([\d\.]+)') ;    
 substring     
-----------    
 100    
(1 row)    
    
postgres=# select substring('abc:1.1,bc:100,c:293','[^,]?abc:([\d\.]+)') ;    
 substring     
-----------    
 1.1    
(1 row)    

未命中则返回NULL

postgres=# select substring('abc:1.1,bc:100,c:293','[^,]?adbc:([\d\.]+)') ;    
 substring     
-----------    
     
(1 row)    
    
postgres=# select substring('abc:1.1,bc:100,c:293','[^,]?adbc:([\d\.]+)') is null;    
 ?column?     
----------    
 t    
(1 row)    

5、全文检索

参考 《用PostgreSQL 做实时高效 搜索引擎 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询》

select   

6、精排

计算ranking可能是结合 “命中的标签、评分、标签本身的权值” 根据算法得到一个ranking值。

根据4得到命中标签的评分,根据命中标签从tbl_weight得到对应的权值。

将算法封装到UDF,最后得到RANKING。

ranking算法的UDF函数内容略,请根据业务的需要编写对应算法,伪代码如下。

create or replace function cat_ranking(tsquery) returns float8 as $$  
declare  
    
begin  
  for each x in array (contains_element) loop  
    search hit element's score.  
    search hit element's weight.  
    cat ranking and increment  
  end loop;  
  return res;  
end;  
$$ language plpgsql strict;  

7、

7.1 删除标签与对应的评分:

regexp_replace 函数。

7.2 追加标签与对应的评分:

concat函数。

7.3 修改元素评分:

regexp_replace 函数。

以上都可以使用正则表达式来操作。

例子2 - 多维数组

使用数组来存储标签和权值,实际上在编程上会比使用tsvector更简单。

首先需要介绍一些用到的数组函数

根据元素求位置,根据标签,求它的位置,根据这个位置从score[]得到它的SCORE。  
  
postgres=# select array_position(array[1,2,null,null,2,2,3,1],null);  
 array_position   
----------------  
              3  
(1 row)  
  
postgres=# select array_positions(array[1,2,null,null,2,2,3,1],null);  
 array_positions   
-----------------  
 {3,4}  
(1 row)  
  
postgres=# select array_positions(array[1,2,null,null,2,2,3,1],2);  
 array_positions   
-----------------  
 {2,5,6}  
(1 row)  
  
求某个位置的元素  
  
array[i]  
  
postgres=# select (array[1,2,null,null,2,2,3,1])[1];  
 array   
-------  
     1  
(1 row)  
  
postgres=# select (array[1,2,null,null,2,2,3,1])[3];  
 array   
-------  
        
(1 row)  
  
postgres=# select (array[1,2,null,null,2,2,3,1])[5];  
 array   
-------  
     2  
(1 row)  
  
追加元素  
  
array_append  
  
替换元素  
  
array_replace  
  
删除某个元素  
  
array_remove,注意如果有一样的元素,都会被删掉(如果有一样的score,就的注意,需要用删除位置来删除元素)  
  
postgres=# select array_remove(array[1,2,null,null,2,2,3,1],2);  
   array_remove      
-------------------  
 {1,NULL,NULL,3,1}  
(1 row)  
  
删除某个位置的元素,  
  
postgres=# create or replace function array_remove(anyarray,int[]) returns anyarray as $$  
  select array(select $1[i] from (select id from generate_series(1,array_length($1,1)) t(id) where id <> all( $2) ) t(i))  
$$ language sql strict;  
CREATE FUNCTION  
postgres=# select array_remove(array[1,2,null,null,2,2,3,1],array[1,2]);  
    array_remove       
---------------------  
 {NULL,NULL,2,2,3,1}  
(1 row)  
  
postgres=# select array_remove(array[1,2,null,null,2,2,3,1],array[3,5]);  
   array_remove     
------------------  
 {1,2,NULL,2,3,1}  
(1 row)  

1、店铺标签表:

create table tbl (    
  shop_id int8 primary key,   -- 店铺 ID    
  tags text[],                -- 数组,标签1,标签2,.....       
  scores float8[]             -- 数组,评分1,评分2,.....  
);     
  
create index idx_tbl_1 on tbl using gin(tags);  
国民_足浴,国民_餐饮,娱乐_KTV  
  
0.99,0.1,0.45  

2、标签权值表:

create table tbl_weight (    
  tagid int primary key,   -- 标签ID     
  tagname name,            -- 标签名     
  desc text,               -- 标签描述    
  weight float8            -- 标签权值    
);    
  
create index idx_tbl_weight_1 on tbl_weight (tagname);  

3、包含、不包含、相交的数组查询。

https://www.postgresql.org/docs/10/static/functions-array.html

4、精排算法,与例子1类似。自定义UDF即可。

使用array简化了开发工作量,不需要使用正则表达式,效率也会提高。

参考

https://www.postgresql.org/docs/10/static/functions-matching.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
算法
自定义UUID算法
自定义UUID算法
68 0
|
关系型数据库 Go PostgreSQL
golang pgx自定义PostgreSQL类型
golang的pgx驱动提供了大约70种PostgreSQL类型支持,但还是有一些类型没有涵盖,本文介绍如何自己编写代码支持特殊的类型。
|
7月前
|
算法 安全 Java
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
【4月更文挑战第28天】性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
267 1
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
|
2月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
39 0
|
7月前
|
自然语言处理 算法 关系型数据库
postgresql 全文检索 SCWS和zhparser部署
UPDATE report_content SET content_tsv = to_tsvector('testzhcfg',content);
154 8
|
7月前
|
人工智能 自然语言处理 关系型数据库
|
6月前
|
负载均衡 算法 Nacos
SpringCloud之LoadBalancer自定义负载均衡算法,基于nacos权重
ReactorLoadBalancer接口,实现自定义负载算法需要实现该接口,并实现choose逻辑,选取对应的节点。
521 0
|
6月前
|
SQL 关系型数据库 PostgreSQL
【sql】PostgreSQL物化视图表使用案例
【sql】PostgreSQL物化视图表使用案例
70 0
|
7月前
|
负载均衡 算法 Java
Ribbon自定义负载均衡算法
Ribbon自定义负载均衡算法
69 1
|
7月前
|
算法 云计算 索引
生成UUID和自定义UUID算法
生成UUID和自定义UUID算法
475 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版