PostgreSQL中文全文检索

一 安装必备软件

1.1 安装SCWS

下载scws:http://www.xunsearch.com/scws/down/scws-1.2.2.tar.bz2

#解压
[root@pg1 opt]#  tar -jxvf scws-1.2.2.tar.bz2
#编译&安装
[root@pg1 opt]# cd scws-1.2.2
[root@pg1 scws-1.2.2]# ./configure
[root@pg1 scws-1.2.2]# make
[root@pg1 scws-1.2.2]# make install

1.2 安装zhparser

gtihub主页:https://github.com/amutu/zhparser
zhparser地址:https://codeload.github.com/amutu/zhparser/zip/master

# 解压
 [root@pg1 opt]# unzip zhparser-master.zip
# 进入文件目录
[root@pg1 opt]# cd zhparser-master
# 设置path目录
[root@pg1 zhparser-master]# export PATH=$PATH:/home/postgres/bin
# 编译安装
[root@pg1 zhparser-master]# SCWS_HOME=/usr/local make && make install

1.3 安装神器RUM

关于PostgreSQL9.6的全文搜索神器RUM,可以查看德哥的博客:
PostgreSQL 全文检索加速 快到没有朋友 - RUM索引接口
PostgreSQL 文本数据分析实践之 - 相似度分析
rum下载地址:https://codeload.github.com/postgrespro/rum/zip/master

# 解压,比如在 /opt/rum-master目录下
 [root@pg1 opt]# unzip rum-master.zip
# 赋予文件权限
[root@pg1 opt]# chown -R postgres.postgres /opt/rum-master
# 切换到postgres账户
[root@pg1 opt]# su - postgres
# 进入文件目录
[postgres@pg1 ~]$ cd /opt/rum-master
# 编译
[postgres@pg1 rum-master]$  make USE_PGXS=1
[postgres@pg1 rum-master]$ make USE_PGXS=1 install
[postgres@pg1 rum-master]$ make USE_PGXS=1 installcheck

二 中文分词扩展安装配置

2.1 安装扩展

# 创建一个新数据库
[postgres@pg1 rum-master]$ psql
psql (9.6.0)
Type "help" for help.

postgres=# create database knowledge;
CREATE DATABASE
# 切换到knowledge数据库
postgres=# \c knowledge;
You are now connected to database "knowledge" as user "postgres".
# 创建zhparser扩展
knowledge=# create extension zhparser;
CREATE EXTENSION
# 创建rum扩展
knowledge=# create extension rum;
CREATE EXTENSION
# 查看安装的解析器
 knowledge=# \dFp
   List of text search parsers
   Schema   |   Name   |     Description     
------------+----------+---------------------
 pg_catalog | default  | default word parser
 public     | zhparser | 
(2 rows)
# 查看zhparser将中文切分成的26种token
knowledge=#  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)

2.2 创建使用zhparser作为解析器的全文搜索的配置

knowledge=#  CREATE TEXT SEARCH CONFIGURATION testzhcfg (PARSER = zhparser);
CREATE TEXT SEARCH CONFIGURATION

2.3 往全文搜索配置中增加token映射

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

三 中文分词测试

# 由于客户端和服务器端字符集不同,一般中文会报错
knowledge=#  select to_tsvector('testzhcfg','南京人民*');
ERROR:  invalid byte sequence for encoding "UTF8": 0xc4 0xcf
# 解决方法方法有两种,一种是在psql中输入“\encoding GBK” 
# 另一种是设置环境变量“export PGCLIENTENCODING=GBK”
knowledge=# \encoding GBK
knowledge=#  select to_tsvector('testzhcfg','南京人民*');
      to_tsvector      
-----------------------
 '人民*':2 '南京':1
(1 row)

以下配置在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

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

knowledge=# set zhparser.multi_short=on;
SET
knowledge=#  select to_tsvector('testzhcfg','南京人民*');
               to_tsvector               
-----------------------------------------
 '人民':3 '人民*':2 '南京':1 '*':4

开启后,果然匹配的更多了。

四 行级全文检索

在一些应用程序中,可能需要对表的所有字段进行检索,有些字段可能需要精准查询,有些字段可能需要模糊查询或全文检索。
比如检索T表,某个字段存在一个名称为'a'的返回:

select * from t where name1='a' or name1= 'a' or name2='a' or ......;

首先,or查询会不走索引,效率低下,其次如果加上like,效率更低。
在pg中就可以使用行级全文检索,如:

create table Test(
    id serial not null,
    name text,
    name1 text
)
insert into Test(name,name1) values ('中国','南京');
select t::text from Test t;
#结果如下:
knowledge=# select t::text from test t;
       t       
---------------
 (1,中国,南京)
(1 row)

将整行转成大文本,可以从中继续分词查询满足关键字的,研究未完待续。

五 其他专家提出的问题,这里引用如下:

# ‘南大被忽视了’
knowledge=#  select to_tsvector('testzhcfg','南大') ;
 to_tsvector 
-------------
 
(1 row)

knowledge=# select to_tsvector('testzhcfg','南大 北大 东大 西大') ;
        to_tsvector         
----------------------------
 '东大':2 '北大':1 '西大':3
(1 row)

调查发现原因在于它们被SCWS解析出来的token类型不同:

knowledge=# select ts_debug('testzhcfg','南大 北大 东大 西大') ;
                ts_debug                 
-----------------------------------------
 (j,"abbreviation (jian lue)",南大,{},,)
 (n,noun,北大,{simple},simple,{北大})
 (n,noun,东大,{simple},simple,{东大})
 (n,noun,西大,{simple},simple,{西大})
(4 rows)

'南大'被识别为j(简略词),而之前并没有为j创建token映射。现在加上j的token映射,就可以了。

knowledge=#  ALTER TEXT SEARCH CONFIGURATION testzhcfg ADD MAPPING FOR j WITH simple;
ALTER TEXT SEARCH CONFIGURATION
knowledge=# select to_tsvector('testzhcfg','南大 北大 东大 西大') ;
             to_tsvector             
-------------------------------------
 '东大':3 '北大':2 '南大':1 '西大':4
(1 row)

上一篇:PostgreSQL工具杂记


下一篇:Openlayers 3加载XYZ示例