全文检索

介绍

全文检索(或者文本搜索)提供了能识别自然语言文档的查询能力,并可以有选择地将结果按照查询的相关度排序。最常用的搜索类型是找到所有包含给定查询词的文档并按照它们与查询的相似性顺序返回它们。

为实现全文检索,第一种是全量扫描逐行匹配,另一种是通过构建索引加快查询的速度。

文本搜索操作在数据库中已经存在多年了,对于文本数据类型,UDB-TX有~, ~*, LIKE,以及ILIKE运算符,但是它们缺少现代信息系统所需的许多基本属性。如: 没有语言支持,即使是英语。正则表达式是不够的,因为它们不容易处理派生单词; 它们不提供搜索结果的排序;它们往往很慢,因为没有索引支持,所以每次搜索都必须处理所有文档。

全文索引允许文档被预处理并为以后的快速搜索保存一个索引。预处理包括:

  • 将文档解析成Token。Token的类型依赖于特定的应用程序,但是对于大多数情况下,使用一组预定义的类型就足够了。UDB-TX使用Parser来执行这一步。默认情况下提供了一个标准的Parser,并且可以为特定的需求创建定制的Parser。

  • 将Token转换为词素。词素就是按照字典,将Token标准化为词素(英语中的各种变体),并消除停用词。UDB-TX提供了各种标准词典,并且可以根据具体需要创建自定义词典。

  • 存储为搜索而优化的预处理文档。例如,每个文档都可以表示为一个标准化词素的排序数组。除了词素,通常还需要存储位置信息相似度排序,这样包含更多查询词素的区域被分配比具有分散查询词的区域更高的等级。

数据类型tsvector用于存储预处理文档以及一个类型tsquery表示已处理过的查询。有许多函数和运算符可用于这些数据类型,其中最重要的是匹配操作符@@

文档

文档是全文搜索系统中的搜索单位;例如,杂志文章或电子邮件消息。文本搜索引擎必须能够解析文档并存储词素与文档的关联。

UDB-TX中,文档通常是数据库表的一行中的文本字段,或者可能是这些字段的组合,也可能存储在几个表中或者动态获得。换句话说,一个文档可以由不同的部分组成。例如:

SELECT title || ' ' ||  author || ' ' ||  abstract || ' ' || body AS document
FROM messages
WHERE mid = 12;
SELECT m.title || ' ' || m.author || ' ' || m.abstract || ' ' || d.body AS document
FROM messages m, docs d
WHERE m.mid = d.did AND m.mid = 12;

注意: 实际上,在这些示例查询中,coalesce应该用来防止单一的NULL属性不会导致整个文档的NULL结果。

另一种可能性是将文档作为简单的文本文件存储在文件系统中。在这种情况下,数据库可以用来存储全文索引和执行搜索,一些独特的标识符可以用来从文件系统中检索文档。然而,从数据库外部检索文件需要超级用户权限或特殊功能支持,因此这通常不如将所有数据保存在内部方便。此外,将所有内容保存在数据库中可以方便地访问文档元数据,以帮助索引和显示。

为了进行文本搜索,每个文档必须简化为预处理的tsvector格式。搜索和排名完全在代表文档的tsvector——只有当文档已被选择向用户显示时,才需要检索原始文本。因此,我们经常谈到tsvector来代表文档,当然它只是完整文档的一个压缩表示。

基本文本匹配

UDB-TX的全文搜索是基于匹配运算符@@,如果一个tsvector(文档)匹配一个tsquery(查询),那它就返回true。先写入哪种数据类型并不重要:

SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat & rat'::tsquery;
 ?column?
----------
 t
SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat rat'::tsvector;
 ?column?
----------
 f

tsquery包含搜索项,这些搜索项必须是已经规范化的词素,并且可以使用AND、OR、NOT和后跟运算符来组合多个搜索项。函数to_tsquery, plainto_tsquery,以及phraseto_tsquery可以帮助将用户编写的文本转换成正确的tsquery 。 同样的,to_tsvector用于解析和规范化文档字符串。因此,在实践中,文本搜索匹配看起来更像这样

SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');
 ?column? 
----------
 t

这个@@操作符还支持text输入,允许将文本字符串显式转换为tsvector或者tsquery在简单的情况下可以跳过。可用的变型有:

tsvector @@ tsquery
tsquery  @@ tsvector
text @@ tsquery
text @@ text

对于tsquery&(AND)运算符指定它的两个参数都必须出现在文档中才能匹配。同样,|(OR)运算符指定必须至少有一个参数出现,而!(NOT)运算符指定其参数为不匹配。例如,查询fat & ! rat匹配包含fat但包含rat的文档。

通过tsquery运算符<->,可以用来匹配具有相邻且按给定顺序的词素。例如:

SELECT to_tsvector('fatal error') @@ to_tsquery('fatal <-> error');
 ?column? 
----------
 t
SELECT to_tsvector('error is not fatal') @@ to_tsquery('fatal <-> error');
 ?column? 
----------
 f

UDB-TX支持的分词系统

全文索引的一个前提是对于复杂文本进行分词,即提取Key。UDB-TX支持多种分词系统:SCWS分词、pg_jieba分词、pg_bigm(二元分词)、pg_trgm(三元分词)。

SCWS分词

SCWS (Simple Chinese Words Segmentation)即简易中文分词系统。这是一套基于词频词典的机械中文分词引擎,它能将一整段的汉字基本正确的切分成词。词是汉语的基本语素单位,而书写的时候不像英语会在词之间用空格分开。SCWS 采用的是自行采集的词频词典,并辅以一定程度上的专有名称、人名、地名、数字年代等规则集,切词效率高。UDB-TX支持zhparser和SCWS搭配使用。

pg_jieba分词

jieba号称是Python中最好的中分词库。基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能词情况所构成的有向无环图;采用动态规划查找最大概率路径,找出基于词频的最大切分组合;对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法。

pg_bigm二元分词

顾名思义,是将文档中的字进行前后两两结合,具体“我在深圳南山区”可以分词称为“我在、在深、深圳、圳南、南山、山区”,当然也是可以设置N元分词(N一般为1~10),因为pg_bigm是在pg_trgm的基础上发展起来的。。

pg_trgm三元分词

pg_trgm是内置模块,该模块使用3-gram(三元模型)模型提供全文搜索功能。但是不支持非字母语言的全文搜索。即不支持中文。 本文的重点是中文全文检索,所以内容主要涵盖 SCWS分词pg_jieba分词、和pg_bigm二元分词

pg_bigm 与 pg_trgm的比较

