服装网站建设的规模和类别,建设部网站公告,全网推广服务,学历提升大专大概要多少钱pgsql_全文检索_使用空间换时间的方法支持中文搜索
一、环境
PostgreSQL 14.2, compiled by Visual C build 1914, 64-bit
二、引言
提到全文检索首先想到的就是ES(ElasticSearch)和Lucene#xff0c;专业且强大。对于一些小众场景对于搜索要求不高#xff0c;数据量也不…pgsql_全文检索_使用空间换时间的方法支持中文搜索
一、环境
PostgreSQL 14.2, compiled by Visual C build 1914, 64-bit
二、引言
提到全文检索首先想到的就是ES(ElasticSearch)和Lucene专业且强大。对于一些小众场景对于搜索要求不高数据量也不大的情况 上ES等有些繁重增加工作量还增加了后期运维成本。 PgSql也支持全文检索原理和ES一样支持分词和反向索引(倒排索引)比如数据量只有几十万时可以考虑直接使用DB去做查询。
三、帮助文档
全文检索控制文本搜索文本搜索类型
四、概念
ES执行全文检索的逻辑是
需要对目标内容文档做分词分词是将内容拆分成各个独立的词每个词会有词频和在内容中的位置等信息使用分词后的内容生成索引文件这个就是生成倒排索引的阶段是每个词关联到不同的文档查询时需要对查询关键词进行分词跟第一步很像只带分词的文档长度小了很多使用查询关键词匹配索引文件按照词频、相似度、权重等指标对目标文档检索并按得分对文档排序返回最终匹配的文档记录
五、PgSQL全文检索基础
PgSQL全局检索前需要了解三个基础概念文档、查询、操作符。 tsvector类型表示一个为文本搜索优化的形式下的文档tsquery类型表示一个文本查询。
tsvector文档类型 tsvector是一个数据类型和varchar、integer类似。一个tsvector值是一个排序的可区分词位的列表记录了分词后的词条、词频、词位、权重信息。
SELECT to_tsvector(hello word!hello word!);
------
hello:1,3 word:2,4其中hello是词条后边的数据是词位逗号分割的是多个词条在文档中的位置词位的数量可以反应该词在文档中的词频。
tsquery查询类型 对多个查询关键词做与或非逻辑表达支持的逻辑操作符有与、|或和!非
select to_tsquery(hello word);
------
hello word匹配操作符 使用查询检索文档返回一个true/false的结果标记操作是否匹配
SELECTto_tsvector(hello word!) query q1,to_tsvector(hello word1!) query q2,to_tsvector(hello word2!) query q3
from to_tsquery(hello word) query;
------
q1 q2 q3
true false false六、排序计算匹配得分
排序有两个函数支持ts_rank()、ts_rank_cd() 他们都会参考词频、相似度但ts_rank_cd()会计算覆盖密度排名。
-- 计算文档中同时包含hello和word的文档得分
SELECT ts_rank_cd(to_tsvector(hello word!), to_tsquery(hello word));
SELECT ts_rank(to_tsvector(hello word!), to_tsquery(word word));
--
SELECT ts_rank_cd (to_tsvector(hello word!), query),ts_rank (to_tsvector(hello word!),query)
from to_tsquery(hello word) query;七、控制权重
tsvector是一个标准的DB类型是类型就可以做显示转换在pgsql中类型显示转换的操作符是两个冒号(:。 前面用到的to_tsvector()函数默认会按照英文的语法使用空格对文档进行分词把文档分词后做词频统计。 pgsql支持的权重值有四个按照权重从大到小分别是A、 B、C、D。
将字符串转tsvector类型 原始文档“hello word! hello word!”分词 select to_tsvector(‘hello word! hello word!’);自定义权重select ‘hello:1A,3B word:2C,4D’::tsvector; 其中的权重值A、B、C、D是人为加的,需要满足下列格式要求1.多个词条用空格分隔2.每个词条后用冒号:分隔冒号左边是词右边是词位、词频、权重信息
--文档分词
select to_tsvector(hello word! hello word!);
select hello:1A,3B word:2C,4D::tsvector;
--词频影响得分
SELECTts_rank(to_tsvector(hello word!),query) rank1,ts_rank(to_tsvector(hello word! hello word!),query) rank2
from to_tsquery(hello word) query;
----
rank1 rank2
0.09910322 0.34000534rank2中word出现两次所以在计算得分时rank2比rank1高。
--权重影响得分
SELECTts_rank(hello:1,3 word:2,4::tsvector,query) rank1,ts_rank(hello:1A word:2A::tsvector,query) rank2
from to_tsquery(word) query;
----------
rank1 rank2
0.075990885 0.6079271word词条在rank1的词频比rank2词频高但通过权重控制最终词频低的得分变高了。
八、高亮显示
高亮显示比较简单使用 tsquery 类型对文档内的关键字加上html的b标签。
--高亮
SELECT ts_headline,ts_headline (hello word!hello word!,query)
from to_tsquery(word) query;
------
hello bword/b!hello bword/b!九、提高性能使用 GIN 和 GiST 索引
有两种索引可以被用来加速全文搜索。注意全文搜索并非一定需要索引但是在一个定期会被搜索的列上通常需要有一个索引。
CREATE INDEX name ON table USING GIN(column); 创建一个基于 GIN通用倒排索引的索引。column必须是tsvector类型。 CREATE INDEX name ON table USING GIST(column); 创建一个基于 GiST通用搜索树的索引。column可以是tsvector或tsquery类型。
GIN 索引是更好的文本搜索索引类型。作为倒排索引每个词词位在 其中都有一个索引项其中有压缩过的匹配位置的列表。多词搜索可以找到 第一个匹配然后使用该索引移除缺少额外词的行。GIN 索引只存储 tsvector值的词词位并且不存储它们的权重标签。因此 在使用涉及权重的查询时需要一次在表行上的重新检查。
一个 GiST 索引是有损的这表示索引可能产生假匹配并且有必要检查真实的表行来消除这种假匹配PostgreSQL在需要时会自动做这一步。GiST 索引之所以是有损的是因为每一个文档在索引中被表示为一个定长的签名。该签名通过哈希每一个词到一个 n 位串中的一个单一位来产生通过将所有这些位 OR 在一起产生一个 n 位的文档签名。当两个词哈希到同一个位位置时就会产生假匹配。如果查询中所有词都有匹配真或假则必须检索表行查看匹配是否正确。
GiST 索引可以被覆盖例如使用INCLUDE子句。 包含的列可以具有没有任何 GiST 操作符类的数据类型。 包含的属性将非压缩存储。
有损性导致的性能下降归因于不必要的表记录即被证实为假匹配的记录获取。因为表记录的随机访问是较慢的这限制了 GiST 索引的可用性。假匹配的可能性取决于几个因素特别是唯一词的数量因此推荐使用词典来缩减这个数量。
总结
对于简单的全文检索场景使用pgsql就可以实现对于检索的基础概念如文档、查询和操作符词频、权重、排序、高亮都简单说明。
pgsql默认的to_tsvector()函数只支持使用空格进行分词对于中文这个函数就不好用了。
对于中文分词有两个方案解决1使用pgsql的中文分词插件2利用空间换时间的方法在记录写入db前利用java的jieba等分词组件对文档分词并按 tsvector格式拼接独立一列记录分词后的类型。如果需要提高检索效率考虑在tsvector字段上添加GIN类型索引。
两种方法各有利弊使用是权衡考虑。