使用 tsearch2
OK,所有东西都安装完毕,我们需要试验一下了,下面是一个基本过程:
例子1:在原有的表上增加全文索引字段
准备全文索引的表
假设我们准备使用全文索引的数据库名字叫 BBS,首先要在这个数据库上安装 tsearch2:
psql -d BBS -f tsearch2.sql
在编译完成tsearch2之后,tsearch2.sql 在 $PGSRC/contrib/tsearch2 里面。
假设我们有这样一个表,里面保存着BBS的帖子:
create table BbsPost( id serial, topic varchar(100), content text, posterId integer, postTime timestamp );
增加一个全文索引字段
现在我们希望我们能够对 topic 字段和 content 字段进行全文索引,那么我们需要添加一个字段给表BbsPost:
psql BBS alter table BbsPost add column idxFti tsvector;
然后,我们要更新这个字段,使之包含合理的分词字段:
update BbsPost set idxFti = to_tsvector(coalesce(carriecharseg(topic, 1), '') || ' ' || coalesce(carriecharseg(content, 1), ''));
创建全文索引
然后,我们需要在这个字段上创建特殊的索引:
create index bbspost_idxfti_idx on BbsPost using gist(idxFti);
清理数据库
之后,我们再清理一下数据库:
vacuum full analyze analyze;
这样,全文索引就准备完成了!
例子二:通过扩展表使用全文索引
首先,仍然对BBS数据库进行处理,这次我们不直接在原有全文字段表上增加字段,而是另外建立一个表:
create table bbsPost_fti (id integer, idxfti tsvector);我们创建两个字段的表,用于对
bbsPost表进行全文索引。然后,我们给
bbsPost_fti加一个外键:
alter table bbsPost_fti add foreign key (id) references bbsPost(id);这样保证
bbsPost_fti的 id 一定是
bbsPost中存在的。然后,我们可以向
bbsPost_fti里面插入数据:
insert into bbsPost_fti (id, idxfti) select id, to_tsvector(coalesce(carriecharseg(topic, 1), '') || ' ' || coalesce(carriecharseg(content, 1), '')) from bbsPost order by id;这样,初始化所有数据到
bbsPost_fti中。然后创建索引:
create index idxfti_idx on bbsPost_fti using gist(idxfti); create index bbsPost_fti_id_idx on bbsPost_fti (id);
我们也可以用倒排索引(GIN)进行全文索引,这样检索速度比 GIST 更快:
create index idxfti_idx on bbsPost_fti using gin(idxfti);
在我的试验中,GIN比GIST快了将近5倍,唯一的缺点是更新速度明显变慢。这个需要用户自己去平衡了。
最后,也是清理数据库:
vacuum full analyze;
然后我们也可以开始使用了!
使用全文索引
我们上面用的是分字程序,那么我们可以这样使用SQL查询来进行数据检索:
select * from BbsPost where idxFti @@ '中&文';
这样,就把包含“中”和“文”字的帖子都找了出来。@@ 操作符还支持与或非的逻辑:
select * from BbsPost where idxFti @@ '(中&文)|(英&文)';
用圆括弧:() 和 & 和 | 和 ! 可以组合查询条件,对数据表进行查询。目前,我们只拥有分字的程序,将来在完成中文分词程序之后,我们可以实现更简单的搜索,类似:
select * from BbsPost where idxFti @@ '(中文)|(英文)&(中国)';
这样的查询,大家可以用 explain analyze 看看,这样的查询的效率和 like 查询的效率差距有多大? ;)
中文屏蔽词的添加
在语言里面有很多没有用的屏蔽词,比如英文里面的 "the",那么中文也有许多这样的词,比如“的”字,在这些词上建立索引,没必要也浪费,因此,我们可以用一种叫做 stop word (屏蔽词)的机制,给关闭这些词。具体做法是:
- 找到$PGHOME/share/contrib/
- echo "的" | iconv -f gbk -t utf8 > chinese.stop.utf8 (如果你的终端是UTF8的,则可以忽略 iconv 语句。)
- 更多的 chinese stop word 可以用 echo "屏蔽词" | iconv -f gbk -t utf8 >> chinese.stop.utf8 实现
至此,使用 tsearch2 进行中文全文索引的最基本的要点已经在此列出,更多相关的信息,我会在有进一步的试验结果之后再详细展开。
