繁体   English   中英

弹性搜索 - 提升/评分 - 两个不同长度的单词

[英]Elastic Search - Boosting/Scoring - Two words with different length

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

有没有办法增加'text ab'的得分,因为它更短?

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

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

  • 字段:“text ab” - lengthnorm = 1 /√2= 0.7
  • 字段:“text 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())));
    }
}

你有它。 对文档和查询的测试运行显示:

  • 字段:“text ab” - 总分= 0.18579213
  • 字段:“text abcd” - 总分= 0.18579213
  • 字段:“text abcdefghi” - 总分= 0.1486337

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

规范以超压缩形式存储在单个字节中。 它们只有一个3位尾数,这使它们的精度略小于1位十进制数。 因此,在给定压缩方案的情况下,仅与这两个添加的字符的差异是不够的。 当涉及到这种提升时,常识是:“ 只有重大差异很重要 ”(参见DefaultSimilarity文档


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

好吧,你需要覆盖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";
    }
}

现在我得到:

  • 字段:“text ab” - 总分= 0.2518424
  • 字段:“text abcd” - 总分= 0.22525471
  • 字段:“text abcdefghi” - 总分= 0.1839197

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM