分类:
2008-05-21 15:07:57
全文搜索(或者说是文本搜索)提供了一种可以标识满足某个查询的自然语言文档的能力,并且还可以根据文档的相关性对文档进行排序。最常见的搜索是找出所有包含给出的查询词的文档,并且以它们和查询的相似性的顺序输出。查询和相似性的概念相当灵活,并且和具体的应用有关。最简单的搜索认为查询是一组词的集合,相似性是文档中查询词出现的频率。
文本搜索操作符在数据库里的存在已经有很多年了。PostgreSQL 有 ~,~*,LIKE,和 ILIKE 操作符用于文本数据类型,但是它们缺乏许多现代的信息系统需要的重要功能:
全文索引允许我们可以对文档进行预处理并且可以保存一个事后可以用于快速搜索的索引。预处理包括:
词典允许对如何对记号进行一般化处理有更细粒度的控制。使用合适的词典,我们就可以:
提供了一个数据类型 tsvector 用于存储预处理后的文档,还提供了一个 tsquery 类型用于代表查询()。这些数据类型上有很多函数和操作符可用(),最重要的是匹配操作符 @@,我们在。全文搜索可以通过使用索引加速()。
文档是全文搜索系统里面的搜索的单位;比如,一篇杂志的文章或者一个电子邮件的信息。文本搜索引擎必须能够分析文档并且存储与父文档相关的语意(关键词)。然后,这些关联用于搜索包含查询词的文档。
在 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;
另外一个可能是把文档以简单的文本文件的形式存储在文件系统里。在这种场合下,数据库可以用于存储全文索引并且执行搜索,然后可以用一个唯一标识来从文件系统中检索文档。不过,从数据库外面检索文件要求(数据库)超级用户权限或者是一些特殊的函数支持,所以相比之下,通常把所有数据保存在 PostgreSQL 里面是最方便的。还有,把所有东西都保存在数据库里也让我们很容易访问文档的元数据以帮助索引和现实。
为了使用文本搜索,每个文档都必须缩减成预处理过的 tsvector 格式。搜索和相关性完全都是在文档的 tsvector 形式上进行的 -- 原始的文档只有在需要给用户显示的事后才需要检索。所以,我们通常直接把 tsvector 当做文档,当然了,它其实只是一个完整文档的紧凑表现形式。
PostgreSQL 的全文搜索是基于匹配操作符 @@,如果一个 tsvector(文档)匹配一个 tsquery(查询),它就返回真。哪个数据类型写在前头并无所谓:
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操作符组合起来。(细节参阅。)有两个函数 to_tsquery 和 plainto_tsquery 可以帮助把用户写的 text 转换成合适的 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 输入,允许在简单情况下省略 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)。
上面的都是简单文本的搜索例子。如我们前面说过的,全文搜索的功能包括做更多事情的能力:忽略对某些词的索引(屏蔽词),处理同义词,以及使用复杂的词法分析等。比如,不仅仅基于空白的分词。这些功能是通过文本搜索的配置控制的。PostgreSQL 对许多语言带着许多预定义的配置,并且我们可以很容易地创建自己的配置。(psql的\dF命令显示所有可用的配置。)
在安装的过程中,初始化脚本会选择一个合适的配置,并且会把 postgresql.conf 里面的 default_text_search_config 设置为该值。如果你在整个集群使用了同样的文本搜索配置,那么你可以使用 postgresql.conf 里面的值。要在集群里使用不同的配置,而又要在任何一个数据库里使用同样的配置,那么使用 ALTER DATABASE ... SET。或者,你在每个会话里设置 default_text_search_config。
每个以来于某个配置的文本搜索函数都有一个可选的 regconfig 参数,这样就可以明确地使用该配置。只有在省略这个参数的时候才使用default_text_search_config。
为了让我们可以很容易制作客户化的文本搜索配置,配置是从更简单的数据库对象上制作的。PostgreSQL 的文本搜索功能提供四种配置相关的数据库对象:
文本搜索分析器和末班都是在底层的 C 函数的基础上制作的;因此,如果我们需要开发一个新的,就需要 C 编程能力,并且需要超级用户权限把他们安装到一个数据库里。(在PostgreSQL源代码的 contrib/ 里面有一些附加分析器和模板的例子。)因为字典和配置只是参数和一些下层的分析器和模板的组合,所以创建新的字典或者配置不需要特殊的权限。创建客户化字典和配置的例子在本章后面出现。