PostgreSQL 10.1 手册_部分 II. SQL 语言_第 12 章 全文搜索_12.1. 介绍

简介: 12.1. 介绍 12.1.1. 什么是一个文档? 12.1.2. 基本文本匹配 12.1.3. 配置 全文搜索(或者文本搜索)提供了确定满足一个查询的自然语言文档的能力,并可以选择将它们按照与查询的相关度排序。

12.1. 介绍

全文搜索(或者文本搜索)提供了确定满足一个查询的自然语言文档的能力,并可以选择将它们按照与查询的相关度排序。最常用的搜索类型是找到所有包含给定查询词的文档并按照它们与查询的相似性顺序返回它们。查询相似性的概念非常灵活并且依赖于特定的应用。最简单的搜索认为查询是一组词而相似性是查询词在文档中的频度。

文本搜索操作符已经在数据库中存在很多年了。PostgreSQL对文本数据类型提供了~~*LIKEILIKE操作符,但是它们缺少现代信息系统所要求的很多基本属性:

  • 即使对英语也缺乏语言的支持。正则表达式是不够的,因为它们不能很容易地处理派生词,例如satisfiessatisfy。你可能会错过包含satisfies的文档,尽管你可能想要在对于satisfy的搜索中找到它们。可以使用OR来搜索多个派生形式,但是这样做太罗嗦也容易出错(有些词可能有数千种派生)。

  • 它们不提供对搜索结果的排序(排名),这使它们面对数以千计被找到的文档时变得无效。

  • 它们很慢因为没有索引支持,因此它们必须为每次搜索处理所有的文档。

全文索引允许文档被预处理并且保存一个索引用于以后快速的搜索。预处理包括:

  • 将文档解析成记号。标识出多种类型的记号是有所帮助的,例如数字、词、复杂的词、电子邮件地址,这样它们可以被以不同的方式处理。原则上记号分类取决于相关的应用,但是对于大部分目的都可以使用一套预定义的分类。PostgreSQL使用一个解析器来执行这个步骤。其中提供了一个标准的解析器,并且为特定的需要也可以创建定制的解析器。

  • 将记号转换成词位。和一个记号一样,一个词位是一个字符串,但是它已经被正规化,这样同一个词的不同形式被变成一样。例如,正规化几乎总是包括将大写字母转换成小写形式,并且经常涉及移除后缀(例如英语中的ses)。这允许搜索找到同一个词的变体形式,而不需要冗长地输入所有可能的变体。此外,这个步骤通常会消除停用词,它们是那些太普通的词,它们对于搜索是无用的(简而言之,记号是文档文本的原始片段,而词位是那些被认为对索引和搜索有用的词)。PostgreSQL使用词典来执行这个步骤。已经提供了多种标准词典,并且为特定的需要也可以创建定制的词典。

  • 为搜索优化存储预处理好的文档。例如,每一个文档可以被表示为正规化的词位的一个有序数组。与词位一起,通常还想要存储用于近似排名的位置信息,这样一个包含查询词更密集区域的文档要比那些包含分散的查询词的文档有更高的排名。

词典允许对记号如何被正规化进行细粒度的控制。使用合适的词典,你可以:

  • 定义不应该被索引的停用词。

  • 使用Ispell把同义词映射到一个单一词。

  • 使用一个分类词典把短语映射到一个单一词。

  • 使用一个Ispell词典把一个词的不同变体映射到一种规范的形式。

  • 使用Snowball词干分析器规则将一个词的不同变体映射到一种规范的形式。

我们提供了一种数据类型tsvector来存储预处理后的文档,还提供了一种类型tsquery来表示处理过的查询(第 8.11 节)。有很多函数和操作符可以用于这些数据类型(第 9.13 节),其中最重要的是匹配操作符@@,它在第 12.1.2 节中介绍。全文搜索可以使用索引来加速(第 12.9 节)。

12.1.1. 什么是一个文档?

一个document是在一个全文搜索系统中进行搜索的单元,例如,一篇杂志文章或电子邮件消息。文本搜索引擎必须能够解析文档并存储词位(关键词)与它们的父文档之间的关联。随后,这些关联会被用来搜索包含查询词的文档。

对于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;

注意

实际上在这些例子查询中,coalesce应该被用来防止一个单一NULL属性导致整个文档的一个NULL结果。

