我试图了解如何fieldNorm
计算(在索引时)然后在查询时使用(并且显然是重新计算)。
在所有示例中,我都使用没有停用词的 StandardAnalyzer。
在索引内容时调试DefaultSimilarity
'computeNorm
方法,我注意到对于 2 个特定文档,它返回:
- 文档 A 为 0.5(其字段中有 4 个标记)
- 文档 B 为 0.70710677(其字段中有 2 个标记)
它通过使用以下公式来做到这一点:
state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
boost 始终为 1
之后,当我查询这些文档时,我看到在查询说明中我得到
0.5 = fieldNorm(field=titre, doc=0)
对于文件 A0.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;
}
在索引时间,我现在得到:
- 1.5 用于文档 A(其字段中有 4 个标记)
- 1.7071068 用于文档 B(其字段中有 2 个标记)
但是现在,当我查询这些文档时,我可以看到它们都具有与 explain 函数报告的相同的字段规范:
1.5 = fieldNorm(field=titre, doc=0)
对于文件 A1.5 = fieldNorm(field=titre, doc=1)
对于文件 B
对我来说,这现在真的很奇怪,如果我在索引时使用一个明显很好的相似性来计算 fieldNorm,这给了我与令牌数量成正比的适当值,后来,在查询时,所有这些都丢失了,怎么办?查询说两个文档具有相同的字段规范?
所以我的问题是:
- 为什么Similarity的computeNorm方法报告的索引时间fieldNorm与查询解释报告的索引时间不一样?
- 为什么,对于在索引时获得的两个不同的 fieldNorm 值(通过相似性 computeNorm),我在查询时得到相同的 fieldNorm 值?
== 更新
好的,我在Lucene 的文档中找到了一些东西,它澄清了我的一些问题,但不是全部:
然而,结果规范值在存储之前被编码为单个字节。在搜索时,从索引目录中读取标准字节值并将其解码回浮点标准值。这种编码/解码虽然减少了索引大小,但也带来了精度损失——不能保证 decode(encode(x)) = x。例如,decode(encode(0.89)) = 0.75。
有多少精度损失?我们应该在不同的值之间设置一个最小差距,以便即使在重新计算精度损失之后它们仍然保持不同?