暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用阿里云PostgreSQL zhparser中文分词时不可不知的几个参数

digoal 2016-03-10
722

作者

digoal

日期

2016-03-10

标签

PostgreSQL , 有且只有一条记录


背景

阿里云RDS PgSQL已支持zhparser中文分词插件,用法举例:

```
create extension zhparser;

select * from pg_ts_parser ;
prsname | prsnamespace | prsstart | prstoken | prsend | prsheadline | prslextype
----------+--------------+-------------+-----------------+-----------+---------------+---------------
default | 11 | prsd_start | prsd_nexttoken | prsd_end | prsd_headline | prsd_lextype
zhparser | 25956 | zhprs_start | zhprs_getlexeme | zhprs_end | prsd_headline | zhprs_lextype
(2 rows)

CREATE TEXT SEARCH CONFIGURATION testzhcfg (PARSER = zhparser);

digoal=# select * from pg_ts_config where cfgname='testzhcfg';
cfgname | cfgnamespace | cfgowner | cfgparser
-----------+--------------+----------+-----------
testzhcfg | 25956 | 10 | 26134
(1 row)

ALTER TEXT SEARCH CONFIGURATION testzhcfg ADD MAPPING FOR n,v,a,i,e,l WITH simple;

digoal=# select * from pg_ts_config_map where mapcfg=(select oid from pg_ts_config where cfgname='testzhcfg');
mapcfg | maptokentype | mapseqno | mapdict
--------+--------------+----------+---------
26135 | 97 | 1 | 3765
26135 | 101 | 1 | 3765
26135 | 105 | 1 | 3765
26135 | 108 | 1 | 3765
26135 | 110 | 1 | 3765
26135 | 118 | 1 | 3765
(6 rows)

SELECT * FROM ts_parse('zhparser', 'hello world! 2010年保障房建设在全国范围内获全面启动,从中央到地方纷纷加大 了 保 障 房 的 建 设
和 投 入 力 度 。2011年,保障房进入了更大规模的建设阶段。住房城乡建设部党组书记、部长姜伟新去年底在全国住房城乡建设工作会议上表示,
要继续推进保障性安居工程建设。');

SELECT to_tsvector('testzhcfg','“今年保障房新开工数量虽然有所下调,但实际的年度在建规模以及竣工规模会超以往年份,相对应的对资金的需
求也会创历史纪录。”陈国强说。在他看来,与2011年相比,2012年的保障房建设在资金配套上的压力将更为严峻。');

SELECT to_tsquery('testzhcfg', '保障房资金压力');
to_tsquery


'保障' & '房' & '资金' & '压力'
(1 row)
```

zhparser还有一些特殊的配置项,以下配置在PG9.2及以上版本使用,这些选项是用来控制字典加载行为和分词行为的,这些选项都不是必须的,默认都为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

`` 8.void scws_set_ignore(scws_t s, int yes)` 设定分词结果是否忽略所有的标点等特殊符号(不会忽略\r和\n)。

参数 yes 1 表示忽略,0 表示不忽略,缺省情况为不忽略。

  1. void scws_set_multi(scws_t s, int mode) 设定分词执行时是否执行针对长词复合切分。(例:“中国人”分为“中国”、“人”、“中国人”)。

参数 mode 复合分词法的级别,缺省不复合分词。取值由下面几个常量异或组合:

  • SCWS_MULTI_SHORT 短词
  • SCWS_MULTI_DUALITY 二元(将相邻的2个单字组合成一个词)
  • SCWS_MULTI_ZMAIN 重要单字
  • SCWS_MULTI_ZALL 全部单字
  1. void scws_set_duality(scws_t s, int yes) 设定是否将闲散文字自动以二字分词法聚合。

参数 yes 如果为 1 表示执行二分聚合,0 表示不处理,缺省为 0。
```

测试multi_short如下

```
digoal=> select to_tsvector('zhcfg','云安全部');
to_tsvector


'云安':1
(1 row)

digoal=> select to_tsvector('zhcfg','云 安全部');
to_tsvector


'云':1 '安全':3 '安全部':2
(1 row)

digoal=> set zhparser.multi_short=off;
SET
digoal=> select to_tsvector('zhcfg','网络安全部');
to_tsvector


'安全部':2 '网络':1
(1 row)

digoal=> set zhparser.multi_short=on;
SET
digoal=> select to_tsvector('zhcfg','网络安全部');
to_tsvector


'安全':3 '安全部':2 '网络':1
(1 row)
```

影响索引zhparser的设置影响to_tsvector函数索引。

建议初始 zhparser.multi_short=on 设置为on。

或者设置用户级别或者数据库级别的参数,例如。

alter role all set zhparser.multi_short=on;

思考

有一些场景,可能会给全文检索带来困扰例如

"浙江省杭州市烟草公司" 需要与 "杭州烟草局" 进行匹配,但是你会发现匹配不上,原因是词不对。即使用如下文章,也无法解决这个问题。

《PostgreSQL 文本数据分析实践之 - 相似度分析》

使用短文本也许能解决这个问题,但是会增加VECTOR的长度,同时增加GIN索引的大小。并且引入一些含义重复的词。

zhparser digoal=> set zhparser.multi_short=on; SET

pg_jieba postgres=# set scws.multi_mode =short; SET

```
postgres=# select * from to_tsvector('scwscfg', '浙江省杭州烟草公司');
to_tsvector


'公司':5 '杭州':3 '浙江':2 '浙江省':1 '烟草':4
(1 row)

postgres=# select * from to_tsvector('scwscfg', '浙江省杭州市烟草公司');
to_tsvector


'公司':6 '杭州':4 '杭州市':3 '浙江':2 '浙江省':1 '烟草':5
(1 row)

postgres=# select * from to_tsvector('scwscfg', '浙江省杭州市烟草局');
to_tsvector


'杭州':4 '杭州市':3 '浙江':2 '浙江省':1 '烟草':6 '烟草局':5
(1 row)
```

```
postgres=# set scws.multi_mode =none;
SET
postgres=# select * from to_tsvector('scwscfg', '浙江省杭州市烟草公司');
to_tsvector


'公司':4 '杭州市':2 '浙江省':1 '烟草':3
(1 row)

postgres=# select * from to_tsvector('scwscfg', '浙江杭州烟草公司');
to_tsvector


'公司':4 '杭州':2 '浙江':1 '烟草':3
(1 row)

postgres=# select * from to_tsvector('scwscfg', '浙江杭州烟草局');
to_tsvector


'杭州':2 '浙江':1 '烟草局':3
(1 row)

postgres=# select * from to_tsvector('scwscfg', '浙江杭州烟草');
to_tsvector


'杭州':2 '浙江':1 '烟草':3
(1 row)
```

``` postgres=# select regexp_replace('浙江省烟草局','[省局]','','g'); regexp_replace


浙江烟草 (1 row)

postgres=# select to_tsquery('jiebacfg', regexp_replace('浙江省烟草局','[省局]','','g')); to_tsquery


'浙江' & '烟草' (1 row) ```

短文本可以切到单字级别,但是那就失去分词的意义了。

另一方面,打开multi_short , vector会变大,GIN索引也会变大。

建议可以进行一些处理:

当一个tsvector同时出现类似“杭州、杭州市”时,只保留短的这个“杭州”。

在生成ts_query进行搜索时,做同样的处理。

需要在系统中保留一些停词,例如“公司、局、省、市”等。

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论