gpt4 book ai didi

java - Elastic Search - Boosting/Scoring - 两个不同长度的词

转载 作者:搜寻专家 更新时间:2023-11-01 01:51:55 26 4
gpt4 key购买 nike

当查询带有查询 'text' 的字段时,找到两个带有 'text abcd' 和 'text ab' 的文档,它们都得到相同的分数。

有没有办法提高“文本 ab”的得分,因为它更短?

最佳答案

这似乎是基于对长度在 lucene 评分方面的误解。将标记 视为索引文本的原子单位而不是字符是很有用的。 lucene 在评分中考虑的长度是字段中的标记数。您指定的两个字段都恰好有两个标记。它们的长度相同,因此它们的长度范数也相等,并且不影响相对得分。

如果您有一个包含三个词的字段,您实际上会看到长度对分数的影响:

  • 字段:“文本ab”——lengthnorm = 1/√2 = 0.7
  • 字段:“文本abcd”——lengthnorm = 1/√2 = 0.7
  • 字段:“text abc def ghi”——lengthnorm = 1/√4 = 0.5

该标准乘以分数,因此最后列出的文档的分数会低一些。


如果您不认同以术语而不是字符为单位来思考内容的想法:

由于您正在考虑的长度适用于字符,因此实现这一点肯定有些违背常理。不过,您在考虑规范方面走在正确的轨道上。这绝对应该在索引时进行预处理并作为规范存储。

您需要在自定义相似性类中实现它。我假设我们喜欢 DefaultSimilarity 的其余部分,因此您可以扩展它并覆盖 LengthNorm 以简化此操作。您可以很容易地利用字段偏移量来获得:

public class MySimilarity extends DefaultSimilarity {
@Override
public float lengthNorm(FieldInvertState state) {
return state.getBoost() * ((float) (1.0 / Math.sqrt(state.getOffset())));
}
}

就是这样。给定文档和查询的测试运行显示:

  • 字段:“文本 ab”——总分 = 0.18579213
  • 字段:“文本 abcd”——总分 = 0.18579213
  • 字段:“文本 abcdefghi”——总分 = 0.1486337

所以,你可以从我添加的较长文档中看到它是有效的,那么为什么“text ab”和“text abcd”仍然具有相同的分数?

规范以超压缩形式存储在单个字节中。它们只有 3 位尾数,这使它们的精度略低于 1 位小数。因此,考虑到压缩方案,仅这两个添加字符的差异不足以产生影响。当涉及到这种提升时,常识是:“只有大的差异才重要”(参见 the DefaultSimilarity documentation)


所以,“谁在乎在搜索时节省一些内存?小差异对我来说很重要!”,我听到你说。

好的,您需要覆盖 encodeNormdecodeNorm。由于这些在 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";
}
}

现在我得到:

  • 字段:“文本 ab”——总分 = 0.2518424
  • 字段:“文本 abcd”——总分 = 0.22525471
  • 字段:“文本 abcdefghi”——总分 = 0.1839197

关于java - Elastic Search - Boosting/Scoring - 两个不同长度的词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26256150/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com