Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103550864
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-21 15:07:57

From PgsqlWiki

Jump to: ,

 介绍

全文搜索(或者说是文本搜索)提供了一种可以标识满足某个查询的自然语言文档的能力,并且还可以根据文档的相关性对文档进行排序。最常见的搜索是找出所有包含给出的查询词的文档,并且以它们和查询的相似性的顺序输出。查询和相似性的概念相当灵活,并且和具体的应用有关。最简单的搜索认为查询是一组词的集合,相似性是文档中查询词出现的频率。

文本搜索操作符在数据库里的存在已经有很多年了。PostgreSQL 有 ~,~*,LIKE,和 ILIKE 操作符用于文本数据类型,但是它们缺乏许多现代的信息系统需要的重要功能:

  • 没有语言支持,甚至英语也不支持。正则表达式是不够用的,因为它们无法很容易地处理衍生的词,比如,satisfies 和 satisfy。在搜索 satisfy 的时候,你可能会失去包含 satisfies 的文档,但你实际上是希望能找到的。我们可以使用 OR 来搜索多个派生出来的形式,但是这个事情肯定是很枯燥并且很容易出错的(有些词可能会有上千个派生词)。
  • 它们对不提供搜索叫诶过的排序(ranking),这样的话,在找到上千个匹配文档的时候,就不够高效了。
  • 因为它们没有索引支持,所以它们会比较慢,因此它们必须为每个查询都处理所有的文档。

全文索引允许我们可以对文档进行预处理并且可以保存一个事后可以用于快速搜索的索引。预处理包括:

  • 把文档分析成记号。标识出不同类别的记号是很有用的,比如,数字,词,复杂的词,电子邮件地址等等,这样就可以用不同的方法来处理它们。实际上记号分类取决约具体的应用,但是对于大多数用途来说,使用一个预定义的类别集合就足够了。PostgreSQL 使用了一个分析器来执行这个步骤。PostgreSQL 提供了一个标准的分析器,用户也可以为特殊用途创建客户化的分析器。
  • 把记号转换成语意。语意是一个字串,和记号很像,但是它已经是一般化了的,这样同一个词的不同形式就可以一样来处理。比如,一般化通常都会包括把大写转换成小写,并且通常会包括删除后缀(比如在英语里的 s 或者 es)。这样就可以让搜索去寻找同一个词的不同的形式,而不用枯燥地输入所有可能的变种。还有,这一步通常会删除屏蔽词,屏蔽词是那些出现得太过频繁而没有搜索价值的词。(简单说就是,记号是文档文本的裸片段,而语意是被认为对索引和搜索有用的词。)PostgreSQL 使用词典来执行这个步骤。提供了许多标准的词典,并且我们可以为特殊的用途创建客户化的词典。
  • 把预处理后的文档以便于搜索的方式存储。比如,每个文档可以表现为一个一般化之后的语意的有序数组。和语意一起的通常还有用于近似相关性的位置信息的存储,这样一个包含更“密集”的查询词的区域就可以赋予比那些分散的查询词更高的相关性。

词典允许对如何对记号进行一般化处理有更细粒度的控制。使用合适的词典,我们就可以:

  • 定义不应该索引的屏蔽词。
  • 使用 Ispell 把同义词定义成一个词。
  • 使用 thesaurus 把一个短语映射成一个词。
  • 使用 Ispell 词典将一个词的不同变种映射成一个规范的形式。
  • 使用 Snowball 词根规则把一个词的不同变种映射成一个规范的形式。

提供了一个数据类型 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;
注意:实际上,在这个简单的查询里,必须使用联合以避免一个 NULL 属性导致整个文档的 NULL 结果。

另外一个可能是把文档以简单的文本文件的形式存储在文件系统里。在这种场合下,数据库可以用于存储全文索引并且执行搜索,然后可以用一个唯一标识来从文件系统中检索文档。不过,从数据库外面检索文件要求(数据库)超级用户权限或者是一些特殊的函数支持,所以相比之下,通常把所有数据保存在 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/ 里面有一些附加分析器和模板的例子。)因为字典和配置只是参数和一些下层的分析器和模板的组合,所以创建新的字典或者配置不需要特殊的权限。创建客户化字典和配置的例子在本章后面出现。

取自""
阅读(1575) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~