另一种存储文档的可能性是作为文件系统中的简单文本文件。在这种情况下,数据库可以被用来存储全文索引并执行搜索,并且某些唯一标识符可以被用来从文件系统检索文档。但是,从数据库的外面检索文件要求超级用户权限或者特殊函数支持,因此这种方法通常不如把所有数据放在PostgreSQL内部方便。另外,把所有东西放在数据库内部允许方便地访问文档元数据来协助索引和现实。

对于文本搜索目的,每一个文档必须被缩减成预处理后的tsvector格式。搜索和排名被整个在一个文档的tsvector表示上执行 — 只有当文档被选择来显示给用户时才需要检索原始文本。我们因此经常把tsvector说成是文档,但是当然它只是完整文档的一种紧凑表示。

12.1.2. 基本文本匹配

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

正如以上例子所建议的,一个tsquery并不只是一个未经处理的文本, 顶多一个tsvector是这样。一个tsquery包含搜索术语, 它们必须是已经正规化的词位,并且可以使用 AND 、OR、NOT 以及 FOLLOWED BY 操作符结合多个术语 (语法细节请见第 8.11.2 节)。有几个函数to_tsqueryplainto_tsquery以及phraseto_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输出,它允许在简单情况下跳过从文本字符串到tsvectortsquery的显式转换。可用的变体是:

tsvector @@ tsquery
tsquery  @@ tsvector
text @@ tsquery
text @@ text

前两种我们已经见过。形式text @@ tsquery等价于to_tsvector(x) @@ y。形式text @@ text等价于to_tsvector(x) @@ plainto_tsquery(y)

tsquery中,&(AND)操作符指定它的两个参数都必须出现在文档中才表示匹配。类似地,|(OR)操作符指定至少一个参数必须出现,而!(NOT)操作符指定它的参数出现才能匹配。 例如,查询fat & ! rat匹配包含fat但是不包含 rat的文档。

<->(FOLLOWED BY) tsquery操作符的帮助下搜索可能的短语,只有该操作符的参数的匹配是相邻的并且符合给定顺序时,该操作符才算是匹配。例如:

SELECT to_tsvector('fatal error') @@ to_tsquery('fatal <-> error');
 ?column? 
----------
 t

SELECT to_tsvector('error is not fatal') @@ to_tsquery('fatal <-> error');
 ?column? 
----------
 f

FOLLOWED BY 操作符还有一种更一般的版本,形式是<N>,其中N是一个表示匹配词位位置之间的差。<1><->相同,而<2>允许刚好一个其他词位出现在匹配之间,以此类推。当有些词是停用词时,phraseto_tsquery函数利用这个操作符来构造一个能够匹配多词短语的tsquery。例如:

SELECT phraseto_tsquery('cats ate rats');
       phraseto_tsquery        
-------------------------------
 'cat' <-> 'ate' <-> 'rat'

SELECT phraseto_tsquery('the cats ate the rats');
       phraseto_tsquery        
-------------------------------
 'cat' <-> 'ate' <2> 'rat'

一种有时候有用的特殊情况是,<0>可以被用来要求两个匹配同一个词的模式。

圆括号可以被用来控制tsquery操作符的嵌套。如果没有圆括号,|的计算优先级最低,然后从低到高依次是&<->!

值得注意的是,AND/OR/NOT运算符意味着当它们在FOLLOWED BY运算符的参数范围内, 与它们没有在范围内的时候有细微的不同,因为在FOLLOWED BY中,匹配的确切位置是很重要的。 例如,通常!x仅匹配不包含x的文档。但是,如果不是紧跟在x之后, 那么!x <-> y匹配y;文档中其他地方出现的x并不妨碍匹配。 另一个例子是x & y通常只要求xy都出现在文档的某处, 但是(x & y) <-> z要求xy匹配在z 之前的相同位置。因此,这个查询的行为不同于x <-> z & y <-> z, 它将与包含两个单独的序列x zy z的文档相匹配。 (由于xy无法在相同位置匹配,因此此特定查询没有任何用处; 但是在更复杂的情况下(如前缀匹配模式),此形式的查询可能会有用。)

12.1.3. 配置

前述的都是简单的文本搜索例子。正如前面所提到的,全文搜索功能包括做更多事情的能力:跳过索引特定词(停用词)、处理同义词并使用更高级的解析,例如基于空白之外的解析。这个功能由文本搜索配置控制。PostgreSQL中有多种语言的预定义配置,并且你可以很容易地创建你自己的配置(psql\dF命令显示所有可用的配置)。

在安装期间一个合适的配置将被选择并且default_text_search_config也被相应地设置在postgresql.conf中。如果你正在对整个集簇使用相同的文本搜索配置,你可以使用在postgresql.conf中使用该值。要在集簇中使用不同的配置但是在任何一个数据库内部使用同一种配置,使用ALTER DATABASE ... SET。否则,你可以在每个会话中设置default_text_search_config

依赖一个配置的每一个文本搜索函数都有一个可选的regconfig参数,因此要使用的配置可以被显式指定。只有当这个参数被忽略时,default_text_search_config才被使用。

为了让建立自定义文本搜索配置更容易,一个配置可以从更简单的数据库对象来建立。PostgreSQL的文本搜索功能提供了四类配置相关的数据库对象:

  • 文本搜索解析器将文档拆分成记号并分类每个记号(例如,作为词或者数字)。

  • 文本搜索词典将记号转变成正规化的形式并拒绝停用词。

  • 文本搜索模板提供位于词典底层的函数(一个词典简单地指定一个模板和一组用于模板的参数)。

  • 文本搜索配置选择一个解析器和一组用于将解析器产生的记号正规化的词典。

文本搜索解析器和模板是从低层 C 函数构建而来,因此它要求 C 编程能力来开发新的解析器和模板,并且还需要超级用户权限来把它们安装到一个数据库中(在PostgreSQL发布的contrib/区域中有一些附加的解析器和模板的例子)。由于词典和配置只是对底层解析器和模板的参数化和连接,不需要特殊的权限来创建一个新词典或配置。创建定制词典和配置的例子将在本章稍后的部分给出。

本文转自PostgreSQL中文社区,原文链接:12.1. 介绍

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
10月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1593 152
|
10月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
1106 156
|
SQL 关系型数据库 MySQL
Go语言数据库编程:使用 `database/sql` 与 MySQL/PostgreSQL
Go语言通过`database/sql`标准库提供统一数据库操作接口,支持MySQL、PostgreSQL等多种数据库。本文介绍了驱动安装、连接数据库、基本增删改查操作、预处理语句、事务处理及错误管理等内容,涵盖实际开发中常用的技巧与注意事项,适合快速掌握Go语言数据库编程基础。
1579 213
|
10月前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
916 5
|
存储 关系型数据库 测试技术
拯救海量数据:PostgreSQL分区表性能优化实战手册(附压测对比)
本文深入解析PostgreSQL分区表的核心原理与优化策略,涵盖性能痛点、实战案例及压测对比。首先阐述分区表作为继承表+路由规则的逻辑封装,分析分区裁剪失效、全局索引膨胀和VACUUM堆积三大性能杀手,并通过电商订单表崩溃事件说明旧分区维护的重要性。接着提出四维设计法优化分区策略,包括时间范围分区黄金法则与自动化维护体系。同时对比局部索引与全局索引性能,展示后者在特定场景下的优势。进一步探讨并行查询优化、冷热数据分层存储及故障复盘,解决分区锁竞争问题。
1768 2
|
SQL 关系型数据库 PostgreSQL
CTE vs 子查询:深入拆解PostgreSQL复杂SQL的隐藏性能差异
本文深入探讨了PostgreSQL中CTE(公共表表达式)与子查询的选择对SQL性能的影响。通过分析两者底层机制,揭示CTE的物化特性及子查询的优化融合优势,并结合多场景案例对比执行效率。最终给出决策指南,帮助开发者根据数据量、引用次数和复杂度选择最优方案,同时提供高级优化技巧和版本演进建议,助力SQL性能调优。
1469 1
|
SQL 关系型数据库 OLAP
云原生数据仓库AnalyticDB PostgreSQL同一个SQL可以实现向量索引、全文索引GIN、普通索引BTREE混合查询,简化业务实现逻辑、提升查询性能
本文档介绍了如何在AnalyticDB for PostgreSQL中创建表、向量索引及混合检索的实现步骤。主要内容包括:创建`articles`表并设置向量存储格式,创建ANN向量索引,为表增加`username`和`time`列,建立BTREE索引和GIN全文检索索引,并展示了查询结果。参考文档提供了详细的SQL语句和配置说明。
674 2
|
关系型数据库 数据库 PostgreSQL
使用 PostgreSQL 和 Python 实现全文搜索
【10月更文挑战第2天】使用 PostgreSQL 和 Python 实现全文搜索
350 1
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)

推荐镜像

更多