功能和特性 pg_trgm pg_bigm
用于全文搜索的匹配方法 3-gram 2-gram
可用索引 GIN and GiST GIN only
可用的文本搜索运算符 LIKE(), ILIKE(), ~ , ~* LIKE only
非字母语言的全文搜索 (例如,中语) 不支持 支持
使用1-2个字符的关键字进行全文搜索 慢(
相似性搜索 支持 支持
最大索引列大小 238,609,291 Bytes (~228MB) 107,374,180 Bytes (~102MB)

全文检索常见索引

GIN索引结构

GIN索引(Generalized Inverted Index, 通用倒排索引)是一个存储对(key, posting list)集合的索引结构,其中key是一个键值,而posting list 是一组出现过key的位置。如(‘祖国’, ‘14:2 23:4’)中,表示“祖国”在14:2和23:4这两个位置出现过,在UDB-TX中这些位置实际上就是元组的TID(行号:Data Block ID(32bit)+ Item Point(16 bit) )。表中的每一个属性,在建立索引时,都可能会被解析为多个键值,所以同一个元组的TID可能会出现在多个key的posting list中。

逻辑结构

GIN索引在逻辑上可以看成一个relation,该relation有两种结构:

1.只索引基表的一列

key value
Key1 Posting list( or posting tree)
Key2 Posting list( or posting tree)
  1. 索引基表的多列(复合、多列索引)

column_id key value
Column1 num Key1 Posting list( or posting tree)
Column2 num Key1 Posting list( or posting tree)
Column3 num Key1 Posting list( or posting tree)

这种结构,对于基表中不同列的相同的key,在GIN索引中也会当作不同的key来处理。

物理结构

GIN索引在物理存储上包含如下内容:

Entry GIN索引中的一个元素,可以认为是一个词位,也可以理解为一个key
Entry tree 在Entry上构建的B树
Posting List 一个Entry出现的物理位置(heap ctid, 堆表行号)的链表
Posting Tree 在一个Entry出现的物理位置链表(heap ctid, 堆表行号)上构建的B树,所以posting tree的Key是ctid,而entry tree的Key是被索引的列的值
Pending List 索引元组的临时存储链表,用于fastupdate模式的插入操作

从上面可以看出GIN索引主要由Entry tree和Posting Tree(or Posting List)组成,其中Entry tree是GIN索引的主结构树,Posting Tree是辅助树。Entry Tree类似于B+tree,而Posting Tree则类似于B-tree。另外,不管Entry Tree还是Posting Tree,它们都是按KEY有序组织的

RUM索引

RUM索引与GIN类似,但是在Posting List|Tree的每一个ctid后面会追加一些属性值,例如(‘祖国’, ‘14:2:100’)表示“祖国”在14:2 这个位置出现了100次,这个频次就是一种额外的信息,在处理排序或者统计出现频次的时候,性能很优异。可以说RUM索是对GIN索引的一种加强,但是RUM索引的膨胀率要比GIN索引高,维护索引会消耗更多的性能。

注意: RUM索引不属于UDB-TX内置的索引类型,需要通过插件的方式加载后才能使用。 例子如下:

unvdb=# create extension rum;
unvdb=# create index on ts using rum(doc_tsv);

GIN索引(通用倒排索引)支持通过tsvector和tsquery两种数据类型进行全文检索,但是有如下几个问题:

  • 排序慢

    需要有关词汇的位置信息才能进行排序。GIN索引不存储词汇的位置,因此在索引扫描之后,需要额外的扫描来检索词汇位置。

  • 短语查询慢

    GIN索引需要位置信息来执行短语搜索。

  • 时间戳排序慢

    GIN索引无法在带有词素的索引中存储一些相关信息,因此需要执行额外的扫描。

基于GIN索引,UDB-TX提供RUM插件,在RUM索引中存储额外的信息(词汇位置或时间戳的位置信息)来解决以上问题。

RUM索引的缺点是构建和插入时间比GIN索引慢。 这是因为需要存储除密钥之外的其他信息,并且RUM使用通用WAL记录。

通用的操作符

RUM模块提供以下操作符。

操作符 返回值数据类型 描述
tsvector <=> tsquery float4 返回tsvector与tsquery之间的距离。
timestamp <=> timestamp float8 返回两个时间戳之间的距离。
timestamp <=| timestamp float8 只返回左侧时间戳的距离。
timestamp |=> timestamp float8 只返回右侧时间戳的距离。

说明 后三种操作符也适用于这些数据类型:timestamptz、int2、int4、int8、float4、float8、money、oid。

下文将介绍RUM的各个函数。

rum_tsvector_ops

  • 适用数据类型:tsvector

  • 说明:该函数存储带有位置信息的tsvector词组,支持按<=>运算符排序和前缀搜索。

  • 示例

  • 建立一个表格,命令如下:

    CREATE TABLE test_rum(t text, a tsvector);
    CREATE TRIGGER tsvectorupdate
    BEFORE UPDATE OR INSERT ON test_rum
    FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('a', 'pg_catalog.english', 't');
    INSERT INTO test_rum(t) VALUES ('The situation is most beautiful');
    INSERT INTO test_rum(t) VALUES ('It is a beautiful');
    INSERT INTO test_rum(t) VALUES ('It looks like a beautiful place');
    

创建RUM插件,命令如下:

CREATE EXTENSION rum;

创建新的索引,命令如下:

CREATE INDEX rumidx ON test_rum USING rum (a rum_tsvector_ops);

1.测试执行如下两种查询:

SELECT t, a <=> to_tsquery('english', 'beautiful | place') AS rank
    FROM test_rum
    WHERE a @@ to_tsquery('english', 'beautiful | place')
    ORDER BY a <=> to_tsquery('english', 'beautiful | place');

返回如下输出结果:

                t                |  rank
---------------------------------+---------
 It looks like a beautiful place | 8.22467
 The situation is most beautiful | 16.4493
 It is a beautiful               | 16.4493
(3 rows)
SELECT t, a <=> to_tsquery('english', 'place | situation') AS rank
    FROM test_rum
    WHERE a @@ to_tsquery('english', 'place | situation')
    ORDER BY a <=> to_tsquery('english', 'place | situation');

返回如下输出结果:

                t                |  rank
---------------------------------+---------
 The situation is most beautiful | 16.4493
 It looks like a beautiful place | 16.4493
(2 rows)

rum_tsvector_hash_ops

  • 适用数据类型:tsvector

  • 说明:该函数存储tsvector词组的哈希值和位置信息。支持按<=>运算符排序, 但不支持前缀搜索。

rum_TYPE_ops

  • 适用数据类型:

    • <<==>=><=>操作支持int2、int4、int8、float4、float8、money、oid、time、timetz、date、interval、macaddr、inet、cidr、text、varchar、char、bytea、bit、varbit、numeric、timestamp、timestamptz。

    • <=||=>支持int2、int4、int8、float4、float8、money、oid、timestamp、timestamptz。

  • 说明:该函数可以与rum_tsvector_addon_ops、rum_tsvector_hash_addon_ops和rum_anyarray_addon_ops函数一起使用。

rum_tsvector_addon_ops

  • 适用数据类型:tsvector

  • 说明:该函数存储tsvector词法,以及模块字段支持的任何词法。

  • 示例

    1. 建立一个表格和索引,命令如下:

      CREATE TABLE tsts (id int, t tsvector, d timestamp);
      \copy tsts from 'rum/data/tsts.data'
      CREATE INDEX tsts_idx ON tsts USING rum (t rum_tsvector_addon_ops, d)
          WITH (attach = 'd', to = 't');
      

2.执行如下计划命令

EXPLAIN (costs off)
    SELECT id, d, d <=> '2016-05-16 14:21:25' FROM tsts WHERE t @@ 'wr&qh' ORDER BY d <=> '2016-05-16 14:21:25' LIMIT 5;

返回如下输出结果:

                                   QUERY PLAN
-----------------------------------------------------------------------------------
 Limit
   ->  Index Scan using tsts_idx on tsts
         Index Cond: (t @@ '''wr'' & ''qh'''::tsquery)
         Order By: (d <=> 'Mon May 16 14:21:25 2016'::timestamp without time zone)
(4 rows)

执行如下查询命令:

SELECT id, d, d <=> '2016-05-16 14:21:25' FROM tsts WHERE t @@ 'wr&qh' ORDER BY d <=> '2016-05-16 14:21:25' LIMIT 5;

返回如下输出结果:

 id  |                d                |   ?column?
-----+---------------------------------+---------------
 355 | Mon May 16 14:21:22.326724 2016 |      2.673276
 354 | Mon May 16 13:21:22.326724 2016 |   3602.673276
 371 | Tue May 17 06:21:22.326724 2016 |  57597.326724
 406 | Wed May 18 17:21:22.326724 2016 | 183597.326724
 415 | Thu May 19 02:21:22.326724 2016 | 215997.326724
(5 rows)
    1. 说明 当前RUM在使用按引用传递附加信息进行排序来创建索引时可能有缺陷。这是由于后缀树具有固定长度的右边界和固定长度的无子节点后缀项,所以不允许创建此类索引。

rum_tsvector_hash_addon_ops

  • 适用数据类型:tsvector

  • 说明:该函数存储tsvector词库的哈希值以及任何支持模块的字段,不支持前缀搜索。

rum_tsquery_ops

  • 适用数据类型:tsquery

  • 说明:在其他信息中存储查询树的分支。

  • 示例

    1. 建立一个表格和索引,命令如下:

      CREATE TABLE test_array (i int2[]);
      INSERT INTO test_array VALUES ('{}'), ('{0}'), ('{1,2,3,4}'), ('{1,2,3}'), ('{1,2}'), ('{1}');
      CREATE INDEX idx_array ON test_array USING rum (i rum_anyarray_ops);
      
    2. 执行如下计划命令:

      SET enable_seqscan TO off;
      EXPLAIN (COSTS OFF) SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC;
      

      返回如下输出结果:

                      QUERY PLAN
      ------------------------------------------
       Index Scan using idx_array on test_array
         Index Cond: (i && '{1}'::smallint[])
         Order By: (i <=> '{1}'::smallint[])
      (3 rows)
      

    ​ 3. 执行如下查询命令:

    SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC;
    

    返回如下输出结果:

         i
    ---------
     {1}
     {1,2}
     {1,2,3}
     {1,2,3,4}
    (4 rows)
    

rum_anyarray_ops

  • 适用数据类型:anyarray

  • 说明:该函数存储具有数组长度的anyarrray元素。支持运算符&&@><@=,支持按<=>运算符排序。

  • 示例

    1. 建立一个表格和索引,命令如下:

      CREATE TABLE test_array (i int2[]);
      INSERT INTO test_array VALUES ('{}'), ('{0}'), ('{1,2,3,4}'), ('{1,2,3}'), ('{1,2}'), ('{1}');
      CREATE INDEX idx_array ON test_array USING rum (i rum_anyarray_ops);
      
    2. 执行如下计划命令:

      SET enable_seqscan TO off;
      EXPLAIN (COSTS OFF) SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC;
      

      返回如下输出结果:

                      QUERY PLAN
      ------------------------------------------
       Index Scan using idx_array on test_array
         Index Cond: (i && '{1}'::smallint[])
         Order By: (i <=> '{1}'::smallint[])
      (3 rows)
      
    3. 执行如下查询命令:

      SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC;
      返回如下输出结果:
      
           i
      -----------
       {1}
       {1,2}
       {1,2,3}
       {1,2,3,4}
      (4 rows)
      

      rum_anyarray_addon_ops

      • 适用数据类型:anyarray

      • 说明:该函数存储anyarrray元素以及模块字段支持的任何元素。

SCWS分词

基于SCWS分词的全文索引会用到SCWS和zhparser两个插件。

启用中文分词

可以使用下面的命令,启用中文分词:

--创建zhparser解析器 
CREATE EXTENSION zhparser;
--将zhparser解析器作为全文检索配置项
create text search configuration chinese (PARSER = zhparser); 
--指定分词策略, 通常情况:只需要按照名词(n),动词(v),形容词(a),成语(i),叹词(e)和习用语(l)6种方式对句子进行划分就可以
ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
--可选的参数设定(后面有说明)
alter role all set zhparser.multi_short=on;
--简单测试
SELECT * FROM ts_parse('zhparser', 'hello world! 2010年保障房建设在全国范围内获全面启动,从中央到地方纷纷加大 了 保 障 房 的 建 设 和 投 入 力 度 。2011年,保障房进入了更大规模的建设阶段。住房城乡建设部党组书记、部长姜伟新去年底在全国住房城乡建设工作会议上表示,要继续推进保障性安居工程建设。');
SELECT to_tsvector('chinese','“今年保障房新开工数量虽然有所下调,但实际的年度在建规模以及竣工规模会超以往年份,相对应的对资金的需求也会创历史纪录。”陈国强说。在他看来,与2011年相比,2012年的保障房建设在资金配套上的压力将更为严峻。');
SELECT to_tsquery('chinese', '保障房资金压力');

zhparser可以将中文切分成26中token

unvdb=# select ts_token_type('zhparser');

ts_token_type

(97,a,”adjective,形容词”) (98,b,”differentiation,区别词”) (99,c,”conjunction,连词”) (100,d,”adverb,副词”) (101,e,”exclamation,感叹词”) (102,f,”position,方位词”) (103,g,”root,词根”) (104,h,”head,前连接成分”) (105,i,”idiom,成语”) (106,j,”abbreviation,简称”) (107,k,”tail,后连接成分”) (108,l,”tmp,习用语”) (109,m,”numeral,数词”) (110,n,”noun,名词”) (111,o,”onomatopoeia,拟声词”) (112,p,”prepositional,介词”) (113,q,”quantity,量词”) (114,r,”pronoun,代词”) (115,s,”space,处所词”) (116,t,”time,时语素”) (117,u,”auxiliary,助词”) (118,v,”verb,动词”) (119,w,”punctuation,标点符号”) (120,x,”unknown,未知词”) (121,y,”modal,语气词”) (122,z,”status,状态词”) (26 rows)

unvdb=#

zhparser还有一些特殊的配置项,这些选项是用来控制字典加载行为和分词行为的,这些选项都不是必须的,默认都为false(即如果没有在配置文件中设置这些选项,则zhparser的行为与将下面的选项设置为false一致)。

zhparser.punctuation_ignore = f

zhparser.seg_with_duality = f

zhparser.dict_in_memory = f

zhparser.multi_short = f

zhparser.multi_duality = f

zhparser.multi_zmain = f

zhparser.multi_zall = f

对应的scws介绍, 可参考 http://www.xunsearch.com/scws/docs.php#libscws

利用分词进行全文索引的方法如下:

建表: create table gin_zhparser_test (id integer, title varchar(50),content text, primary key(id), tsv_content tsvector);

插入数据:

insert into gin_zhparser_test values(generate_series(1,100000),'《丑小鸭》', '一只只小鸭子都从蛋壳里钻出来了,就剩下一个特别大的蛋。过了好几天,这个蛋才慢慢裂开,钻出一只又大又丑的鸭子。他的毛灰灰的,嘴巴大大的,身子瘦瘦的,大家都叫他“丑小鸭”。 丑小鸭来到世界上,除了鸭妈妈,谁都欺负他。哥哥、姐姐咬他,公鸡啄他,连养鸭的小姑娘也讨厌他。丑小鸭感到非常孤单,就钻出篱笆,离开了家。 丑小鸭来到树林里,小鸟讥笑他,猎狗追赶他。他白天只好躲起来,到了晚上才敢出来找吃的。 秋天到了,树叶黄了,丑小鸭来到湖边的芦苇里,悄悄地过日子。一天傍晚,一群天鹅从空中飞过。丑小鸭望着洁白美丽的天鹅,又惊奇又羡慕。 天越来越冷,湖面结了厚厚的冰。丑小鸭趴在冰上冻僵了。幸亏一位农夫看见了,把他带回家。 一天,丑小鸭出来散步,看见丁香开花了,知道春天来了。他扑扑翅膀,向湖边飞去,忽然看见镜子似的湖面上,映出一个漂亮的影子,雪白的羽毛,长长的脖子,美丽极了。这难道是自己的影子?啊,原来我不是丑小鸭,是一只漂亮的天鹅呀!') ;
insert into gin_zhparser_test values(100001,'《丑小鸭》','迎接美好生活');

更新全文索引列:

update gin_zhparser_test set tsv_content = to_tsvector('chinese', coalesce(content,''));

创建索引:

Create index idx_gin_test on gin_zhparser_test using gin(tsv_content);

执行查询:

select * from gin_zhparser_test where tsv_content @@ plainto_tsquery('迎接美好生活');

注意:全文索引列也可以不存在表中,如下实例:

--为t1表的name字段创建全文索引,需要将SQL语句中的表名(t1)和字段(name)替换为实际业务中的表名和字段值。
create index idx_t1 on t1 using gin (to_tsvector('chinese',upper(name) ));
--使用全文索引
 select * from t1 where to_tsvector('chinese',upper(t1.name)) @@ to_tsquery('chinese','(防火)') ;

特别提示: 与表达式索引相比,单独列方法的一个优点是,不必为了利用索引而在查询中显式指定文本搜索配置。如上例所示,查询可以依赖于tsv_content。另一个优点是搜索会更快,因为不需要重做to_tsvector验证索引匹配的调用。 然而,表达式索引方法设置起来更简单,而且它需要的磁盘空间更少,因为tsvector表示形式不显式存储。

自定义中文分词词典

自定义中文分词词典,示例如下:

-- 确实的分词结果
SELECT to_tsquery('chinese', '保障房资金压力');
-- 往自定义分词词典里面插入新的分词
insert into pg_ts_custom_word values ('保障房资');
-- 使新的分词生效
select zhprs_sync_dict_xdb();
-- 退出此连接
\c
-- 重新查询,可以得到新的分词结果
SELECT to_tsquery('chinese', '保障房资金压力');

使用自定义分词的注意事项如下:

  • 最多支持一百万条自定义分词,超出部分不做处理,必须保证分词数量在这个范围之内。自定义分词与缺省的分词词典将共同产生作用。

  • 每个词的最大长度为128字节,超出部分将会截取。

  • 增删改分词之后必须执行select zhprs_sync_dict_xdb();并且重新建立连接才会生效。

pg_jieba分词

使用方法

–创建jieba解析器

CREATE EXTENSION pg_jieba;

–使用示例1:

SELECT * FROM to_tsvector('jiebacfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造');
                                                 to_tsvector
--------------------------------------------------------------------------------------------------------------
 '中国科学院':5 '于':4 '后':8 '在':9 '小明':1 '日本京都大学':10 '毕业':3 '深造':11 '硕士':2 '计算所':6 ',':7
(1 row)

使用示例2:

SELECT * FROM to_tsvector('jiebacfg', '李小福是创新办主任也是云计算方面的专家');
                                        to_tsvector
-------------------------------------------------------------------------------------------
 '专家':11 '主任':5 '也':6 '云计算':8 '创新':3 '办':4 '方面':9 '是':2,7 '李小福':1 '的':10
(1 row)

jieba自带的全文检索配置项

  • jiebamp: Use mp

  • jiebahmm: Use hmm

  • jiebacfg: Combine MP&HMM(Mix). 适用于大多数场景 (推荐使用)

  • jiebaqry: First use Mix, then use full. Similar to the one used by web search engines.

Config Statment Result
jiebamp 我来到北京清华大学 ‘来到’ & ‘北京’ & ‘清华大学’
jiebamp 他来到了网易杭研大厦 ‘来到’ & ‘网易’ & ‘杭’ & ‘研’ & ‘大厦’
jiebamp 小明硕士毕业于中国科学院计算所,后在日本京都大学深造 ‘明’ & ‘硕士’ & ‘毕业’ & ‘中国科学院’ & ‘计算所’ & ‘日本京都大学’ & ‘深造’
Config Statment Result
jiebahmm 我来到北京清华大学 ‘我来’ & ‘北京’ & ‘清华大学’
jiebahmm 他来到了网易杭研大厦 ‘他来’ & ‘网易’ & ‘杭’ & ‘研大厦’
jiebahmm 小明硕士毕业于中国科学院计算所,后在日本京都大学深造 ‘小明’ & ‘硕士’ & ‘毕业于’ & ‘中国’ & ‘科学院’ & ‘计算’ & ‘日’ & ‘本京’ & ‘大学’ & ‘深造’
Config Statment Result
jiebacfg 我来到北京清华大学 ‘来到’ & ‘北京’ & ‘清华大学’
jiebacfg 他来到了网易杭研大厦 ‘来到’ & ‘网易’ & ‘杭研’ & ‘大厦’
jiebacfg 小明硕士毕业于中国科学院计算所,后在日本京都大学深造 ‘小明’ & ‘硕士’ & ‘毕业’ & ‘中国科学院’ & ‘计算所’ & ‘日本京都大学’ & ‘深造’
Config Statment Result
jiebaqry 我来到北京清华大学 ‘来到’ & ‘北京’ & ‘清华’ & ‘华大’ & ‘大学’ & ‘清华大学’
jiebaqry 他来到了网易杭研大厦 ‘来到’ & ‘网易’ & ‘杭研’ & ‘大厦’
jiebaqry 小明硕士毕业于中国科学院计算所,后在日本京都大学深造 ‘小明’ & ‘硕士’ & ‘毕业’ & ‘中国’ & ‘科学’ & ‘学院’ & ‘科学院’ & ‘中国科学院’ & ‘计算’ & ‘计算所’ & ‘日本’ & ‘京都’ & ‘大学’ & ‘日本京都大学’ & ‘深造’

扩展功能

  • pg_jieba支持配置多个自定义词库并切换。

    -- 0号词典插入数据(默认0号词典,权重10)
    INSERT INTO jieba_user_dict VALUES ('国有云');
    INSERT INTO jieba_user_dict values ('研发工程师',0,10);
    -- 使用jieba自带词库分词
    SELECT * FROM to_tsvector('jiebacfg', 'whe是国有云的一个研发工程师');
    to_tsvector
    ------------------------------------------------------
    'whe':1 '一个':6 '云':4 '工程师':8 '研发':7 '国有':3
    (1 row)
    -- 切换自定义词典到0号
    SELECT jieba_load_user_dict(0);
    jieba_load_user_dict
    ----------------------
    (1 row)
    SELECT * FROM to_tsvector('jiebacfg', 'whe是国有云的一个研发工程师');
    to_tsvector
    --------------------------------------------
    'whe':1 '一个':5 '研发工程师':6 '国有云':3
    (1 row)
    

支持按照偏移量显示分词结果。

SELECT * FROM to_tsvector('jiebacfg_pos', 'whe是国有云的一个研发工程师');
                                     to_tsvector
--------------------------------------------------------------------------------------
 'whe:0':1 '一个:8':6 '云:6':4 '工程师:12':8 '是:3':2 '的:7':5 '研发:10':7 '国有:4':3
(1 row)

pg_bigm二元分词

–创建pg_bigm解析器

CREATE EXTENSION pg_bigm;
-- 删除pg_bigm解析器, 使用CASCADE选项执行,以删除所有依赖于pg_bigm的数据库对象,例如pg_bigm全文搜索索引。 
DROP EXTENSION pg_bigm CASCADE;

全文搜索示例

创建索引

可以使用GIN index为全文搜索创建索引。

下列范例会建立表pg_tools它存储相关工具的名称和描述,向表中插入四条记录,然后在描述专栏。

=# CREATE TABLE pg_tools (tool text, description text);
=# INSERT INTO pg_tools VALUES ('pg_hint_plan', 'Tool that allows a user to specify an optimizer HINT to UDB');
=# INSERT INTO pg_tools VALUES ('pg_dbms_stats', 'Tool that allows a user to stabilize planner statistics in UDB');
=# INSERT INTO pg_tools VALUES ('pg_bigm', 'Tool that provides 2-gram full text search capability in UDB');
=# INSERT INTO pg_tools VALUES ('pg_trgm', 'Tool that provides 3-gram full text search capability in UDB');
=# CREATE INDEX pg_tools_idx ON pg_tools USING gin (description gin_bigm_ops);
  • gin必须用作索引方法。GiST不适用于pg_bigm。

  • gin_bigm_ops必须用作运算符类。

还可以创建多列pg_bigm索引,然后指定与GIN相关的参数,如下所示。

=# CREATE INDEX pg_tools_multi_idx ON pg_tools USING gin (tool gin_bigm_ops, description gin_bigm_ops) WITH (FASTUPDATE = off);

执行全文搜索

可以使用LIKE模式匹配来执行全文搜索。

=# SELECT * FROM pg_tools WHERE description LIKE '%search%';
  tool   |                             description                             
---------+---------------------------------------------------------------------
 pg_bigm | Tool that provides 2-gram full text search capability in UDB
 pg_trgm | Tool that provides 3-gram full text search capability in UDB
(2 rows)
  • 搜索关键字必须指定为LIKE运算符可以正确处理的模式字符串。

执行相似性搜索

您可以使用=%运算符来执行相似性搜索。

以下查询返回tool列中与单词“bigm”足够相似的所有值。这种相似性搜索基本上很快,因为它可以使用全文搜索索引。它通过查看两个字符串的相似性是否高于或等于的值来衡量两个字符串是否足够相似pg_bigm.similarity_limit。这意味着,在这个查询中,与单词’ bigm ‘相似度高于或等于0.2的值在工具列中只有’ pg_bigm ‘和’ pg_trgm ‘。

=# SET pg_bigm.similarity_limit TO 0.2;
=# SELECT tool FROM pg_tools WHERE tool =% 'bigm';
  tool   
---------
 pg_bigm
 pg_trgm
(2 rows)

请看bigm _相似性函数了解如何计算相似性的详细信息。

可用的函数

likequery

likequery是一个将搜索关键字(参数#1)转换成LIKE操作符可以正确处理的模式字符串的函数。

  • 参数#1(文本)-搜索关键字

  • 返回值(文本)-从参数#1转换而来的模式字符串,以便LIKE操作符可以正确处理

如果参数#1为空,返回值也为空。

该函数执行如下转换:

  • 将%附加到搜索关键字的开头和结尾。

  • 使用\对搜索关键字中的字符%、_和\进行转义。

在pg_bigm中,通过使用LIKE模式匹配来执行全文搜索。因此,需要将搜索关键字转换成LIKE操作符可以正确处理的模式字符串。通常,客户端应用程序应该负责这种转换。但是,通过使用likequery函数,可以节省在应用程序中实现这种转换逻辑的工作量。

=# SELECT likequery('pg_bigm has improved the full text search performance by 200%');
                             likequery                             
-------------------------------------------------------------------
 %pg\_bigm has improved the full text search performance by 200\%%
(1 row)

使用likequery,您可以将“执行全文搜索”示例中使用的全文搜索查询重写为:

=# SELECT * FROM pg_tools WHERE description LIKE likequery('search');
  tool   |                             description                             
---------+---------------------------------------------------------------------
 pg_bigm | Tool that provides 2-gram full text search capability in UDB
 pg_trgm | Tool that provides 3-gram full text search capability in UDB
(2 rows)

show_bigm

show_bigm返回给定字符串中所有2-grams的数组(参数#1)。

  • 参数#1(文本)-字符串

  • 返回值(text[]) -参数#1中所有2-grams的数组

show_bigm返回的2-gram是从一个字符串中提取的一组两个连续的字符,空白字符被附加到开头和结尾。例如,字符串“ABC”的两个字母是“(空白)A”“AB”“BC”“C(空白)”。

=# SELECT show_bigm('full text search');
                            show_bigm                             
------------------------------------------------------------------
 {" f"," s"," t",ar,ch,ea,ex,fu,"h ","l ",ll,rc,se,"t ",te,ul,xt}
(1 row)

bigm_similarity

bigm_similarity返回一个数字,表示两个字符串(参数#1和#2)的相似程度。

  • 参数#1(文本)-字符串

  • 参数#2(文本)-字符串

  • 返回值(实数)-两个参数的相似性

这个函数通过计算两个字符串共享的2-grams的数量来度量它们的相似性。相似性的范围从0(表示两个字符串完全不同)到1(表示两个字符串相同)。

=# SELECT bigm_similarity('full text search', 'text similarity search');
 bigm_similarity 
-----------------
        0.571429
(1 row)

注意,当确定包含在用于计算相似性的字符串中的2-grams的集合时,每个参数被认为具有一个空格前缀和后缀。例如,尽管字符串“ABC”包含字符串“B ”,但它们的相似度为0,因为它们没有如下共享的2-grams。另一方面,字符串“ABC”和“A”如下共享一个2-gram“(空白)A”,因此它们的相似度高于0。这和pg_trgm的相似度函数的行为基本相同。

  • 字符串“ABC”的两个字母是“(空白)A”“AB”“BC”“C(空白)”。

  • 字符串“A”的两个字母是“(空白)A”“A(空白)”。

  • 字符串“B”的两个字母是“(空白)B”“B(空白)”。

=# SELECT bigm_similarity('ABC', 'A');
 bigm_similarity 
-----------------
            0.25
(1 row)
=# SELECT bigm_similarity('ABC', 'B');
 bigm_similarity 
-----------------
               0
(1 row)

注意bigm_similarity是不区分大小写的,但是pg_trgm的相似度函数是区分大小写的。例如,字符串“abc”和“ABC”的相似度在pg_trgm的相似度函数中是1,但在bigm_similarity中是0。

=# SELECT similarity('ABC', 'abc');
 similarity 
------------
          1
(1 row)
=# SELECT bigm_similarity('ABC', 'abc');
 bigm_similarity 
-----------------
               0
(1 row)

pg_gin_pending_stats

pg_gin_pending_stats是一个函数,它返回gin索引的挂起列表中的页数和元组数(参数#1)。

  • 参数# 1(regclass)-GIN索引的名称或OID

  • 返回值#1(整数)-待定列表中的页数

  • 返回值#2 (bigint) -待定列表中元组的数量

请注意,如果参数#1是在禁用FASTUPDATE选项的情况下构建的GIN索引,则返回值#1和#2为0,因为它没有待定列表。

=# SELECT * FROM pg_gin_pending_stats('pg_tools_idx');
 pages | tuples
-------+--------
     1 |      4
(1 row)

限制

索引列大小

bigm GIN索引所索引的列的大小不能超过107,374,180字节(~102MB)。任何输入更大值的尝试都会导致错误。

=# CREATE TABLE t1 (description text);
=# CREATE INDEX t1_idx ON t1 USING gin (description gin_bigm_ops);
=# INSERT INTO t1 SELECT repeat('A', 107374181);
ERROR:  out of memory

pg_trgm也有这个限制。但是,trgm索引列的最大大小是238,609,291字节(~228MB)。

文本搜索类型

UDB-TX系统提供了两种旨在支持全文搜索的数据类型。tsvector类型表示以文本搜索优化的形式的文档;tsquery类型类似地表示搜索的文本。

tsvector

tsvector的值是不同词素的排序列表。输入过程中会自动进行排序和消除重复,如下例所示:

SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector;
                      tsvector
----------------------------------------------------
 'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat'

要表示包含空格或标点的词位,请用引号将它们括起来:

SELECT $$the lexeme '    ' contains spaces$$::tsvector;
                 tsvector                  
-------------------------------------------
 '    ' 'contains' 'lexeme' 'spaces' 'the'

(在这个例子和下一个例子中,我们使用带引号的字符串文字,以避免在文字中使用双引号造成的混乱。)嵌入的引号和反斜杠必须成对出现:

SELECT $$the lexeme 'Joe''s' contains a quote$$::tsvector;
                    tsvector                    
------------------------------------------------
 'Joe''s' 'a' 'contains' 'lexeme' 'quote' 'the'

选的,整数位置可以附加到词素上:

SELECT 'a:1 fat:2 cat:3 sat:4 on:5 a:6 mat:7 and:8 ate:9 a:10 fat:11 rat:12'::tsvector;
                                  tsvector
-------------------------------------------------------------------------------
 'a':1,6,10 'and':8 'ate':9 'cat':3 'fat':2,11 'mat':7 'on':5 'rat':12 'sat':4

位置通常表示源单词在文档中的位置。位置信息可用于邻近排序。位置值的范围从1到16383;更大的数字被默认设置为16383。相同词素的重复位置被丢弃。

有位置的词素可以进一步用权重来标识,可以是A, B, C,或者D. D是默认值,因此不会显示在输出中:

SELECT 'a:1A fat:2B,4C cat:5D'::tsvector;
          tsvector          
----------------------------
 'a':1A 'cat':5 'fat':2B,4C

权重通常用于反映文档结构。文本搜索排序功能可以为不同的权重标记分配不同的优先级。

重要的是要理解tsvector类型本身不执行任何词素的规范化;它假设给出的词素对于应用程序是正确规范化的。原始文档文本通常应该被传递to_tsvector去做词素规范化以适合搜索:

SELECT to_tsvector('english', 'The Fat Rats');
   to_tsvector   
-----------------
 'fat':2 'rat':3

tsquery

tsquery值用于存储要搜索的词素,并可以使用布尔运算符组合它们&(与),|(或),以及!(不是),以及词组搜索运算符<->。还有一种变体<*N*>后跟运算符的,其中*N*是一个整数常量,指定要搜索的两个词位之间的距离。<->相当于<1>.

圆括号可以用来加强这些操作符的分组。如果没有括号,!(NOT)优先,<->次之,然后&(与),|(或)。

以下是一些例子:

SELECT 'fat & rat'::tsquery;
    tsquery    
---------------
 'fat' & 'rat'
SELECT 'fat & (rat | cat)'::tsquery;
          tsquery          
---------------------------
 'fat' & ( 'rat' | 'cat' )
SELECT 'fat & rat & ! cat'::tsquery;
        tsquery         
------------------------
 'fat' & 'rat' & !'cat'

文本搜索函数和运算符

文本搜索的运算符

Operator Description Example(s)
tsvector @@ tsqueryboolean``tsquery @@ tsvectorbooleanDoes tsvector match tsquery? (The arguments can be given in either order.)to_tsvector('fat cats ate rats') @@ to_tsquery('cat & rat')t
text @@ tsquerybooleanDoes text string, after implicit invocation of to_tsvector(), match tsquery?'fat cats ate rats' @@ to_tsquery('cat & rat')t
tsvector @@@ tsqueryboolean``tsquery @@@ tsvectorbooleanThis is a deprecated synonym for @@.to_tsvector('fat cats ate rats') @@@ to_tsquery('cat & rat')t
tsvector `
tsquery && tsquerytsqueryANDs two tsquerys together, producing a query that matches documents that match both input queries.`’fat
tsquery `
!! tsquerytsqueryNegates a tsquery, producing a query that matches documents that do not match the input query.!! 'cat'::tsquery!'cat'
tsquery <-> tsquerytsqueryConstructs a phrase query, which matches if the two input queries match at successive lexemes.to_tsquery('fat') <-> to_tsquery('rat')'fat' <-> 'rat'
tsquery @> tsquerybooleanDoes first tsquery contain the second? (This considers only whether all the lexemes appearing in one query appear in the other, ignoring the combining operators.)'cat'::tsquery @> 'cat & rat'::tsqueryf
tsquery <@ tsquerybooleanIs first tsquery contained in the second? (This considers only whether all the lexemes appearing in one query appear in the other, ignoring the combining operators.)'cat'::tsquery <@ 'cat & rat'::tsqueryt``'cat'::tsquery <@ '!cat & rat'::tsqueryt

文本搜索函数

Function Description Example(s)
array_to_tsvector ( text[] ) → tsvectorConverts an array of lexemes to a tsvector. The given strings are used as-is without further processing.array_to_tsvector('{fat,cat,rat}'::text[])'cat' 'fat' 'rat'
get_current_ts_config ( ) → regconfigReturns the OID of the current default text search configuration (as set by default_text_search_config).get_current_ts_config()english
length ( tsvector ) → integerReturns the number of lexemes in the tsvector.length('fat:2,4 cat:3 rat:5A'::tsvector)3
numnode ( tsquery ) → integerReturns the number of lexemes plus operators in the tsquery.`numnode(‘(fat & rat)
plainto_tsquery ( [ config regconfig, ] query text ) → tsqueryConverts text to a tsquery, normalizing words according to the specified or default configuration. Any punctuation in the string is ignored (it does not determine query operators). The resulting query matches documents containing all non-stopwords in the text.plainto_tsquery('english', 'The Fat Rats')'fat' & 'rat'
phraseto_tsquery ( [ config regconfig, ] query text ) → tsqueryConverts text to a tsquery, normalizing words according to the specified or default configuration. Any punctuation in the string is ignored (it does not determine query operators). The resulting query matches phrases containing all non-stopwords in the text.phraseto_tsquery('english', 'The Fat Rats')'fat' <-> 'rat'``phraseto_tsquery('english', 'The Cat and Rats')'cat' <2> 'rat'
websearch_to_tsquery ( [ config regconfig, ] query text ) → tsqueryConverts text to a tsquery, normalizing words according to the specified or default configuration. Quoted word sequences are converted to phrase tests. The word “or” is understood as producing an OR operator, and a dash produces a NOT operator; other punctuation is ignored. This approximates the behavior of some common web search tools.websearch_to_tsquery('english', '"fat rat" or cat dog') → `’fat’ <-> ‘rat’
querytree ( tsquery ) → textProduces a representation of the indexable portion of a tsquery. A result that is empty or just T indicates a non-indexable query.querytree('foo & ! bar'::tsquery)'foo'
setweight ( vector tsvector, weight "char" ) → tsvectorAssigns the specified weight to each element of the vector.setweight('fat:2,4 cat:3 rat:5B'::tsvector, 'A')'cat':3A 'fat':2A,4A 'rat':5A
setweight ( vector tsvector, weight "char", lexemes text[] ) → tsvectorAssigns the specified weight to elements of the vector that are listed in lexemes.setweight('fat:2,4 cat:3 rat:5,6B'::tsvector, 'A', '{cat,rat}')'cat':3A 'fat':2,4 'rat':5A,6A
strip ( tsvector ) → tsvectorRemoves positions and weights from the tsvector.strip('fat:2,4 cat:3 rat:5A'::tsvector)'cat' 'fat' 'rat'
to_tsquery ( [ config regconfig, ] query text ) → tsqueryConverts text to a tsquery, normalizing words according to the specified or default configuration. The words must be combined by valid tsquery operators.to_tsquery('english', 'The & Fat & Rats')'fat' & 'rat'
to_tsvector ( [ config regconfig, ] document text ) → tsvectorConverts text to a tsvector, normalizing words according to the specified or default configuration. Position information is included in the result.to_tsvector('english', 'The Fat Rats')'fat':2 'rat':3
to_tsvector ( [ config regconfig, ] document json ) → tsvector``to_tsvector ( [ config regconfig, ] document jsonb ) → tsvectorConverts each string value in the JSON document to a tsvector, normalizing words according to the specified or default configuration. The results are then concatenated in document order to produce the output. Position information is generated as though one stopword exists between each pair of string values. (Beware that “document order” of the fields of a JSON object is implementation-dependent when the input is jsonb; observe the difference in the examples.)to_tsvector('english', '{"aa": "The Fat Rats", "b": "dog"}'::json)'dog':5 'fat':2 'rat':3``to_tsvector('english', '{"aa": "The Fat Rats", "b": "dog"}'::jsonb)'dog':1 'fat':4 'rat':5
json_to_tsvector ( [ config regconfig, ] document json, filter jsonb ) → tsvector``jsonb_to_tsvector ( [ config regconfig, ] document jsonb, filter jsonb ) → tsvectorSelects each item in the JSON document that is requested by the filter and converts each one to a tsvector, normalizing words according to the specified or default configuration. The results are then concatenated in document order to produce the output. Position information is generated as though one stopword exists between each pair of selected items. (Beware that “document order” of the fields of a JSON object is implementation-dependent when the input is jsonb.) The filter must be a jsonb array containing zero or more of these keywords: "string" (to include all string values), "numeric" (to include all numeric values), "boolean" (to include all boolean values), "key" (to include all keys), or "all" (to include all the above). As a special case, the filter can also be a simple JSON value that is one of these keywords.json_to_tsvector('english', '{"a": "The Fat Rats", "b": 123}'::json, '["string", "numeric"]')'123':5 'fat':2 'rat':3``json_to_tsvector('english', '{"cat": "The Fat Rats", "dog": 123}'::json, '"all"')'123':9 'cat':1 'dog':7 'fat':4 'rat':5
ts_delete ( vector tsvector, lexeme text ) → tsvectorRemoves any occurrence of the given lexeme from the vector.ts_delete('fat:2,4 cat:3 rat:5A'::tsvector, 'fat')'cat':3 'rat':5A
ts_delete ( vector tsvector, lexemes text[] ) → tsvectorRemoves any occurrences of the lexemes in lexemes from the vector.ts_delete('fat:2,4 cat:3 rat:5A'::tsvector, ARRAY['fat','rat'])'cat':3
ts_filter ( vector tsvector, weights "char"[] ) → tsvectorSelects only elements with the given weights from the vector.ts_filter('fat:2,4 cat:3b,7c rat:5A'::tsvector, '{a,b}')'cat':3B 'rat':5A
ts_headline ( [ config regconfig, ] document text, query tsquery [, options text ] ) → textDisplays, in an abbreviated form, the match(es) for the query in the document, which must be raw text not a tsvector. Words in the document are normalized according to the specified or default configuration before matching to the query.
ts_headline ( [ config regconfig, ] document json, query tsquery [, options text ] ) → text``ts_headline ( [ config regconfig, ] document jsonb, query tsquery [, options text ] ) → textDisplays, in an abbreviated form, match(es) for the query that occur in string values within the JSON document.
ts_rank ( [ weights real[], ] vector tsvector, query tsquery [, normalization integer ] ) → realComputes a score showing how well the vector matches the query.
ts_rank_cd ( [ weights real[], ] vector tsvector, query tsquery [, normalization integer ] ) → realComputes a score showing how well the vector matches the query, using a cover density algorithm. ts_rank_cd(to_tsvector('raining cats and dogs'), 'cat')0.1
ts_rewrite ( query tsquery, target tsquery, substitute tsquery ) → tsqueryReplaces occurrences of target with substitute within the query. `ts_rewrite(‘a & b’::tsquery, ‘a’::tsquery, ‘foo
ts_rewrite ( query tsquery, select text ) → tsqueryReplaces portions of the query according to target(s) and substitute(s) obtained by executing a SELECT command. SELECT ts_rewrite('a & b'::tsquery, 'SELECT t,s FROM aliases') → `’b’ & ( ‘foo’
tsquery_phrase ( query1 tsquery, query2 tsquery ) → tsqueryConstructs a phrase query that searches for matches of query1 and query2 at successive lexemes (same as <-> operator).tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'))'fat' <-> 'cat'
tsquery_phrase ( query1 tsquery, query2 tsquery, distance integer ) → tsqueryConstructs a phrase query that searches for matches of query1 and query2 that occur exactly distance lexemes apart.tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'), 10)'fat' <10> 'cat'
tsvector_to_array ( tsvector ) → text[]Converts a tsvector to an array of lexemes.tsvector_to_array('fat:2,4 cat:3 rat:5A'::tsvector){cat,fat,rat}
unnest ( tsvector ) → setof record ( lexeme text, positions smallint[], weights text )Expands a tsvector into a set of rows, one per lexeme.select * from unnest('cat:3 fat:2,4 rat:5A'::tsvector) →` lexeme

文本搜索调试函数

Function Description Example(s)
ts_debug ( [ config regconfig, ] document text ) → setof record ( alias text, description text, token text, dictionaries regdictionary[], dictionary regdictionary, lexemes text[] )Extracts and normalizes tokens from the document according to the specified or default text search configuration, and returns information about how each token was processed. ts_debug('english', 'The Brightest supernovaes')(asciiword,"Word, all ASCII",The,{english_stem},english_stem,{}) ...
ts_lexize ( dict regdictionary, token text ) → text[]Returns an array of replacement lexemes if the input token is known to the dictionary, or an empty array if the token is known to the dictionary but it is a stop word, or NULL if it is not a known word. ts_lexize('english_stem', 'stars'){star}
ts_parse ( parser_name text, document text ) → setof record ( tokid integer, token text )Extracts tokens from the document using the named parser. ts_parse('default', 'foo - bar')(1,foo) ...
ts_parse ( parser_oid oid, document text ) → setof record ( tokid integer, token text )Extracts tokens from the document using a parser specified by OID. ts_parse(3722, 'foo - bar')(1,foo) ...
ts_token_type ( parser_name text ) → setof record ( tokid integer, alias text, description text )Returns a table that describes each type of token the named parser can recognize. ts_token_type('default')(1,asciiword,"Word, all ASCII") ...
ts_token_type ( parser_oid oid ) → setof record ( tokid integer, alias text, description text )Returns a table that describes each type of token a parser specified by OID can recognize. ts_token_type(3722)(1,asciiword,"Word, all ASCII") ...
ts_stat ( sqlquery text [, weights text ] ) → setof record ( word text, ndoc integer, nentry integer )Executes the sqlquery, which must return a single tsvector column, and returns statistics about each distinct lexeme contained in the data. ts_stat('SELECT vector FROM apod')(foo,10,15) ...