全文检索
全文检索在现代数据应用中扮演着非常重要的角色,能够极大程度地丰富数据应用并充分发挥数据的价值,本文将介绍trgm/tsvector/tsquery/中文分词等功能, 用户可以非常方便的将全文检索应用到数据处理应用中。
全文检索的挑战
实现全文检索,在数据架构中面临诸多挑战。
功能挑战
-
查询语法易用性:
- 需要提供用户易于理解和使用的查询语法,降低学习成本和使用门槛。
-
数据预处理功能:
-
词干提取:不同语言的词形变化多样,需要支持词干提取。比如搜索cat,希望能匹配到包含cats的文档。
-
停用词过滤:过滤掉常见但无意义的词汇, 如英语的“the,is”, 中文的“的地得”等。
-
性能挑战
-
性能与可扩展性:需要满足业务场景下的QPS和延迟要求,确保随着数据量增长仍能水平扩展。
-
数据实时性:保证搜索查询能检索到实时更新的数据,并确保查询结果的一致性。
基于trgm扩展计算字符串相似度
对于简单的仅需要字符串模糊匹配的检索场景,例如根据email中的几个字符搜索用户等。
ProtonBase 内置了 PostgreSQL 的pg_trgm扩展,通过使用三元组(trigram) 匹配增强了部分文本搜索的能力。pg_trgm 提供了一系列函数和操作符用于计算文本相似度。
三元组(trigram)是从字符串中取出的三个连续字符的组合。通过将文本分解为三元组,用户可以执行更有效和灵活的相似性搜索。
计算三元组
pg_trgm 模块计算文本字符串的三元组方式:
-
只考虑字母数字字符。
-
在计算三元组之前将字符串转换为小写。
-
每个单词假定前缀为两个空格,后缀为一个空格。
-
去重输出的三元组集。
计算相似性
给定两个字符串 A 和 B 的三元组集,pg_trgm 计算相似性得分为:
- 两个集合交集的大小除以两个集合并集的大小。
我们可以使用 show_trgm和similarity 函数来查看 pg_trgm 如何在字符串中计算三元组以及计算相似性:
SELECT show_trgm('Zhangsan'), show_trgm('Zhan'), similarity('Zhangsan', 'Zhan');
show_trgm | show_trgm | similarity
---------------------------------------------+-----------------------------+------------
{" z"," zh","an ",ang,gsa,han,ngs,san,zha} | {" z"," zh","an ",han,zha} | 0.5555556(1 row)
-- 两个输入字符串共有9个不同的三元组(并集),共有5个相同三元组(交集)。
-- 因此,相似性得分为 5/9 (0.5555556)。这个扩展简单易用, 特别适用于需要模糊字符串匹配的场景。
以下是一个简单的示例:
-- 创建test_email表
CREATE TABLE email_search (
email TEXT
) USING COLUMNAR;
INSERT INTO email_search (email) VALUES
('alice@example.com'),
('bob@sample.org'),
('charlie@gmail.com'),
('david@yahoo.com'),
('eve@hotmail.com'),
('frank@outlook.com'),
('gerry@qq.com'),
('lisi@sina.com'),
('zhangsan@qq.com');SPLIT_GIN索引
ProtonBase 内置了SPLIT_GIN的分布式倒排索引,来提升全文检索场景下的查询效率。
我们可以创建 SPLIT_GIN 索引以加速相关搜索查询,使用 gin_trgm_ops 参数, 可以加速 LIKE 和 ILIKE 运算符。
-- 创建索引
CREATE INDEX email_search_email_gin ON email_search USING SPLIT_GIN(email gin_trgm_ops);
-- 测试索引
textsearch=> SELECT email FROM email_search where email like '%zhangsan%';
email
-----------------
zhangsan@qq.com
(1 row)
textsearch=> SELECT email FROM email_search where email ilike '%lisi%';
email
---------------
lisi@sina.com
(1 row)基于tsvector和tsquery实现丰富的检索表达式
通过内置的~、~*、LIKE和ILIKE等操作符,以及trgm扩展, 我们可以支持简单的文本检索能力。
但对于复杂的检索场景,例如需要严格匹配单词,以及查询单词的组合AND/OR/NOT等,我们则需要利用更高级的功能。
ProtonBase提供以下两个基本的数据类型以及查询操作符支持更复杂的全文检索。
-
tsvector类型:表示将字符串根据选择的分词配置规则转换为词位(lexemes)的列表。 -
tsquery类型:表示一个文本查询,使用布尔操作符&(AND)、|(OR)和!(NOT)来组合词位。 -
@@查询操作符: tsvector @@ tsquery , 返回bool, 表示是该分词是否命中查询。
tsvector 类型
-
tsvector的功能是将字符串,根据选择的分词配置规则,转换为分词的类型,你可以理解为一组被抽象出来的词位。更多内容参考tsvector。- 内置的
to_tsvector函数,同时会做规范化(normalize)。
- 内置的
textsearch=> SELECT 'The Fat Rats'::tsvector;
tsvector
--------------------
'Fat' 'Rats' 'The'
(1 row)
textsearch=> SELECT to_tsvector('The Fat Rats');
to_tsvector
-----------------
'fat':2 'rat':3
(1 row)tsquery 类型
-
表示一个文本查询需要query的词位,并且使用布尔操作符
&(AND)、|(OR)和!(NOT)来组合它们。更多内容参考tsquery。- 内置的
to_tsquery函数,也会规范化。
- 内置的
textsearch=> SELECT 'Fat & Rats'::tsquery;
tsquery
----------------
'Fat' & 'Rats'
(1 row)
textsearch=> SELECT to_tsquery('english', 'Fat & Rats');
to_tsquery
---------------
'fat' & 'rat'
(1 row)tsquery 操作符
-
&(AND)操作符指定它的两个参数都必须出现在文档中才表示匹配。 -
|(OR)操作符指定至少一个参数必须出现 -
!(NOT)操作符指定它的参数不出现才能匹配。例如,查询fat & ! rat匹配包含fat但不包含rat的文档。 -
<->(FOLLOWED BY)tsquery运算符,可以搜索短语, 仅当其参数具有相邻且按给定顺序匹配时才匹配。例如:textsearch=> SELECT to_tsvector('fatal error') @@ to_tsquery('fatal <-> error'); ?column? ---------- t textsearch=> SELECT to_tsvector('error is not fatal') @@ to_tsquery('fatal <-> error'); ?column? ---------- f -
<N>是一个更通用的 FOLLOWED BY 运算符版本, 其中N是一个整数,表示匹配词元位置之间的差异。<1>等同于<->, 而<2>允许匹配之间出现一个其他词元,依此类推。phraseto_tsquery函数利用此运算符构建一个 可匹配多词短语的tsquery,当其中一些词是停用词时。例如:textsearch=> SELECT phraseto_tsquery('cats ate rats'); phraseto_tsquery --------------------------- 'cat' <-> 'ate' <-> 'rat' (1 row) textsearch=> SELECT phraseto_tsquery('the cats ate the rats'); phraseto_tsquery --------------------------- 'cat' <-> 'ate' <2> 'rat' (1 row) -
圆括号可以被用来控制
tsquery操作符的嵌套。- 如果没有圆括号,
|的计算优先级最低,然后从低到高依次是&、<->、!。
- 如果没有圆括号,
tsquery相关函数
plainto_tsquery
plainto_tsquery将未格式化的文本querytext转换成一个tsquery值。该文本被解析并被正规化,很像to_tsvector,然后&(AND)布尔操作符被插入到留下来的词之间。
textsearch=> SELECT plainto_tsquery('english', 'The Fat Rats');
plainto_tsquery
-----------------
'fat' & 'rat'
(1 row)-
websearch_to_tsquerywebsearch_to_tsquery使用一种可供选择的语法从querytext创建一个tsquery值,这种语法中简单的未格式化文本是一个有效的查询。和plainto_tsquery以及phraseto_tsquery不同,它还识别特定的操作符。此外,这个函数绝不会报出语法错误,这就可以把原始的用户提供的输入用于搜索。支持下列语法:-
无引号文本:不在引号中的文本将被转换成由&操作符分隔的词,就像被plainto_tsquery处理过那样。 -
"引号文本":在引号中的文本将被转换成由<->操作符分隔的词,就像被phraseto_tsquery处理过那样。 -
OR:“or”将转换为|运算符。 -
-:破折号将转换为!运算符。
-
textsearch=> SELECT websearch_to_tsquery('english', 'The fat rats');
websearch_to_tsquery
----------------------
'fat' & 'rat'
(1 row)
textsearch=> SELECT websearch_to_tsquery('english', '"supernovae stars" -crab');
websearch_to_tsquery
----------------------------------
'supernova' <-> 'star' & !'crab'
textsearch=> SELECT websearch_to_tsquery('english', '"sad cat" or "fat rat"');
websearch_to_tsquery
-----------------------------------
'sad' <-> 'cat' | 'fat' <-> 'rat'
(1 row)
textsearch=> SELECT websearch_to_tsquery('english', 'signal -"segmentation fault"');
websearch_to_tsquery
---------------------------------------
'signal' & !( 'segment' <-> 'fault' )
(1 row)
textsearch=> SELECT websearch_to_tsquery('english', '""" )( dummy \\ query <->');
websearch_to_tsquery
----------------------
'dummi' <-> 'queri'
(1 row)SPLIT_GIN索引
建议为ts_vector字段创建SPLIT_GIN索引。
-- 指定为列存,方便使用SPLIT_GIN index
CREATE TABLE text_search (content text) using COLUMNAR;
INSERT INTO text_search VALUES
('Ruby on Rails for web application development.'),
('Rust ownership and memory safety.'),
('Concurrency in Golang programming.'),
('Building web APIs with Golang and Rust.'),
('Golang vs Rust: A comparison of programming languages.'),
('Mobile app development using React Native.'),
('Functional programming with Haskell and Scala.'),
('The impact of cloud computing on modern IT.'),
('Security best practices in web development.'),
('Optimizing SQL queries for performance.'),
('JavaScript frameworks for web application development.'),
('Software development life cycle methodologies.'),
('Artificial intelligence and machine learning in Python.');
--为该文档增加tsvector计算列 (也可以添加为普通列)
ALTER TABLE text_search ADD tsv_content TSVECTOR
GENERATED ALWAYS AS (to_tsvector('english', content)) STORED;
-- 为该tsvector列创建索引
CREATE INDEX text_search_tsv_gin ON text_search USING SPLIT_GIN(tsv_content);查询示例
textsearch=> SELECT content FROM text_search WHERE tsv_content @@ to_tsquery('english', 'web & development');
content
--------------------------------------------------------
Security best practices in web development.
Ruby on Rails for web application development.
JavaScript frameworks for web application development.
(3 rows)
textsearch=> SELECT content FROM text_search WHERE tsv_content @@ to_tsquery('english', 'web <-> development');
content
---------------------------------------------
Security best practices in web development.
(1 row)
textsearch=> SELECT content FROM text_search WHERE tsv_content @@ to_tsquery('english', 'JavaScript | application');
content
--------------------------------------------------------
Ruby on Rails for web application development.
JavaScript frameworks for web application development.
(2 rows)
textsearch=> SELECT content FROM text_search WHERE tsv_content @@ to_tsquery('english', 'Rust & !programming');
content
-----------------------------------------
Building web APIs with Golang and Rust.
Rust ownership and memory safety.
(2 rows)
textsearch=> SELECT content FROM text_search WHERE tsv_content @@ to_tsquery('english', 'cloud | !develop');
content
---------------------------------------------------------
Rust ownership and memory safety.
Concurrency in Golang programming.
Building web APIs with Golang and Rust.
Golang vs Rust: A comparison of programming languages.
Functional programming with Haskell and Scala.
The impact of cloud computing on modern IT.
Optimizing SQL queries for performance.
Artificial intelligence and machine learning in Python.
(8 rows)中文分词
ProtonBase也提供了一组内置的中文分词config,只需要将 to_tsvector 以及 to_tsquery 的 english 改成 chinese 即可。
textsearch=> SELECT to_tsvector('chinese', '中国北京');
to_tsvector
-------------------
'中国':1 '北京':2
(1 row)SPLIT_GIN索引
-- 指定为列存,方便使用SPLIT_GIN index
CREATE TABLE text_search_cn (content text) using COLUMNAR;
INSERT INTO text_search_cn VALUES
('这是一个测试文档,用于演示中文分词功能。'),
('ProtonBase代表着先进的云原生分布式数据库,兼容PostgreSQL。'),
('在数据库设计中,合理使用索引可以显著提高查询性能。'),
('PostgreSQL是一款强大的开源关系型数据库管理系统,以其高度的可扩展性、丰富的功能集而受到广泛赞誉。'),
('Python编程语言在人工智能和机器学习中非常流行。'),
('Rust是一种强调内存安全、并发性和零成本抽象的编程语言。'),
('Golang在编程语言中以强大的并发支持闻名。'),
('Web开发中中文分词非常重要。'),
('ProtonBase的tsvector很强大,支持中文搜索。')
;
-- 为该文档增加tsvector计算列 (也可以添加为普通列)
ALTER TABLE text_search_cn ADD tsv_content TSVECTOR
GENERATED ALWAYS AS (to_tsvector('chinese', content)) STORED;
-- 为该tsvector列创建索引
CREATE INDEX text_search_cn_tsv_gin ON text_search_cn USING SPLIT_GIN(tsv_content);-- 查询示例
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', '中文');
content
--------------------------------------------
这是一个测试文档,用于演示中文分词功能。
ProtonBase的tsvector很强大,支持中文搜索。
Web开发中中文分词非常重要。
(3 rows)
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', '数据库 & 分布式');
content
------------------------------------------------------------
ProtonBase代表着先进的云原生分布式数据库,兼容PostgreSQL。
(1 row)
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', '数据库 <-> 设计');
content
----------------------------------------------------
在数据库设计中,合理使用索引可以显著提高查询性能。
(1 row)
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', 'PostgreSQL & 数据库');
content
--------------------------------------------------------------------------------------------------
ProtonBase代表着先进的云原生分布式数据库,兼容PostgreSQL。
PostgreSQL是一款强大的开源关系型数据库管理系统,以其高度的可扩展性、丰富的功能集而受到广泛赞誉。
(2 rows)
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', 'python | 编程语言');
content
--------------------------------------------------------
Python编程语言在人工智能和机器学习中非常流行。
Golang在编程语言中以强大的并发支持闻名。
Rust是一种强调内存安全、并发性和零成本抽象的编程语言。
(3 rows)
textsearch=> SELECT content FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', '(并发|数据库)&查询');
content
----------------------------------------------------
在数据库设计中,合理使用索引可以显著提高查询性能。
(1 row)
-- 排序
textsearch=> SELECT
ts_rank(tsv_content, to_tsquery('chinese', 'PostgreSQL & 数据库')) as rank,
content
FROM text_search_cn
WHERE tsv_content @@ to_tsquery('chinese', 'PostgreSQL & 数据库')
ORDER BY rank desc;
rank | content
-------------+--------------------------------------------------------------------------------------------------
0.098500855 | ProtonBase代表着先进的云原生分布式数据库,兼容PostgreSQL。
0.09148999 | PostgreSQL是一款强大的开源关系型数据库管理系统,以其高度的可扩展性、丰富的功能集而受到广泛赞誉。
(2 rows)全文搜索排名
在 ProtonBase 中,全文搜索不仅能够找到匹配的文档,还能通过排名函数评估每个结果的相关性。
核心排名函数
ProtonBase 提供了两个主要的排名函数:
ts_rank([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ])
- 基于词频(term frequency)进行排名
- 不考虑词在文档中的位置信息
ts_rank_cd([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ])
- "cd" 代表 "cover density"
- 除了词频外,还考虑匹配词在文档中的接近程度
- 通常比
ts_rank计算成本更高但结果更精确
权重参数
权重参数用于调整不同文本部分的优先级:
SELECT ts_rank('{0.1, 0.2, 0.4, 1.0}', textsearchable_index_col, query)权重数组对应:
- 0.1: D 权重 - 标题以外的部分
- 0.2: C 权重 - 标题
- 0.4: B 权重 - 摘要
- 1.0: A 权重 - 正文内容
标准化选项
标准化选项控制排名值如何根据文档长度进行调整:
SELECT ts_rank(textsearchable_index_col, query, 32)常用标志(可以组合使用):
- 0(默认):不进行标准化
- 1: 除以 (文档长度 + 1)
- 2: 除以文档长度
- 4: 除以平均文档长度
- 8: 除以文档中唯一词的数量
- 16: 除以 (文档中唯一词的数量 + 1)
- 32: 使用对数缩放
权重分配
在 ProtonBase 中,您可以对不同字段分配不同权重:
-- 创建带权重的TSVECTOR列
ALTER TABLE products ADD COLUMN tsv_weighted TSVECTOR;
UPDATE products SET tsv_weighted =
setweight(to_tsvector('english', coalesce(name, '')), 'A') || -- 最高权重
setweight(to_tsvector('english', coalesce(description, '')), 'B') ||
setweight(to_tsvector('english', coalesce(tags::text, '')), 'C'); -- 最低权重
-- 使用带权重的搜索
SELECT
id,
name,
ts_rank(tsv_weighted, plainto_tsquery('premium coffee')) AS relevance
FROM products
WHERE tsv_weighted @@ plainto_tsquery('premium coffee')
ORDER BY relevance DESC;实际应用示例
电商产品搜索
-- 为产品表创建全文搜索索引
ALTER TABLE products ADD COLUMN search_vector TSVECTOR;
UPDATE products SET search_vector =
setweight(to_tsvector('english', name), 'A') ||
setweight(to_tsvector('english', description), 'B') ||
setweight(to_tsvector('english', array_to_string(specs, ' ')), 'C');
-- 执行带排名的搜索
SELECT
id,
name,
ts_rank_cd(search_vector,
websearch_to_tsquery('wireless charging pad'),
32) AS relevance,
ts_headline(description, websearch_to_tsquery('wireless charging pad'),
'StartSel=<mark>, StopSel=</mark>') AS highlighted_desc
FROM products
WHERE search_vector @@ websearch_to_tsquery('wireless charging pad')
ORDER BY relevance DESC
LIMIT 10;内容管理系统
-- 文章搜索优化
SELECT
articles.id,
articles.title,
ts_rank(articles.search_vector, query) AS title_rank,
ts_rank(articles.content_vector, query) AS content_rank,
ts_rank(
setweight(articles.search_vector, 'A') ||
setweight(articles.content_vector, 'B'),
query
) AS combined_rank,
authors.name AS author
FROM
articles,
authors,
plainto_tsquery('postgresql performance tuning') AS query
WHERE
articles.author_id = authors.id AND
(articles.search_vector @@ query OR articles.content_vector @@ query)
ORDER BY combined_rank DESC;基于 BM25 的全文检索
BM25 索引支持在 tsvector 类型的列上进行高效的全文搜索。使用 BM25 全文搜索功能,首先需要在 tsvector 类型的列上创建 BM25 索引。
CREATE TABLE bm25_example
(
id int,
content text,
content_tsv tsvector
);
CREATE INDEX ON bm25_example USING split_bm25 (content_tsv);如果需要在 text 等其它非 tsvector 类型列上进行全文搜索,需要创建相应的 tsvector 类型的生成列。
CREATE TABLE bm25_example
(
id int,
content text,
content_tsv tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', content)) STORED
);
CREATE INDEX ON bm25_example USING split_bm25 (content_tsv);BM25 查询
简单的过滤查询
下面的查询返回所有同时包含 hello 和 world 的结果。
SELECT id FROM bm25_example WHERE content_tsv @@@ 'hello AND world'::bm25query;@@@ 运算符检查 tsvector 和 bm25query 是否匹配。
BM25 Top-N 查询
SELECT id
FROM bm25_example
ORDER BY bm25_score(content_tsv, 'hello AND world'::bm25query) DESC NULLS LAST
LIMIT 10;相关性越高,bm25_score() 函数返回的相关性得分越大;另外由于 NULL 默认最大,因此为了按相关性得分从大到小排列、并且将 NULL 排在最后,需要加上 DESC NULLS LAST。
为简化使用,我们提供了 <@> 运算符,返回负的 BM25 相关性得分。因此上面的查询可以简化为:
SELECT id
FROM bm25_example
ORDER BY content_tsv <@> 'hello AND world'::bm25query
LIMIT 10;bm25query
bm25query 的输入采用 Lucene 语法,参考 Lucene Query Parser Syntax (opens in a new tab)。
支持的特性包括:
-
通配符查询
?匹配任意单个字符,如'te?t'::bm25query;*匹配 0 个、1 个或多个任意字符,如'te*t'::bm25query。 -
正则表达式
两个斜线围起来表示正则表达式匹配,如
'/[mb]oat/'::bm25query表示匹配moat或boat。 -
模糊匹配
~符号跟在词后表示进行模糊匹配,基于编辑距离。编辑距离跟在~符号后面,可选值为 0、1、2,默认值为 2,如app~1。 -
短语匹配
使用双引号引起来表示短语匹配,如
'"hello world"'::bm25query表示要求world必须紧跟在hello之后。 -
邻近匹配
短语后面跟
~符号表示邻近匹配,~后面的数字表示短语中所有相邻词的间隔之和,如'"hello world"~3'::bm25query表示hello和world中间最多有 3 个词。 -
调整权重(boosting)
要调整查询中某个部分的权重,可以在后面跟
^符号再跟上具体权重数值。大于 1 表示增加权重,小于 1 表示减小权重。 -
布尔运算
支持
AND、OR、NOT三个布尔运算符(必须全部大写),&&、||、!与之等价。如'hello AND world'、'hello && world'表示hello和world同时存在。 -
+、-运算符+放置在某个组件前面表示该组件必须被匹配;-放在前面表示必须不能被匹配。如'+hello -world'表示必须包含hello且不能包含world。 -
分组运算符
使用
()将某一部分括起来作为整体,也可用来改变运算符结合的优先级。如'apple AND (hello OR world)^3.5'::bm25query。
BM25 相关函数及运算符
-
bm25_score(document tsvector, query bm25query) → float返回 document 和 query 的 BM25 相关性得分。
-
tsvector <-> bm25query → floatbm25_score()函数的运算符形式。 -
neg_bm25_score(document tsvector, query bm25query) → float返回 BM25 相关性得分的负值。
-
tsvector <@> bm25query → floatneg_bm25_score()函数的运算符形式。 -
tsvector @@@ bm25query → boolean判断
tsvector和bm25query是否匹配,匹配返回true。 -
plainto_bm25query(config regconfig, querytext text [, combine_op text]) → bm25query将
querytext按照config处理后得到的词,按combine_op组合得到bm25query。combine_op可选值为'AND'或'OR',默认为'OR'。'AND'表示每个词都必须包含,'OR'表示任意词被包含即可。postgres=> SELECT plainto_bm25query('english', 'green apple', 'AND'); plainto_bm25query ------------------- green AND appl (1 row) postgres=> SELECT plainto_bm25query('english', 'green apple', 'OR'); plainto_bm25query ------------------- green OR appl (1 row) -
phraseto_bm25query(config regconfig, querytext text [, slop int]) → bm25query将
querytext按照config处理后得到的词,组合成短语bm25query。slop表示相邻词之间最大间隔之和。postgres=> SELECT phraseto_bm25query('english', 'green apple', 3); phraseto_bm25query -------------------- "green appl"~3 (1 row) -
luceneto_bm25query([config regconfig], querytext text) → bm25queryquerytext先按 Lucene 语法解析,然后对其中的 term 按config处理。postgres=> SELECT luceneto_bm25query('/(green|red)/ OR apple'); luceneto_bm25query ----------------------- /(green|red)/ OR appl (1 row) -
split_to_tsvector(document text, delimiters text [, option text]) → tsvector将
document按delimiters中的任意字符分隔得到tsvector。option当前支持'i'或'c',默认为'i'。'i'表示忽略大小写、统一转为小写,'c'表示大小写敏感。postgres=> SELECT split_to_tsvector('a,B.c', ',.', 'i'); split_to_tsvector ------------------- 'a':1 'b':2 'c':3 (1 row) postgres=> SELECT split_to_tsvector('a,B.c', ',.', 'c'); split_to_tsvector ------------------- 'a':1 'B':2 'c':3 (1 row) -
split_to_tsvector(document jsonb, delimiters text [, option text]) → tsvector将
jsonb类型的document中所有字符串(仅叶节点上的值,JSON object 的 key 被忽略)按delimiters中的字符分隔;数值转为字符串且不按delimiters切分,true、false、null分别转为字符串'true'、'false'、'null'。postgres=> SELECT split_to_tsvector('{"key": "a,b,C", "num":123.3}'::jsonb, ',.', 'i'); split_to_tsvector ----------------------------- 'a':1 'b':2 'c':3 '123.3':4 (1 row)
限制
- BM25 索引仅支持纯列存表和混存(hybrid)表。
- 索引不存在或者未被应用时,
bm25_score()、neg_bm25_score()、<->、<@>返回 NULL,@@@运算符返回false。 - 只有事务被提交之后,数据才对 BM25 索引可见。
- 当前计算 BM25 分值的统计信息(如文档频率等)是文件级别,而非全局统计值。