我试图了解 fieldNorm
是如何计算的(在索引时),然后在查询时使用(并且显然是重新计算的)。
在所有示例中,我都使用没有停用词的 StandardAnalyzer。
在索引内容时调试 DefaultSimilarity
的 computeNorm
方法,我注意到它返回 2 个特定文档:
它通过使用以下公式来做到这一点:
state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
boost 始终为 1
之后,当我查询这些文档时,我看到在查询解释中我得到
0.5 = fieldNorm(field=titre, doc=0)
0.625 = fieldNorm(field=titre, doc=1)
这已经很奇怪了(对我来说,我确定是我遗漏了什么)。为什么我得到的字段规范值与索引时计算的值不同?这是“查询规范化”的作用吗?如果是这样,它是如何工作的?
然而,这或多或少是可以的,因为两个查询时 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 = fieldNorm(field=titre, doc=0)
1.5 = fieldNorm(field=titre, doc=1)
对我来说,这现在真的很奇怪,如果我在索引时使用明显良好的相似性来计算 fieldNorm,这给了我与 token 数量成正比的适当值,后来在查询时,所有这些都丢失了,查询 sais 两个文档具有相同的字段规范?
所以我的问题是:
== 更新
好的,我在 Lucene's docs 中找到了一些东西,它澄清了我的一些问题,但不是全部:
然而,结果范数值在存储之前被编码为单个字节。在搜索时,从索引目录中读取规范字节值并解码回浮点规范值。这种编码/解码在减小索引大小的同时,也带来了精度损失的代价——不保证 decode(encode(x)) = x。例如,解码(编码(0.89))= 0.75。
有多少精度损失?我们应该在不同的值之间设置一个最小的差距,以便即使在重新计算精度损失之后它们仍然保持不同?
最佳答案
encodeNormValue 的文档描述了编码步骤(这是精度丢失的地方),特别是值的最终表示:
最相关的部分是,尾数只有 3 位,这意味着精度大约是一位有效的十进制数字。
关于基本原理的一个重要说明是在您的引用结束后的几句话,Lucene 文档说:
关于Lucene fieldNorm 相似度计算与查询时值的差异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15135872/