使用查询'文本'查询字段时,查找带有文本abcd'的两个文档。和'文字ab',他们都得到相同的分数。
有没有办法提高'文字ab'的分数,因为它更短?
答案 0 :(得分:5)
这似乎是基于对lucene得分长度的错误概念。将标记视为索引文本的原子单元而不是字符是有用的。 lucene在评分中考虑的长度是字段中的标记数。您指出的两个字段都有两个令牌。它们具有相同的长度,因此它们的长度规范也是相同的,并且它们不会影响相对得分。
如果你有一个包含三个术语的字段,你实际上会看到长度的分数影响:
这个规范会成倍增加,所以那里列出的最后一个文档的得分会低一些。
如果您没有按照以术语而非字符为单位考虑内容的想法出售:
由于您考虑的长度适用于角色,因此实现这一点肯定会有所不同。不过,你正在思考规范。这绝对应该在索引时进行预处理并存储为标准。
您需要在自定义相似度类中实现此功能。我假设我们喜欢剩余的DefaultSimilarity
,因此您可以对其进行扩展,并覆盖LengthNorm
以使其变得简单。您可以非常轻松地利用字段偏移来获得:
public class MySimilarity extends DefaultSimilarity {
@Override
public float lengthNorm(FieldInvertState state) {
return state.getBoost() * ((float) (1.0 / Math.sqrt(state.getOffset())));
}
}
你有它。对文档和查询进行的测试运行显示:
所以,你可以从我添加的较长文档中看到它正在工作,那么为什么"文本ab"和"文本abcd"还是有相同的分数?
规范以超压缩形式存储在单个字节中。它们只有一个3位尾数,这使它们的精度略小于1位十进制数。因此,在给定压缩方案的情况下,仅与这两个添加的字符的差异是不够的。当涉及到这种提升时,常识是:" 只有重大差异才重要" (见the DefaultSimilarity
documentation)
所以,"谁在乎在搜索时节省一些内存?小差异对我很重要!",我听到你说。
好的,您需要覆盖encodeNorm
和decodeNorm
。由于这些是DefaultSimilarity
中的最终版,因此您需要扩展TFIDFSimilarity
。我首先要复制DefaultSimilarity
的来源。最后你可以使用这样的东西:
public class MySimilarity extends TFIDFSimilarity {
public MySimilarity() {}
@Override
public float coord(int overlap, int maxOverlap) {
return overlap / (float)maxOverlap;
}
@Override
public float queryNorm(float sumOfSquaredWeights) {
return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
}
//Since length norms are generally going to leave us with results less than one, multiply
//by a sufficiently large number to not lose all our precision when casting to long
private static final float NORM_ADJUSTMENT = Integer.MAX_VALUE;
@Override
public final long encodeNormValue(float f) {
return (long) (f * NORM_ADJUSTMENT);
}
@Override
public final float decodeNormValue(long norm) {
System.out.println(norm);
return ((float) norm) / NORM_ADJUSTMENT;
}
@Override
public float lengthNorm(FieldInvertState state) {
return state.getBoost() * ((float) (1.0 / Math.sqrt(state.getOffset())));
}
@Override
public float tf(float freq) {
return (float)Math.sqrt(freq);
}
@Override
public float sloppyFreq(int distance) {
return 1.0f / (distance + 1);
}
@Override
public float scorePayload(int doc, int start, int end, BytesRef payload) {
return 1;
}
@Override
public float idf(long docFreq, long numDocs) {
return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
}
@Override
public String toString() {
return "DefaultSimilarity";
}
}
现在我明白了: