Postgresql全文检索

前端之家收集整理的这篇文章主要介绍了Postgresql全文检索前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1、环境

Fedora 20 + Postgresql 9.3.4 + scws 1.2.2 + zhparser

2、安装

2.1 scws

  • wget -q -O - http://www.xunsearch.com/scws/down/scws-1.2.2.tar.bz2• tar xjf - cd scws-1.2.1
  • ./configure --prefix=/usr/local #该路径为scws的安装路径
  • make install

2.2 zhparser

  • git clone https://github.com/amutu/zhparser.git
  • SCWS_HOME=/usr/local/scws make && make install

3、配置

[root@localhost ~]# su postgres
[postgres@localhost ~]$ psql
psql (9.3.4)
Type "help" for help.
postgres=# CREATE EXTENSION ZHPARSER;
postgres=# CREATE TEXT SEARCH CONFIGURATION testzhcfg (PARSER = zhparser);
postgres=# ALTER TEXT SEARCH CONFIGURATION testzhcfg ADD MAPPING FOR n,v,a WITH simple;
注:此处的n,a为词性(名词、动词、形容词),分词时会只考虑此处指定的词性,其他诸如介词、动名词会被忽略。scws中的所有词性说明:http://www.xunsearch.com/scws/docs.PHP#attr,并不是所有的scws中的词性都被支持,如ns(地理名词)是不被支持的。

4、测试

postgres=# SELECT * FROM ts_parse('zhparser','hello world!我不是为了输赢,我就是认真');
tokid | token
-------+-------
101 | hello
101 | world
117 | !
114 | 我
118 | 不是
112 | 为了
110 | 输赢
117 |,
114 | 我
110 | 就是
118 | 认真
(11 rows)
postgres=# SELECT to_tsvector('testzhcfg',我就是认真') @@to_tsquery('认真');
?column?
----------
t
(1 row)
?column?
----------
f
(1 row)

5、自定义词库

5.1 自定义字典

工具:XDB导入导出工具(http://www.xunsearch.com/scws/down/PHPtool_for_scws_xdb.zip)
需要有PHP环境(可在命令行下运行即可,需要有mbstring库),使用方法请参考压缩包中的readme.txt
scws使用的字典为xdb格式,不可以直接编辑和查看,其对应的文本形式如下:
WORD TF IDF ATTR
保障房 1.00 1.00 n
其中,WORD即为字典中词;TF为词频,表示该单词在单个文档中出现的频率;IDF为逆词频,表示该单词在其他文档出现的频率;ATTR为词性。TF*IDF的值表示该词的权重,权重大的会被优先看做是一个整体。如:
WORD TF IDF ATTR
中央 3.00 3.00 n
地方 2.00 2.00 n
“中央”的权重(TF*IDF)小于“从中”,所以“从中央”一起出现时,就会分为“从中”和“央”。
WORD,TF,IDF,ATTR之间的分割符是tab,其他的会出错

5.2 zhparser使用自定义词典

方法1修改/usr/share/pgsql/tsearch_data下的dict.utf8.xdb(保证文件名不变),不过这种方式耗时较长
借助SCWS提供的工具,可以很快的将dict.utf8.xdb转为普通的文本文件,但将文本文件转回去的时候大约耗时1h左右
方法2:通过增加字典文件来扩展词库
约定
  • 字典文件的命名格式为usr_dict_num.xdb,其中num为序号,从1开始,表示第几个自定义的字典num必须连续,如果出现usr_dict_1.xdb,usr_dict_2.xdb,usr_dict_4.xdb,那么usr_dict_4.xdb及以后num大于4的字典都不会被加载
  • 所有自定义的字典要放在/usr/share/pgsql/tsearch_data下面
  • 新增的字典只要复合以上约定可自动加载,无须重新安装zhparser,也无须重新create extension
修改zhparser.c中的代码
修改代码
scws_set_dict(scws,dict_path,SCWS_XDICT_XDB);
修改代码
beg=1;
while(1){
snprintf(dict_path,MAXPGPATH,"%s/tsearch_data/usr_dict_%d.xdb",sharepath,beg);
exist=access(dict_path,F_OK);
if(exist==-1)
break;
scws_add_dict(scws,SCWS_XDICT_XDB);
beg++;
}
修改zhparser.c,需要增加文件:#include "unistd.h"
/usr/share/pgsql/tsearch_data该路径视postgresql的安装路径而定

6、建立全文检索的索引

方式1:表达式索引

CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector(config_name,body));
CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector('english',title || body));

方式2:分离字段索引

ALTER TABLE pgweb ADD COLUMN textsearchable_index_col tsvector;
UPDATE pgweb SET textsearchable_index_col =
to_tsvector('english',coalesce(title,) || coalesce(body,));
CREATE INDEX textsearch_idx ON pgweb USING gin(textsearchable_index_col);
在使用独立字段存储 tsvector 形式的时候,我们需要创建一些触发器以保持 tsvector 字段对 title 和 body 修改的同步。分离字段方式比表达式索引方式的一个优点是它不需要在查询里明确声明文本 搜索的配置就可以使用索引。如上面例子所示,查询可以依赖于default_text_search_config。另 外一个优点是搜索会更快,因为它不需要重新调用 to_tsvector 函数来判断是否和索引匹配。不过, 表达式索引的方法的优点是设置简单,而且它需要的磁盘空间更少,因为 tsvector 表现形式不用明 确存储。

7、实验

数据量:17830826条,约4G

在主键id上执行count查询

postgres=# select count(id) from area_detail;
count
----------
17830826
(1 row)
Time: 25749.020 ms

通过id搜索一条记录

postgres=# select * from area_detail where id = '1601799';
Time: 46.024 ms

通过like搜索数据库记录

postgres=# select * from area_detail where localityname like '%豆沙%';
Time: 25822.282 ms(约25秒)

通过未建索引的全文检索搜索数据库记录

postgres=# select * from area_detail where to_tsvector('testzhcfg',localityname) @@to_tsquery('testzhcfg','豆沙');
Time: 621077.779 ms

通过建立了索引(gin)的全文检索搜索数据库记录

PHP,感谢hightman大神
  • https://github.com/amutu/zhparser,感谢 amutu大神
  • http://blog.163.com/digoal@126/blog/static/163877040201422410175698/
  • http://www.pgsqldb.org:8079/mwiki/index.PHP/12._%E5%85%A8%E6%96%87%E6%90%9C%E7%B4%A2
  • http://my.oschina.net/Kenyon/blog/80904
  • 猜你在找的Postgre SQL相关文章