ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 12.1\. 介绍 全文搜索(或只是_文本搜索_)提供满足_查询_的识别自然语言_文档_的能力, 并且任意地通过相关性查询进行排序。搜索最常见的类型是找到所有包含给定的_查询术语_的记录,并且以_相似性_的查 询顺序返回它们。 `query`和`similarity`的概念是非常灵活的,取决于特定的应用。最简单的 搜索认为`query`是一组词,并且`similarity`为文档中的查询词出现的频率。 文本搜索操作符已经在数据库中存在多年。PostgreSQL为文本数据类型提供`~`, `~*`, `LIKE`和`ILIKE`操作符,但它们缺乏许多通过现代信息系统要求的必要属性: * 没有语言的支持,即使是英语。正则表达式是不充分的,因为他们不能很容易地处理派生词, 比如, `satisfies` 和`satisfy`。你可能会丢失包含`satisfies`的文档, 虽然你可能会发现他们在寻找`satisfy`。使用`OR`搜索多个派生形式是可能的,但这很繁琐, 而且容易出错(有些词可能会有上千的派生词)。 * 他们没有提供搜索结果的分类(排序),当成千的匹配文档被发现时,这使得它们无效。 * 他们往往比较缓慢,因为没有索引的支持,因此他们必须为每一个搜索处理所有文档。 全文索引允许文档被_预处理_,并且为后边的快速搜索保存一个索引。预处理包括: * _解析文档__标记_。标识不同类别的记号是非常有用的, 例如,数字,词,复合词,电子邮件地址,这样他们可以用不同的方法来处理。原则上令牌类依赖于具体的应用, 但出于大多数的目的,可以使用一组预定义的类。PostgreSQL使用_解析器_来 执行这一步。提供了一种标准的解析器,以及为特定的需求创造的自定义分析器。 * _转换标记为__词_。词是一个字符串,就像一个标记,但它已经_标准化_, 这样同一个词的不同形式是一样的。例如,标准化几乎总是包括可折叠的大写字母到小写字母,往往涉及删除后缀(如英语中 的`s` 或者`es` )。这允许搜索找到同一个词的不同形式,没有繁琐的输入所有可能的变种。同时,这一步 通常删除_屏蔽词_,这是很常见的,他们对于搜索无用。(总之,标记是文档文本的原片段,而词汇被认 为是有用的索引和搜索的词。)PostgreSQL使用_词典_执行这一步。提供各种标准词典, 以及为特定的需求创造的自定义词典。 * _为优化搜索存储预处理文档_。比如,每个文档可以表示为标准化词汇排序数组。 伴随着词汇往往为_邻近排序_存储位置信息,这是理想的。因此包含查询词的"密集"区域的 文档比分散查询词分配到一个更高的顺序。 字典允许细粒度控制如何使用合适的字典规范化标记。你可以: * 定义不被索引的屏蔽词。 * 使用Ispell映射同义词到一个词。 * 使用同义词词典将短语映射到一个词。 * 使用Ispell词典将词的不同形式映射到一种范式。 * 使用Snowball词根规则将一个词的不同形式映射到一种范式。 一种数据类型`tsvector`用于存储预处理文档,以及类型`tsquery` 表示处理的查询([Section 8.11](#calibre_link-1007))。 为这些数据类型提供很多的函数和操作符([Section 9.13](#calibre_link-1137)),其中最重要的是匹配运算符`@@`,将在[Section 12.1.2](#calibre_link-1101)中介绍。 全文搜索可以使用索引进行加速([Section 12.9](#calibre_link-1129))。 ## 12.1.1\. 文档是什么? 一个_文档_是全文搜索系统的搜索单元;例如,杂志上的一篇文章或电子邮件消息。 文本搜索引擎必须能够解析文档,而且可以存储它们父文档词(关键词)的联系性。之后, 这些联系用来搜索包含查询词的文档。 在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 mid = did AND mid = 12; ``` > **Note:** 注意:实际上,在这些示例查询中,`coalesce`使用时应防止一个独立的`NULL`属性导致整个文档的`NULL`结果。 另外一个可能性是在文档系统中作为简单的文本文档存储。在这种情况下,数据库可以用于存储全 文索引并且执行搜索,同时使用一些唯一标识从文件系统中检索文档。然而,从外部检索文件,数据库 需要拥有超级用户权限或者特殊函数支持,因此比把所有数据保存在PostgreSQL中相比较, 这往往不太方便。同时,保持所有的数据在数据库里面允许轻松访问文档的元数据以帮助索引和显示。 为了文本搜索目的,每个文档必须减少到预处理`tsvector`格式。在文档的`tsvector`表示形式上完整的执行搜索 和排序—当为了显示给用户来选择文档时,只需要检索原文本。因此我们常说的`tsvector`作为文档,当然它仅仅是 完整文档的一种紧凑表示。 ## 12.1.2\. 基本文本匹配 PostgreSQL中的全文搜索基于匹配算子`@@`,如果一个`tsvector`(document)匹配一个`tsquery`(query), 则返回`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 ``` 正如上面例子表明,一个`tsquery`不仅仅是原文本,更多的是一个`tsvector`。一个包含搜索条件的`tsquery`, 必须是已经标准化的词,并且可能使用AND, OR, 和 NOT操作符连接多个术语(详情请见[Section 8.11](#calibre_link-1007))。 函数`to_tsquery`和`plainto_tsquery`在将用户书写文本转换成一个合适的`tsquery`是非常有帮助的。 比如通过标准化文本中的词。类似的,`to_tsvector`用于解析和标准化文档字符串。因此在实践中文本搜索匹配 可能看起来更像这样: ``` SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat'); ?column? ---------- t ``` 观察这个匹配可能不会成功,如果写成这样: ``` SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat'); ?column? ---------- f ``` 由于这儿没有发生词`rats`的标准化。一个`tsvector`的元素是词,假设已经被标准化,所以`rats`不匹配`rat`。 `@@`操作符也支持`text`输入,允许一个文本字符串的显示转换为`tsvector`或者在简单情况下忽略`tsquery`。 可用形式是: ``` tsvector @@ tsquery tsquery @@ tsvector text @@ tsquery text @@ text ``` 我们已经看到了前面两种,形式 `text` `@@` `tsquery`等价于`to_tsvector(x) @@ y`。`text` `@@` `text`等价于 `to_tsvector(x) @@ plainto_tsquery(y)`。 ## 12.1.3\. 配置 上面是所有简单文本搜索例子。如前所述,全文搜索功能还有能力做更多事情:忽略索引某个词(屏蔽词), 过程同义词和使用复杂解析,比如:不仅仅基于空白格的解析。这些功能通过_文本搜索配置_控制。 PostgreSQL来自多语言的预先定义的配置,并且你也可以很容易的创建你自己的配置(psql的`\dF` 命令显示了 所有可用配置)。 在安装期间选择一个合适的配置,并且在`postgresql.conf`中相应的设置[default_text_search_config](#calibre_link-1138)。 如果为了整个集群使用同一个文本搜索配置你可以使用`postgresql.conf`中的值。为了在集群中使用不同配置,但是在任何其他一个数据库的同一 配置中使用`ALTER DATABASE ... SET`。否则,你可以在每个会话中设置`default_text_search_config`。 每个依赖于配置的文本搜索函数有一个可选的`regconfig`参数,因此可以明确声明使用的配置。 仅当忽略这些参数的时候,才使用`default_text_search_config`。 为了更方便的建立自定义文本搜索配置,从简单的数据库对象中建立了配置。 PostgreSQL文本搜索功能提供了四种类型的配置相关的数据库对象: * _文本搜索解析器_打破文档标记,并且分类每个标记(比如,词和数字)。 * _文本搜索词典_把标记转换成规范格式并且拒绝屏蔽词。 * _文本搜索模板_提供潜在的词典功能(一个词典简单的指定一个模板,并且为模板设置参数)。 * _文本搜索配置_选择一个解析器,并且使用一系列词典规范化语法分析器产生的标记。 文本搜索解析器和模板是从低层次的C函数建立的;因此它需要C程序能力开发新产品, 并且需要超级用户权限安装到数据库中(在PostgreSQL发布的`contrib/`范围内有附加解析器和模板的实例)。 因为词典和配置仅仅参数化并且连接到一些潜在的解析器和模板上,创建一个新的词典或者配置不需要特定的权限。 创建自定义词典和配置实例出现在本章节的后面。