评分文档
全文评分函数
搜索时,文档的评分基于其与查询的相关性。分数是一个介于 0.0 和 1.0 之间的浮点数,其中 1.0 是最高分数。分数作为搜索结果的一部分返回,可用于对结果进行排序。
Redis Stack 提供了一些非常基本的评分函数来评估文档的相关性。它们都基于文档得分和词频。这与使用可排序字段的能力无关。评分函数通过在搜索查询中添加 SCORER {scorer_name}
参数来指定。
如果您更喜欢自定义评分函数,可以使用扩展 API添加更多函数。
以下是 Redis Stack 中提供的预捆绑评分函数列表及其工作原理的简要说明。每个函数都以注册名称提及,可以作为 SCORER
参数传递给FT.SEARCH
。
TFIDF(默认)
基本的TF-IDF 评分,并具有一些额外的功能。
-
对于每个结果中的每个词语,计算该词语对该文档的 TF-IDF 分数。频率根据预先确定的字段权重进行加权,每个词语的频率通过每个文档中最高的词语频率进行归一化。
-
查询词语的总 TF-IDF 乘以通过
SCORE_FIELD
在FT.CREATE
上给出的推定文档得分。 -
根据搜索词语之间的“slop”或累积距离,对每个结果分配一个惩罚。精确匹配将不会受到惩罚,但搜索词语距离较远的匹配将显著降低其分数。对于每个连续词语的二元组,确定它们之间的最小距离。惩罚是距离平方和的平方根;例如,
1/sqrt(d(t2-t1)^2 + d(t3-t2)^2 + ...)
。
假设文档 D 中有 N 个词语,T1...Tn
,则结果得分可以用以下 Python 函数描述。
def get_score(terms, doc):
# the sum of tf-idf
score = 0
# the distance penalty for all terms
dist_penalty = 0
for i, term in enumerate(terms):
# tf normalized by maximum frequency
tf = doc.freq(term) / doc.max_freq
# idf is global for the index, and not calculated each time in real life
idf = log2(1 + total_docs / docs_with_term(term))
score += tf*idf
# sum up the distance penalty
if i > 0:
dist_penalty += min_distance(term, terms[i-1])**2
# multiply the score by the document score
score *= doc.score
# divide the score by the root of the cumulative distance
if len(terms) > 1:
score /= sqrt(dist_penalty)
return score
TFIDF.DOCNORM
与默认的 TFIDF
评分器相同,但有一个重要的区别。
词语频率通过文档长度进行归一化,文档长度表示词语总数。长度是加权的,因此如果文档包含两个词语,一个在权重为 1 的字段中,另一个在权重为 5 的字段中,则总频率为 6,而不是 2。
FT.SEARCH myIndex "foo" SCORER TFIDF.DOCNORM
BM25
基本 TFIDF
评分器的变体,请参阅维基百科文章以了解更多信息。
每个文档的相关性得分乘以推定文档得分,并根据 TFIDF
中的 slop 应用惩罚。
FT.SEARCH myIndex "foo" SCORER BM25
DISMAX
一个简单的评分器,它将匹配词语的频率加起来。在联合子句的情况下,它将给出这些匹配的最大值。没有应用其他惩罚或因素。
它不是Solr 的 DISMAX 算法的逐一实现,但它在广义上遵循该算法。
FT.SEARCH myIndex "foo" SCORER DISMAX
DOCSCORE
一个评分函数,它只返回文档的推定得分,而不对其应用任何计算。由于文档得分可以更新,因此如果您想使用外部得分而不做任何其他操作,这将非常有用。
FT.SEARCH myIndex "foo" SCORER DOCSCORE
HAMMING
通过文档有效负载与查询有效负载之间的反向汉明距离进行评分。由于最邻近的邻居是最重要的,因此使用反向汉明距离(1/(1+d)
),这样距离为 0 就会得到 1 的完美得分,并且排名最高。
这只有在以下情况下才有效
- 文档具有有效负载。
- 查询具有有效负载。
- 两者完全相同长度。
有效负载是二进制安全的,并且具有长度为 64 位倍数的有效负载会产生稍微更快的结果。
示例
> HSET key:1 foo hello payload aaaabbbb
(integer) 2
> HSET key:2 foo bar payload aaaacccc
(integer) 2
> FT.CREATE idx ON HASH PREFIX 1 key: PAYLOAD_FIELD payload SCHEMA foo TEXT
"OK"
> FT.SEARCH idx "*" PAYLOAD "aaaabbbc" SCORER HAMMING WITHSCORES
1) "2"
2) "key:1"
3) "0.5"
4) 1) "foo"
2) "hello"
5) "key:2"
6) "0.25"
7) 1) "foo"
2) "bar"