【发布时间】:2013-02-14 15:55:55
【问题描述】:
我试图了解fieldNorm 是如何计算的(在索引时),然后在查询时使用(并且显然是重新计算)。
在所有示例中,我使用的是没有停用词的 StandardAnalyzer。
在索引内容时调试 DefaultSimilarity 的 computeNorm 方法,我注意到它返回了 2 个特定文档:
- 文档 A 为 0.5(其字段中有 4 个标记)
- 0.70710677 用于文档 B(其字段中有 2 个标记)
它通过使用公式来做到这一点:
state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
boost 始终为 1
之后,当我查询这些文档时,我看到在查询说明中我得到了
-
0.5 = fieldNorm(field=titre, doc=0)用于文档 A -
0.625 = fieldNorm(field=titre, doc=1)用于文档 B
这已经很奇怪了(对我来说,我确定是我错过了一些东西)。为什么我得到的字段规范值与索引时计算的值不同?这是正在实施的“查询规范化”吗?如果是这样,它是如何工作的?
但这或多或少是可以的,因为两个查询时 fieldNorm 的顺序与索引时计算的顺序相同(在这两种情况下,值较短的字段具有较高的 fieldNorm)
然后我创建了自己的 Similarity 类,在其中实现了 computeNorms 方法,如下所示:
public float computeNorm(String pField, FieldInvertState state) {
norm = (float) (state.getBoost() + (1.0d / Math.sqrt(state.getLength())));
return norm;
}
在索引时间我现在得到:
- 文档 A 为 1.5(其字段中有 4 个标记)
- 1.7071068 用于文档 B(其字段中有 2 个标记)
但是现在,当我查询这些文档时,我可以看到它们都具有与解释函数报告的相同的字段规范:
-
1.5 = fieldNorm(field=titre, doc=0)用于文档 A -
1.5 = fieldNorm(field=titre, doc=1)用于文档 B
对我来说,现在这真的很奇怪,如果我在索引时使用一个明显很好的相似性来计算 fieldNorm,这给了我与令牌数量成正比的正确值,稍后,在查询时,所有这些丢失并且查询说两个文档具有相同的字段规范?
所以我的问题是:
- 为什么 Similarity 的 computeNorm 方法报告的索引时间 fieldNorm 与查询说明报告的不一样?
- 为什么,对于在索引时获得的两个不同 fieldNorm 值(通过相似度计算标准),我在查询时得到相同的 fieldNorm 值?
== 更新
好的,我在 Lucene's docs 中找到了一些东西,它澄清了我的一些问题,但不是全部:
但是,生成的规范值在存储之前被编码为单个字节。在搜索时,从索引目录中读取标准字节值并将其解码回浮点标准值。这种编码/解码虽然减少了索引大小,但也带来了精度损失——不能保证 decode(encode(x)) = x。例如,decode(encode(0.89)) = 0.75.
有多少精度损失?我们应该在不同的值之间设置一个最小差距,以便即使在重新计算精度损失后它们仍然保持不同?
【问题讨论】: