09月29, 2019

postgresql 中文全文索引安装与使用

postgresql默认安装的分词插件没有中文分词功能,会将单个字拆开, 这对于检索性能有影响。

使用中文分词插件后,可以将中文语分开,创建倒排索引时更有效率。

安装zhparser插件

CREATE EXTENSION zhparser;
CREATE TEXT SEARCH CONFIGURATION zhparser (PARSER = zhparser); 
-- 设置分词规则
ALTER TEXT SEARCH CONFIGURATION zhparser ADD MAPPING FOR n,v,a,i,e,l,j WITH simple; 
-- 给某一列的分词结果添加 gin 索引

create index idx_gin_content_20181h on weibo_posts_21081h using gin(to_tsvector('zhparser', content));

create index idx_gin_content_20182h on weibo_posts_21082h using gin(to_tsvector('zhparser', content));

create index idx_gin_content on weibo_posts_21091h using gin(to_tsvector('zhparser', content));


SELECT * FROM weibo_posts_21091h WHERE to_tsvector('zhparser', content) @@ '优惠'

全文检索语法

文档(tsvector)类型

对于tsvector类型,表示一个检索单元,通常是一个数据库表中一行的文本字段,或者这些字段的可能组合(级联),也可能存储在多个表中或者动态地获得,它的值是一个无重复值的lexemes排序列表,即一些同一个词的不同变种的标准化,在输入的同时会自动排序和消除重复。to_tsvector函数通常用于解析和标准化文档字符串。

查询(tsquery)类型

对于tsquery类型,表示一个检索条件,存储用于检索的词汇,并且使用布尔操作符&(AND),|(OR)和!(NOT) 来组合它们,括号用来强调操作符的分组。与tsvector一样,任何单词必须在转换为tsquery类型前规范化。to_tsquery函数及plainto_tsquery函数可以方便的用来执行规范化。

SELECT 'fat & rat'::tsquery;

 tsquery   

---------------

 'fat' & 'rat'



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

    tsquery         

---------------------------

 'fat' & ( 'rat' | 'cat' )



SELECT to_tsquery('english', 'fat & rat'); 

  to_tsquery  

---------------

 'fat' & 'rat'

检索表

查询引擎的全文检索基于匹配算子@@,如果一个tsvector与一个tsquery匹配,则返回true。在不使用索引的情况下也是可以进行全文检索的,一个简单查询,显示出title从所有body字段中包含friend的每一行:

SELECT title

FROM web

WHERE to_tsvector('english', body) @@ to_tsquery('english','friend');

其中to_tsvector和to_tsquery中第一个参数用于指定全文检索的分词语言设置,一般可省略

中文查询语法如下:

SELECT content FROM weibo_posts
WHERE to_tsvector('zhparser', content) @@ to_tsquery('zhparser','阿道夫&洗发水&止痒');

zhparser可以将中文切分成下面26种token

testdb=# select ts_token_type('zhparser');
              ts_token_type
-----------------------------------------
 (97,a,adjective)
 (98,b,"differentiation (qu bie)")
 (99,c,conjunction)
 (100,d,adverb)
 (101,e,exclamation)
 (102,f,"position (fang wei)")
 (103,g,"root (ci gen)")
 (104,h,head)
 (105,i,idiom)
 (106,j,"abbreviation (jian lue)")
 (107,k,head)
 (108,l,"tmp (lin shi)")
 (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 (qi ta biao dian)")
 (120,x,unknown)
 (121,y,"modal (yu qi)")
 (122,z,"status (zhuang tai)")
(26 rows)

添加自定义词典

我们可以在网上下载 xdb 格式的词库来替代默认词典,词库放在 share/tsearch_data/ 文件夹下才能被 PgSQL 读取到,默认使用的词库是 dict.utf8.xdb。要使用自定义词库,可以将词库放在词库文件夹后,在 postgresql.conf 配置 zhparser.extra_dict="mydict.xdb" 参数;

当我们只有 txt 的词库,想把这个词库作为默认词库该怎么办呢?使用 scws 带的scwe-gen-dict 工具或网上找的脚本生成 xdb 后放入词库文件夹后,在 PgSQL 中分词一直报错,读取词库文件失败。我经过多次实验,总结出了一套制作一个词典文件的方法:

准备词库源文件 mydict.txt:词库文件的内容每一行的格式为词 TF IDF 词性,词是必须的,而 TF 词频(Term Frequency)、IDF 反文档频率(Inverse Document Frequency) 和 词性 都是可选的,除非确定自己的词典资料是对的且符合 scws 的配置,不然最好还是留空,让 scws 自已确定; 在 postgresql.conf 中设置 zhparser.extra_dicts = "mydict.txt" 同时设置 zhparser.dict_in_memory = true; 命令行进入 PgSQL,执行一条分词语句 select to_tsquery('parser', '随便一个词') ,分词会极慢,请耐心(请保证此时只有一个分词语句在执行); 分词成功后,在/tmp/目录下找到生成的 scws-xxxx.xdb 替换掉 share/tsearch_data/dict.utf8.xdb; 删除刚加入的 extra_dicts dict_in_memory 配置,重启服务器。

自定义词库

详解 TXT 词库的写法 (TXT词库目前已兼容 cli/scws_gen_dict 所用的文本词库)

每行一条记录,以 # 或 分号开头的相当于注释,忽略跳过

每行由4个字段组成,依次为“词语"(由中文字或3个以下的字母合成), "TF", "IDF", "词性",字段使用空格或制表符分开,数量不限,可自行对齐以美化

除“词语”外,其它字段可忽略不写。若忽略,TF和IDF默认值为 1.0 而 词性为 "@"

由于 TXT 库动态加载(内部监测文件修改时间自动转换成 xdb 存于系统临时目录),故建议TXT词库不要过大

删除词做法,请将词性设为“!“,则表示该词设为无效,即使在其它核心库中存在该词也视为无效

注意:1.自定义词典的格式可以是文本TXT,也可以是二进制的XDB格式。XDB格式效率更高,适合大辞典使用。可以使用scws自带的工具scws-gen-dict将文本词典转换为XDB格式;2.zhparser默认的词典是简体中文,如果需要繁体中文,可以在这里下载已经生成好的XDB格式此词典。3.自定义词典的例子可以参考dict_extra.txt。更多信息参见SCWS官方文档。

自定义词库 2.1

自定义词库2.1 增加自定义词库的易容性, 并兼容1.0提供的功能

自定义词库需要superuser权限, 自定义库是数据库级别的(不是实例),每个数据库拥有自己的自定义分词, 并存储在data目录下base/数据库ID下(2.0 版本存储在share/tsearch_data下)

生成环境版本升级(新环境直接安装就可以): alter extension zhparser update ;

test=# SELECT * FROM ts_parse('zhparser', '保障房资金压力');
 tokid | token
-------+-------
   118 | 保障
   110 | 房
   110 | 资金
   110 | 压力

test=# insert into zhparser.zhprs_custom_word values('资金压力');
--删除词insert into zhprs_custom_word(word, attr) values('word', '!');
--\d zhprs_custom_word 查看其表结构,支持TD, IDF
test=# select sync_zhprs_custom_word();
 sync_zhprs_custom_word
------------------------

(1 row)

test=# \q --sync 后重新建立连接
[lzzhang@lzzhang-pc bin]$ ./psql -U lzzhang -d test -p 1600
test=# SELECT * FROM ts_parse('zhparser', '保障房资金压力');
 tokid |  token
-------+----------
   118 | 保障
   110 | 房
   120 | 资金压力

参考

本文链接:http://57km.cc/post/postgresql full index for chinese.html

-- EOF --

Comments