PostgreSQL 全文搜索 简介
1 背景知识
全文搜索 是指从文档集合中找到匹配 查询
的文档,并可以根据与 查询
的 相似性
顺序排序。
查询
是一组词位
和操作符
的表达式。相似性
是查询
在文档中出现的频率。出现的频率越高则相似度
越高。- 下图为全文搜索的整体流程:
2 什么是一个文档?
文档对于文件系统,是一篇杂志文章或电子邮件消息。文档对于PostgreSQL数据库而言是指(一个或多个)表的文本字段。下面就是从 PostgreSQL
数据库多个拼接成的一个文档。
SELECT title || ' ' || author || ' ' || abstract || ' ' || body AS document
FROM messages
WHERE mid = 12;
SELECT m.title || ' ' || m.author || ' ' || m.abstract || ' ' || d.body AS document
FROM messages m, docs d
WHERE m.mid = d.did AND m.mid = 12;
3 正则表达式
PostgreSQL
对文本数据类型提供了 ~
、~*
、LIKE
和 ILIKE
正则表达式操作符,但在日常使用中无法满足自然语言的搜索需求,有下列三个原因。
3.1 问题一:派生词问题
1、因为有些词可能有数千种派生词,以英语为例:satisfy
有 satisfies
和 satisfaction
两种变体单词。所以有可能无法搜索到包含 satisfies
的文档。
2、虽然正则表达式可以使用 OR
来搜索多个派生形式,但是这样做很繁琐也容易出错。
3.2 问题二:相似度排序问题
因为无法按照 相似度
进行排序,所以查询结果是杂乱无章的。
3.3 问题三:性能问题
由于没有索引的支持,每次搜索将会进行全表扫描,查询效率低下。
4 全文搜索预处理过程
全文索引
对文档进行预处理
,并创建全文索引
便于以后快速的搜索。- 预处理的全部过程如下:
4.1 将文档解析成 记号
- 从文档中提取
记号
。
记号
的形式:例如数字
、词
、复杂的词
、电子邮件地址
等,通过对记号
进行分类,可以对不同类型的记号
采取最优处理。 - 将
记号
进行分类。
取决于应用程序的需求,但是对于大部分场景都可以使用一套预定义的分类。
PostgreSQL使用一个 解析器 来执行这个步骤。也可以创建自定义的解析器。
4.2 词位的正规化
此步骤将 记号
转换成 词位
。由于单词的有许多不同变体,将这些单词的 词根
提取出来就称之为 正规化
。
记号
是文档文本的原始片段,而词位
将会被索引和搜索使用。- 和
记号
相同,一个词位
是一个字符串,但是它已经被正规化
。 - 例如:将大写字母转换成小写形式,并且涉及移除后缀(例如英语中的
s
或es
)和前缀,只保留词根部分。 - 通过词位找到同一个词的变体形式,而不需要冗长地输入所有可能的变体。
- 此外,这个步骤不会
正规化
停用词
,它们是那些出现频率很高的单词,对于搜索是无用的。 PostgreSQL使用 词典 来执行这个步骤。
4.3 创建全文索引
全文索引存储正规化后的 词位
数组,它是一个有序数组。全文索引还要存储 相似似度排名
的位置信息,并按照相似度进行排序。
全文搜索可以使用 RUM 索引、GIN 索引 和 Gist 索引 来加速。
5 全文搜索数据类型
数据类型 tsvector 来存储 预处理
后的文档。数据类型 tsquery 表示需要匹配哪些 查询词
。
6 全文搜索的词典
标准词典允许对 记号
如何被正规化进行细粒度的控制。主要功能
- 定义停用词。
- 使用
Ispell
词典把同义词映射到一个单词。 - 使用
分类词典
词典把短语映射到一个单词。 - 使用
Ispell
词典,把一个词的不同变体映射到一种规范的形式。 - 使用
Snowball
词典,指定分析器规则将一个词的不同变体映射到一种规范的形式。
7 全文搜索函数
另外还有很多文本搜索函数和操作符可以用于这些数据类型,其中最重要的是匹配操作符 @@
,它在 基本文本匹配 中介绍。
8 全文搜索配置
8.1 预定义配置
- 预定义配置由 default_text_search_config 参数控制。
这个参数可以在:全局范围、数据库范围、会话范围设置。
to_tsvector
函数有个可选地 regconfig
函数,如果未被指定。则 default_text_search_config 生效。
PostgreSQL
中有多种语言的预定义配置,提供更加强大的功能。
(1)设置停用词。
(2)使用 预定义配置处理同义词。基于空白之外的解析。- PostgreSQL中有多种语言的预定义配置,根据不同的语言提供不同的配置。
- 使用
\dF
命令显示所有可用的预定义配置。
testdb=# \dF
//屏幕输出:
List of text search configurations
Schema | Name | Description
------------+------------+---------------------------------------
pg_catalog | arabic | configuration for arabic language
pg_catalog | armenian | configuration for armenian language
pg_catalog | basque | configuration for basque language
pg_catalog | catalan | configuration for catalan language
pg_catalog | danish | configuration for danish language
pg_catalog | dutch | configuration for dutch language
pg_catalog | english | configuration for english language
pg_catalog | finnish | configuration for finnish language
pg_catalog | french | configuration for french language
pg_catalog | german | configuration for german language
pg_catalog | greek | configuration for greek language
pg_catalog | hindi | configuration for hindi language
pg_catalog | hungarian | configuration for hungarian language
pg_catalog | indonesian | configuration for indonesian language
pg_catalog | irish | configuration for irish language
pg_catalog | italian | configuration for italian language
pg_catalog | lithuanian | configuration for lithuanian language
pg_catalog | nepali | configuration for nepali language
pg_catalog | norwegian | configuration for norwegian language
pg_catalog | portuguese | configuration for portuguese language
pg_catalog | romanian | configuration for romanian language
pg_catalog | russian | configuration for russian language
pg_catalog | serbian | configuration for serbian language
pg_catalog | simple | simple configuration
pg_catalog | spanish | configuration for spanish language
pg_catalog | swedish | configuration for swedish language
pg_catalog | tamil | configuration for tamil language
pg_catalog | turkish | configuration for turkish language
pg_catalog | yiddish | configuration for yiddish language
(29 rows)
8.2 自定义配置
为了让建立自定义文本搜索配置更容易,一个自定义配置可以从更简单的数据库对象来建立。PostgreSQL的文本搜索功能提供了四类配置相关的数据库对象:
-
文本搜索解析器
将文档拆分成记号并分类每个记号(例如,作为词或者数字)。 -
文本搜索词典
将记号转变成正规化的形式并拒绝停用词。 -
文本搜索词典
提供位于词典底层的函数(一个词典简单地指定一个模板和一组用于模板的参数)。 -
文本搜索配置
选择一个解析器和一组用于将解析器产生的记号正规化的词典。
9 全文搜索操作符 @@
@@
是一个匹配操作符,用于判断 查询
在文档中是否找到。
9.1 匹配操作符支持的形式
text @@ tsquery
等价于 to_tsvector (x)@@ y
。text @@ text
等价于to_tsvector(x) @@
plainto_tsquery (y) `。
tsvector @@ tsquery
tsquery @@ tsvector
text @@ tsquery
text @@ text
9.2 匹配操作符逻辑运算符
在 tsquery 中,支持逻辑运算符如下:
&
(AND)操作符指定它的两个参数都必须出现在文档中才表示匹配|
(OR)操作符指定至少一个参数必须出现。- 而
!
(NOT)操作符指定它的参数不出现才能匹配。 例如,查询fat & ! rat
匹配包含fat
但不包含rat
的文档。
9.3 基本文本匹配
PostgreSQL中的全文搜索基于匹配操作符 @@
,表示 一个 tsvector(文档)匹配一个 tsquery (查询)时返回 true
,表示能够匹配成功。
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat & rat'::tsquery;
//屏幕输出:
?column?
----------
t
匹配操作符 @@
对于顺序不敏感。
SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat rat'::tsvector;
//屏幕输出:
?column?
----------
f
9.4 预处理函数 to_tsvector
SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');
//屏幕输出:
?column?
----------
t
9.5 不匹配的情况
由于 ::tsvector
操作符表示文本已经是正规化好的词位,所以这里不会发生词 rats
的正规化,所以 rats
不匹配 rat
。
SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat');
//屏幕输出:
?column?
----------
f