PostgreSQL全文检索使用

1. Psql 安装 (CentOS-7.x)

采用yum安装psql是最简洁高效的

# 更新一下yum
yum update -y
# 直接安装 
yum install postgresql-server -y
# 初始化数据库
postgresql-setup initdb
# 加入linux的服务管理
systemctl enable postgresql.service
# 启动服务
systemctl start postgresql.service

安装完成之后,我们可能需要配置一下,Psql有两个配置文件

/var/lib/pgsql/data/postgres.conf

如果你需要远程访问,请取消注释,并吧localhost改成*,我本地安装,只为了自己平时使用,所以我就默认监听localhost就可以了

postgres.conf
/var/lib/pgsql/data/pg_hba.conf

Psql 初始化过后,默认提供一个postgres用户和一个postgres数据库,但是我们直接psql -U postgres -d postgres命令是连接不上的,因为在默认配置里,当前登录的账户必须是postgres,才能连接

所以我们改一改,认证方式改成md5或者password(不建议),默认是没有密码的,所以要输入密码的时候,回车就好了

更粗暴的方式是直接把认证方式改为trust,这样凡是登录到这台电脑的用户都被信任,个人电脑可以这么干了

更详细的配置可以去看看官方文档

pg_hba.conf

这个时候,我们重启服务,就可以登录了

systemctl restart postgresql.service
psql -U postgres -h localhost -w

2. Psql 关于全文检索的支持(tsvector和tsquery)

个人觉得,Psql对全文检索还是很友好了,以前还是通过Apache Lucene实现的,最近看看Psql,简单了不少

Psql 提供两个数据类型tsvectortsquery,并且通过动态检索自然语言文档的集合,定位到最匹配的查询结果

一个tsvector的值是唯一分词的分类列表,把一话一句词格式化为不同的词条,在进行分词处理的时候,tsvector会自动去掉分词中重复的词条,按照一定的顺序装入,例如

# psql的自动分词(默认是英文分词,中文分词后面讲)
select 'hello world'::tsvector;
# 输出
tsvector
-----------------------------
'hello' 'world'

# 可以设置词条位置常量
select 'hello:3 world:1'::tsvector;
# 输出
tsvector
-----------------------------
'hello':3 'world':1

这个位置信息通常就是当前文档中单词所处的位置,这个位置信息用于关注度的体现。位置信息常量的值的范围为1 到 16383。分词后,会把相同词条的位置记录到一个词条中

tsquery,相当于是查询tsvector的查询条件,并且可以联合使用boolean 操作符来连接, & (AND), | (OR), and ! (NOT). 使用括号(),可以强制分为一组
在全文检索的过程中,tsquerytsvector之间采用@@操作符

select 'hello world fuck you hahahaha'::tsvector @@ 'hello & you'::tsquery;
?column? 
------------------
t

对于英文全文检索应用来说,很多时候的句子是非标准化的,但是tsvector和tsquery是不会知道的,为处理加工的文本应该通过使用to_tsvector函数

# 采用psql提供的函数帮助我们将文本分词
select to_tsvector('hello world');
to_tsvector     
---------------------
 'hello':1 'world':2

# 采用psql提供的函数进行全文检索
select to_tsvector('hello world fuck you hahah') @@ to_tsquery('hello & you');
?column? 
------------------
t

在Psql中 @@操作符会将两边的文本进行自动的转换

  • tsvector @@ tsquery
  • text @@ tsquery
  • text @@ text
  • 后两种,text @@ tsquery 等同于 to_tsvector(x) @@ y.
  • 而 text @@ text 等同于 to_tsvector(x) @@ plainto_tsquery(y).

plainto_tsquery() 用于将文本转为tsquery,这样就不用每次都去写 & 条件了

3. Psql 索引类型

我们也要为全文检索建立索引,提升查询效率,我们为全文检索建立的索引是Gin索引

几种基本索引类型

B-Tree
CREATE INDEX test1_id_index ON test1 (id);

B-Tree索引主要用于等于和范围查询,特别是当索引列包含操作符" <、<=、=、>=和>"作为查询条件时,PostgreSQL的查询规划器都会考虑使用B-Tree索引。在使用BETWEEN、IN、IS NULL和IS NOT NULL的查询中,PostgreSQL也可以使用B-Tree索引(MySQL则不会)。然而对于基于模式匹配操作符的查询,如LIKE、ILIKE、~和 ~*,仅当模式存在一个常量,且该常量位于模式字符串的开头时,如col LIKE 'foo%'或col ~ '^foo',索引才会生效,否则将会执行全表扫描,如:col LIKE '%bar'。

Hash
CREATE INDEX name ON table USING hash (column);

散列(Hash)索引只能处理简单的等于比较。当索引列使用等于操作符进行比较时,查询规划器会考虑使用散列索引。

