控制文本搜索
本主题说明如何创建搜索和查询向量,如何对搜索结果进行排名,以及如何在文本搜索查询的结果中突出显示搜索词。
要实现全文搜索,必须有一个函数来从文档创建tsvector和从用户查询创建tsquery。 此外,我们需要以有用的顺序返回结果,因此我们需要一个函数来比较文档与查询的相关性。 能够很好地显示结果也很重要。 Greenplum数据库为所有这些功能提供支持。
本主题包含以下子主题:
解析文件
Greenplum数据库提供了to_tsvector函数,用于将文档转换为tsvector数据类型。
to_tsvector([config regconfig, ] document text) returns tsvector
to_tsvector将文本文档解析为token,将token缩减为词位,并返回一个tsvector,其中列出了词位及其在文档中的位置。 根据指定或默认文本搜索配置处理文档。 这是一个简单的例子:
SELECT to_tsvector('english', 'a fat cat sat on a mat - it ate a fat rats');
to_tsvector
-----------------------------------------------------
'ate':9 'cat':3 'fat':2,11 'mat':7 'rat':12 'sat':4
在上面的例子中,我们看到生成的tsvector不包含单词a,on或it, 单词rats变成rat,标点符号 - 被忽略。
to_tsvector函数在内部调用解析器,该解析器将文档文本分解为token并为每个token分配类型。 对于每个token,查阅字典列表(文本搜索词典),其中列表可以根据token类型而变化。 识别token的第一个字典发出一个或多个规范化的词位来表示token。 例如,rats变成rat,因为其中一个词典认识到单词rats是复数形式的rat。 有些单词被识别为停止词,这会导致它们被忽略,因为它们过于频繁而无法用于搜索。 在我们的例子中,这些是a,on和it。 如果列表中没有字典识别出token,那么它也会被忽略。 在这个标点符号发生的例子中 - 因为实际上没有为其token类型(空间符号)分配字典,这意味着空间token永远不会被索引。 解析器,字典和要索引的token类型的选择由所选文本搜索配置(文本搜索配置示例)确定。 可以在同一数据库中具有许多不同的配置,并且可以为各种语言提供预定义的配置。 在我们的示例中,我们使用英语的默认配置english。
函数setweight可用于标记具有给定权重的tsvector的条目,其中权重是字母A,B,C或D之一。 这通常用于标记来自文档的不同部分的条目,如title与body。 之后,此信息可用于搜索结果的排名。
因为to_tsvector(NULL)将返回NULL,所以只要字段可能为null,建议使用coalesce。 以下是从结构化文档创建tsvector的推荐方法:
UPDATE tt SET ti = setweight(to_tsvector(coalesce(title,'')), 'A')
|| setweight(to_tsvector(coalesce(keyword,'')), 'B')
|| setweight(to_tsvector(coalesce(abstract,'')), 'C')
|| setweight(to_tsvector(coalesce(body,'')), 'D');
这里我们使用setweight标记完成的tsvector中每个词位的来源, 然后使用tsvector连接运算符||合并标记的tsvector值。 (文本搜索附加功能提供有关这些操作的详细信息。)
解析查询
Greenplum数据库提供了to_tsquery和plainto_tsquery函数,用于将查询转换为tsquery数据类型。 to_tsquery提供了比plainto_tsquery更多功能的访问权限,但对其输入的宽容度较低。
to_tsquery([config regconfig, ] querytext text) returns tsquery
to_tsquery从querytext创建一个tsquery值, 该值必须由布尔运算符& (AND), | (OR) 和 !(NOT)分隔的单个token组成。 可以使用括号对这些运算符进行分组。 换句话说,to_tsquery的输入必须已经遵循tsquery输入的一般规则,如全文搜索类型中所述。 不同之处在于,虽然基本的tsquery输入将token置于面值,但to_tsquery使用指定或默认配置将每个token规范化为一个词位,并根据配置丢弃任何停止词的标记。 例如:
SELECT to_tsquery('english', 'The & Fat & Rats');
to_tsquery
---------------
'fat' & 'rat'
与基本的tsquery输入一样,权重可以附加到每个词位,以限制它仅匹配那些权重的tsvector词位。 例如:
SELECT to_tsquery('english', 'Fat | Rats:AB');
to_tsquery
------------------
'fat' | 'rat':AB
此外,*可以附加到词位以指定前缀匹配:
SELECT to_tsquery('supern:*A & star:A*B');
to_tsquery
--------------------------
'supern':*A & 'star':*AB
这样的词位将匹配以给定字符串开头的tsvector中的任何单词。
to_tsquery也可以接受单引号短语。 当配置包括可能触发此类短语的同义词词典时,这是非常有用的。 在下面的例子中,同义词库包含规则supernovae stars : sn:
SELECT to_tsquery('''supernovae stars'' & !crab');
to_tsquery
---------------
'sn' & !'crab'
如果没有引号,to_tsquery将为未被AND或OR运算符分隔的标记生成语法错误。
plainto_tsquery([ config regconfig, ] querytext ext) returns tsquery
plainto_tsquery未格式化的文本querytext转换为tsquery。 对于to_tsvector,文本被解析和规范化,然后在残存的单词之间插入&(AND)布尔运算符。
示例:
SELECT plainto_tsquery('english', 'The Fat Rats');
plainto_tsquery
-----------------
'fat' & 'rat'
请注意,plainto_tsquery无法在其输入中识别布尔运算符,权重标签或前缀匹配标签:
SELECT plainto_tsquery('english', 'The Fat & Rats:C');
plainto_tsquery
---------------------
'fat' & 'rat' & 'c'
这里,所有输入标点符号都被丢弃为空格符号。
排名搜索结果
排名尝试测量相关文档对特定查询的影响,以便在存在多个匹配时,可以首先显示最相关的匹配。 Greenplum数据库提供两个预定义的排名功能,其中考虑了词位,接近度和结构信息; 也就是说,他们会考虑查询term在文档中出现的频率,term在文档中的接近程度,以及文档中出现的部分的重要程度。 然而,相关性的概念是模糊的并且非常特定于应用程序。 不同的应用程序可能需要用于排名的附加信息,例如文档修改时间。 内置排名功能仅是示例。 您可以编写自己的排名功能和/或将其结果与其他因素结合起来,以满足您的特定需求。
目前可用的两个排名功能是:
ts_rank([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4
根据匹配词位的频率对矢量进行排名。
ts_rank_cd([ weights float4[], ] vector tsvector, query tsquery [, normalization integer ]) returns float4
此函数计算给定文档向量和查询的盖度排名,如Clarke,Cormack和Tudhope在1999年的“信息处理和管理”杂志中的“一至三期查询的相关性排名”中所述。 除了考虑到匹配词位之间的接近程度,盖度类似ts_rank排名。
此函数需要词位位置信息来执行其计算。 因此,它忽略了tsvector中的任何“stripped”词位。 如果输入中没有未提取的词位,则结果为零。 (有关tsvector中strip函数和位置信息的更多信息,请参阅操纵文档。)
对于这两个函数,可选的权重参数提供了对字实例进行或多或少权衡的能力,具体取决于它们的标注方式。 权重数组按以下顺序指定对每个单词类别进行称重的程度:
{D-weight, C-weight, B-weight, A-weight}
如果未提供权重,则使用以下默认值:
{0.1, 0.2, 0.4, 1.0}
通常,权重用于标记文档特殊区域中的单词,如标题或初始摘要,因此可以比文档正文中的单词更重要或更不重视它们。
由于较长的文档更有可能包含查询词语,因此考虑文档大小是合理的,例如,具有五个搜索字实例的百字文档可能比具有五个实例的千字文档更相关。 两个排名函数都采用整数规范化选项,该选项指定文档的长度是否以及如何影响其排名。 整数选项控制多个行为,因此它是一个位掩码:您可以使用|指定一个或多个行为(例如,2|4)。
- 0(默认值)忽略文档长度
- 1 将等级除以(1 + 文档长度的对数)
- 2 将等级除以文件长度
- 4 将等级除以范围之间的平均谐波距离(这仅由ts_rank_cd实现)
- 8 将等级除以文档中唯一单词的数量
- 16 将等级除以(1 +文档中唯一字数的对数)
- 32 将等级除以(等级 + 1)
如果指定了多个标志位,则按列出的顺序应用转换。
重要的是要注意,排名函数不使用任何全局信息,因此不可能像有时期望的那样产生1%或100%的公平标准化。 归一化选项32(rank/(rank+1))可用于将所有等级缩放到0到1的范围内,但当然这只是一个表面的变化; 它不会影响搜索结果的排序。
以下示例仅选择排名最高的十个匹配项:
SELECT title, ts_rank_cd(textsearch, query) AS rank
FROM apod, to_tsquery('neutrino|(dark & matter)') query
WHERE query @@ textsearch
ORDER BY rank DESC
LIMIT 10;
title | rank
-----------------------------------------------+----------
Neutrinos in the Sun | 3.1
The Sudbury Neutrino Detector | 2.4
A MACHO View of Galactic Dark Matter | 2.01317
Hot Gas and Dark Matter | 1.91171
The Virgo Cluster: Hot Plasma and Dark Matter | 1.90953
Rafting for Solar Neutrinos | 1.9
NGC 4650A: Strange Galaxy and Dark Matter | 1.85774
Hot Gas and Dark Matter | 1.6123
Ice Fishing for Cosmic Neutrinos | 1.6
Weak Lensing Distorts the Universe | 0.818218
这是使用标准化排名的相同示例:
SELECT title, ts_rank_cd(textsearch, query, 32 /* rank/(rank+1) */ ) AS rank
FROM apod, to_tsquery('neutrino|(dark & matter)') query
WHERE query @@ textsearch
ORDER BY rank DESC
LIMIT 10;
title | rank
-----------------------------------------------+-------------------
Neutrinos in the Sun | 0.756097569485493
The Sudbury Neutrino Detector | 0.705882361190954
A MACHO View of Galactic Dark Matter | 0.668123210574724
Hot Gas and Dark Matter | 0.65655958650282
The Virgo Cluster: Hot Plasma and Dark Matter | 0.656301290640973
Rafting for Solar Neutrinos | 0.655172410958162
NGC 4650A: Strange Galaxy and Dark Matter | 0.650072921219637
Hot Gas and Dark Matter | 0.617195790024749
Ice Fishing for Cosmic Neutrinos | 0.615384618911517
Weak Lensing Distorts the Universe | 0.450010798361481
排名代价可能很高,因为它需要查询每个匹配文档的tsvector,这可能是I/O相关的,因此很慢。 不幸的是,几乎不可能避免,因为实际的查询经常导致大量的匹配。
突出显示结果
要显示搜索结果,最好显示每个文档的一部分以及它与查询的关联方式。 通常,搜索引擎会显示带有标记搜索词的文档片段。 Greenplum数据库提供了一个实现此功能的函数ts_headline。
ts_headline([config regconfig, ] document text, query tsquery [, options text ]) returns text
ts_headline接受文档和查询,并返回文档中的摘录,其中突出显示查询中的术语。 可以通过config指定用于解析文档的配置; 如果省略config,则使用default_text_search_config配置。
如果指定了options字符串,则它必须包含一个或多个逗号分隔的option=value列表对。 可用选项包括:
- StartSel, StopSel: 用于分隔出现在文档中的查询单词的字符串,以区别于其他摘录的单词。 如果这些字符串包含空格或逗号,则必须双引号。
- MaxWords, MinWords: 这些数字决定了输出的最长和最短标题。
- ShortWord: 这个长度或更短的单词将在标题的开头和结尾处删除。 默认值为3消除了常见的英文文章。
- HighlightAll: 布尔标志; 如果为true,则整个文档将用作标题,忽略前面的三个参数。
- MaxFragments: 要显示的最大文本摘要或片段数。 默认值零选择非面向片段的标题生成方法。 大于零的值选择基于片段的标题生成。 此方法查找具有尽可能多的查询字的文本片段,并在查询字周围拉伸这些片段。 结果,查询单词接近每个片段的中间并且每侧都有单词。 每个片段最多为MaxWords,并且在每个片段的开始和结束处删除长度为ShortWord或更短的单词。 如果不是在文档中找到所有查询词,则将显示文档中第一个MinWords的单个片段。
- FragmentDelimiter: 当显示多个片段时,片段将被此字符串分隔。
任何未指定的选项都会收到以下默认值:
StartSel=<b>, StopSel=</b>,
MaxWords=35, MinWords=15, ShortWord=3, HighlightAll=FALSE,
MaxFragments=0, FragmentDelimiter=" ... "
示例:
SELECT ts_headline('english',
'The most common type of search
is to find all documents containing given query terms
and return them in order of their similarity to the
query.',
to_tsquery('query & similarity'));
ts_headline
------------------------------------------------------------
containing given <b>query</b> terms
and return them in order of their <b>similarity</b> to the
<b>query</b>.
SELECT ts_headline('english',
'The most common type of search
is to find all documents containing given query terms
and return them in order of their similarity to the
query.',
to_tsquery('query & similarity'),
'StartSel = <, StopSel = >');
ts_headline
-------------------------------------------------------
containing given <query> terms
and return them in order of their <similarity> to the
<query>.
ts_headline使用原始文档,而不是tsvector摘要,因此它可能很慢,应谨慎使用。 一个典型的错误是当只显示十个文档时,为每个匹配的文档调用ts_headline。 SQL子查询可以提供帮助; 这是一个例子:
SELECT id, ts_headline(body, q), rank
FROM (SELECT id, body, q, ts_rank_cd(ti, q) AS rank
FROM apod, to_tsquery('stars') q
WHERE ti @@ q
ORDER BY rank DESC
LIMIT 10) AS foo;
Parent topic: 使用全文搜索