本页介绍了如何对 Spanner 中的全文搜索的搜索结果进行排名。
Spanner 支持计算主题相关性得分,这为创建复杂的排名函数提供了构建块。这些得分会根据查询字词频率和其他可自定义选项来计算结果与查询的相关性。
以下示例显示了带有排名的搜索结果:
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY SCORE(AlbumTitle_Tokens, "fifth symphony") DESC
使用 SCORE
函数为查询字词评分
SCORE
函数会为每个查询字词计算一个得分,然后将这些得分组合起来。每个字词的分数大致基于术语频率 - 逆向文档频率 (TF/IDF) 计算得出。该得分是记录最终排序的组成部分之一。该查询会将其与其他信号(例如用于调节主题性得分的最新性)相结合。
在当前实现中,只有在使用 enhance_query=>true
时,TF/IDF 的 IDF 部分才可用。它根据 Google 搜索使用的完整网页语料库(而非特定搜索索引)计算字词的相对频率。如果未启用 rquery 增强功能,则评分仅使用字词频率 (TF) 组件(即 IDF 字词设置为 1)。
SCORE
函数会返回值,这些值用作相关性得分,Spanner 会使用这些得分来确定排序顺序。它们没有独立含义。得分越高,与查询的匹配度就越高。
通常,SEARCH
和 SCORE
函数中的 query
和 enhance_query
等参数相同,以确保检索和排名的一致性。
建议的方法是将这些参数与查询参数(而非字符串字面量)搭配使用,并在 SEARCH
和 SCORE
函数中指定相同的查询参数。
为多列评分
Spanner 使用 SCORE
函数分别为每个字段评分。然后,查询会将这些单独的得分合并在一起。常见的方法是将各个得分相加,然后根据用户提供的字段权重(使用 SQL 查询参数提供)对得分进行提升。
例如,以下查询会组合两个 SCORE
函数的输出:
SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) AND SEARCH(Studio_Tokens, @p2)
ORDER BY SCORE(Title_Tokens, @p1) * @titleweight + SCORE(Studio_Tokens, @p2) * @studioweight
LIMIT 25
以下示例添加了两个提升参数:
- 新鲜度 (
FreshnessBoost
) 会按(1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30)
提高得分 - “热门程度”(
PopularityBoost
) 会将得分乘以系数(1 + IF(HasGrammy, @grammyweight, 0)
来提高得分。
为方便阅读,该查询使用了 WITH
运算符。
SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) AND SEARCH(Studio_Tokens, @p2)
ORDER BY WITH(
TitleScore AS SCORE(Title_Tokens, @p1) * @titleweight,
StudioScore AS SCORE(Studio_Tokens, @p2) * @studioweight,
DaysOld AS (UNIX_MICROS(CURRENT_TIMESTAMP()) - ReleaseTimestamp) / 8.64e+10,
FreshnessBoost AS (1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30),
PopularityBoost AS (1 + IF(HasGrammy, @grammyweight, 0)),
(TitleScore + StudioScore) * FreshnessBoost * PopularityBoost)
LIMIT 25
TOKENLIST_CONCAT
还可用于搜索和评分,以便在适当情况下简化查询:
SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
ORDER BY SCORE(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
LIMIT 25
提升查询顺序匹配分值
对于包含查询字词且与查询中字词出现顺序相同的值,您可以对其主题相关性得分应用乘法提升。这种提升效果有两个版本:部分匹配和完全匹配。在以下情况下,系统会应用部分匹配加权:
TOKENLIST
包含查询中的所有原始字词。- 令牌彼此相邻,并且与在查询中显示的顺序相同。
连接词、否定词和短语有一些特殊规则:
- 包含否定词的查询无法获得部分匹配加权。
- 如果析取运算的一部分出现在适当的位置,则包含析取运算的查询会获得加权。
- 如果包含某个词组的查询中的词组出现在
TOKENLIST
中,并且查询中该词组左侧的字词也出现在TOKENLIST
中该词组左侧,并且该词组右侧的字词也出现在TOKENLIST
中该词组右侧,则该查询会获得权重提升。
当所有先前规则均为 true 时,Spanner 会应用完全匹配加权。查询中的第一个和最后一个令牌是文档中的第一个和最后一个令牌。
文档示例:Bridge Over Troubled Water
查询 | 已应用的提升 |
---|---|
Bridge Troubled | 无提升 |
桥梁 - 其他水域 | 无提升 |
桥梁(跨越或在湍急水域) | 无提升 |
Bridge Over | 部分提升 |
桥梁(水流湍急或水面) | 部分提升 |
Bridge Over Troubled Water | 完全提升 |
横跨“动荡”水域的桥 | 完全增强 |
桥(“Over Troubled”或 missingterm)水 | 完全提升 |
限制检索深度
搜索索引通常包含数百万个文档。对于谓词选择性较低的查询,对所有结果进行排名并不切实。评分查询通常有两个限制:
- 检索深度限制:要为其评分的最大行数。
- 结果集大小限制:查询应返回的行数上限(通常是页面大小)。
查询可以使用 SQL 子查询限制检索深度:
SELECT *
FROM (
SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1)
ORDER BY ReleaseTimestamp DESC
LIMIT @retrieval_limit
)
ORDER BY SCORE(Title_Tokens, @p1)
LIMIT @page_size
如果 Spanner 使用最重要的排名信号对索引进行排序,这种方法尤为有效。
后续步骤
- 了解全文搜索查询。
- 了解如何执行子字符串搜索。
- 了解如何对搜索结果进行分页。
- 了解如何混合使用全文查询和非文本查询。
- 了解如何搜索多个列。