这里需要额外说明的是,PostgreSQL散列索引的性能不比B-Tree索引强,但是散列索引的尺寸和构造时间则更差。另外,由于散列索引操作目前没有记录WAL日志,因此一旦发生了数据库崩溃,我们将不得不用REINDEX重建散列索引。

GiST
CREATE INDEX name ON table USING gist (column);

GiST索引不是一种单独的索引类型,而是一种架构,可以在该架构上实现很多不同的索引策略。从而可以使GiST索引根据不同的索引策略,而使用特定的操作符类型。

GIN
CREATE INDEX name ON table USING gin (column);

GIN索引是反转索引,它可以处理包含多个键的值(比如数组)。与GiST类似,GIN同样支持用户定义的索引策略,从而可以使GIN索引根据不同的索引策略,而使用特定的操作符类型。作为示例,PostgreSQL的标准发布中包含了用于一维数组的GIN操作符类型,如:<@、@>、=、&&等。

两种建立索引方式
# 我新建一个posts表,记录我的博客内容,平时需要根据博客名和内容做查询
create table posts (
  id integer,
  title varchar(50) not null,
  content text not null,
  primary key(id)
);
  1. 为tsv函数建索引
create index post_tsvcontent_idx on posts using gin(to_tsvector('english', title || content));
  1. 新增一个tsv列,为列建立索引(推荐)
alter table posts add_column tsv_content tsvector;
update posts set tsv_content = to_tsvector('english', coalesce(title,'') || coalesce(content,''));
create index post_tsvcontent2_idx on posts using gin(tsv_content);

现在都可以对posts表里的内容进行全文检索了

# 例如
select title from posts where to_tsvector(title || content) @@ plainto_tsquery('hello world');

# 或者
select title from posts where tsv_content @@ plainto_tsquery('hello world');

4. 用触发器更新分词字段

如果我们是单独新建一列去存放tsvector的分词内容,为了简便,我们希望在插入记录过后,自动对需要检索的列生成分词,所以我们就需要触发器

# Psql 提供了两个触发器函数用于实现此功能
tsvector_update_trigger()    
tsvector_update_trigger_column()
# 当然,你也可以写自己的触发器
tsvector_update_trigger() 的使用
# 非常简单
CREATE TRIGGER trigger_posts_tsv_content BEFORE INSERT OR UPDATE 
ON posts FOR EACH ROW EXECUTE PROCEDURE
tsvector_update_trigger(tsv_content, 'english', title, content)

5. 采用zhparser支持中文分词

zhparser是基于Simple Chinese Word Segmentation(SCWS)中文分词库实现的一个PG扩展,作者是 amutu,源码URL为https://github.com/amutu/zhparser

安装SCWS
wget -q -O - http://www.xunsearch.com/scws/down/scws-1.2.2.tar.bz2 | tar xf -
cd scws-1.2.2
./configure
make install
安装zhparser
git clone https://github.com/amutu/zhparser.git
cd zhparser
SCWS_HOME=/usr/local make && make install
配置zhparser扩展
# 连接到目标数据库,创建zhparser解析器
create extension zhparser
# 将zhparser解析器作为全文检索配置项
create text search configuration chinese (PARSER = zhparser);

然后通过\dF和\dFp命令查看配置

demo
指定分词策略

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

# 连接到目标数据库
select ts_token_type('zhparser');
demo

普遍情况下,我们只需要按照名词(n),动词(v),形容词(a),成语(i),叹词(e)和习用语(l)6种方式对句子进行划分就可以了,词典使用的是内置的simple词典,即仅做小写转换

所以添加如下映射

alter text search configuration chinese add mapping for n,v,a,i,e,l with simple;
最后效果
# 连接到目标数据库
select to_tsvector('chinese', '这周日你有空么');
# 输出
to_tsvector 
-------------------------
'么':2 '有空':1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 之前的文章一直在规避索引的建立去优化数据库,不是不想讲,而是这个太重要,必须抽出来讲。今天我们就来研究下数据库索引...
    JackFrost_fuzhu阅读 4,646评论 0 70
  • 在项目中如果要实现全文检索,最普通的方法就是通过数据库查询语句like '%keywords%',但是这种方法在数...
    xsg阅读 7,507评论 2 2
  • 目录结构:1.全文检索 2.Lucene入门3.Lucene进阶 全文检索 一, 生活中的搜索:1.Win...
    CoderZS阅读 1,575评论 0 12
  • 概述 postgresql是一个开源的关系型数据库,可以作为mysql的替代品。本篇意在让读者快速的了解postg...
    胖头鱼战士阅读 8,187评论 0 7
  • 周一的时候翘课,写了一天代码,收获颇丰。周二的时候翘课,看了一天动漫,收获颇丰。 终于有点痴迷于一样东西的感觉了,...
    饵心阅读 142评论 0 0