我试图理解如何计算fieldNorm
(在索引时),然后在查询时使用(并且明显重新计算)。
在所有示例中,我使用的是StandardAnalyzer,没有停用词。
在索引内容时,对DefaultSimilarity
的{{1}}方法进行了取消,我注意到它返回了2个特定文档:
它通过使用公式来实现:
computeNorm
其中助力总是1
之后,当我查询这些文档时,我看到在查询说明中我得到了
state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
0.5 = fieldNorm(field=titre, doc=0)
这已经很奇怪了(对我来说,我确定是我丢失了什么)。为什么我没有得到与索引时计算的字段规范相同的值?这是“查询规范化”的事情吗?如果是这样,它是如何工作的?
然而,这或多或少都可以,因为两个查询时间fieldNorms提供的顺序与索引时计算的顺序相同(具有较短值的字段在两种情况下都具有较高的fieldNorm)
然后我创建了自己的Similarity类,我已经实现了computeNorms方法,如下所示:
0.625 = fieldNorm(field=titre, doc=1)
在索引时我现在得到:
但是现在,当我查询这些文档时,我可以看到它们都具有与explain函数报告的相同的字段规范:
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)
对我来说,现在真的很奇怪,如果我在索引时使用一个明显好的相似度来计算fieldNorm,为什么会给我一个与令牌数量成正比的值,稍后在查询时,所有这些丢失了,查询sais两个文件都有相同的字段规范?
所以我的问题是:
==更新
好的,我在Lucene's docs中找到了一些内容,澄清了我的一些问题,但并非全部问题:
但是,生成的标准值在存储之前被编码为单个字节。在搜索时,从索引目录中读取范数字节值并将其解码回浮点范数值。这种编码/解码虽然减小了索引大小,但却带来了精确丢失的代价 - 无法保证解码(encode(x))= x。例如,decode(encode(0.89))= 0.75。
有多少精度损失?我们应该在不同的值之间存在最小间隙,以便即使在精确损失重新计算之后它们仍然不同吗?
答案 0 :(得分:4)
encodeNormValue的文档描述了编码步骤(精度丢失的地方),特别是值的最终表示:
编码使用三位尾数,五位指数和零指数点15,因此表示大约7x10 ^ 9到2x10 ^ -9的值,具有大约一个精确的十进制十进制数字。零也代表。负数向上舍入为零。值太大而无法表示的值向下舍入到最大可表示值。值太小而无法表示的正值会向上舍入到最小的正可表示值。
最相关的部分是要了解尾数只有3位,这意味着精度约为一个有效十进制数。
关于理由的重要说明是在你的报价结束之后的几句话,Lucene文档说:
支持规范值的这种有损压缩的基本原理是,鉴于用户通过查询表达其真实信息需求的困难(和不准确性),只有重大差异。