solr / lucene得分与文本的百分比相匹配?

时间:2012-11-02 04:23:26

标签: solr lucene

Solr / Lucene相当新鲜。我有一个简单的要求,不确定是否很容易配置solr来执行此操作。

假设所有文档只有一个文本字段,而不是标记化。

当查询进来时,我希望结果按匹配(包含)的文本的百分比排序。百分比由len(query)/len(matched text field)

计算

例如,有三个文件,文本字段如下:
doc1:abcdefghij
doc2:abcdefgh
3:abc

如果搜索词是'cde',则匹配doc 1和doc 2(文本字段包含搜索词)。 对于doc 1,百分比匹配= 3/10 = 30%
对于doc 2,百分比匹配= 3/8 = 37.5%

所以结果应该是:
DOC2
doc1

这有意义吗?如何使用solr实现它?

感谢。

1 个答案:

答案 0 :(得分:4)

您可以覆盖Lucene得分。

扩展org.apache.lucene.search.DefaultSimilarity,定义自定义评分算法。

很多DefaultSimilarity的方法你可能只想存根,比如idf(只返回1),这样更复杂的评分元素不会影响你的结果。

然后在solr中的schema.xml中添加一行,将其配置为使用您的评分类,如:

<similarity class="com.mycompany.MySimilarity" /> 

这是一个包含评分如何运作的信息的页面,请点击此处:Lucene Scoring。那里有一些资源可以添加自定义功能,这可能有助于组合一个可用的Similarily类。

老实说,尤其是如果你是Lucene / Solr的新手,你可能会更好地获得一些默认评分的经验。它工作得很好,你可以通过抛弃它来删除许多有价值的功能。

编辑:

注意,这提供了一种实现相似性的可能(但不是很漂亮)方式。再往下看另一种方式。你仍然需要一个自定义的相似度,但它更简单。

好的,这是对它的抨击。我没有测试过它(现在还没有测试过),但也许它会指出你正确的方向。

可能最简单的方法是为每个字段存储一个编码术语长度的范数。为此,重写computeNorm,并返回从第二个参数获取的长度的倒数。

为了计算您指定的精确评分,您需要访问匹配的查询字词或其长度。两者都不容易。您可能会找到一种方法,或者您可以手动将该值传递到相似性类中。由于您只需要按照指定的顺序获取值,另一种表达您的要求的方式是“从最短到最长的订单结果”。我们已经用computeNorm完成了它。

然后你只是将其余部分排除在外,产生了以下几点:

float computeNorm(String field, FieldInvertState state) {
    int length = state.getOffset() - state.getPosition();
    return 1.0 / (float)length;
}
float coord(int overlap, int maxOverlap) {
    return 1;
}
float idf(int docFreq, int numDocs) {
    return 1;
}
float tf(float freq) {
    return 1;
}
float queryNorm(float sumOfSquaredWeights) {
    return 1;
}
float sloppyFreq(int distance) {
    return 1;
}
float lengthNorm(string fieldName, int numTerms) {
    return 1;
}

注意:标准是在索引文档时计算的,因此在插入文档以使其有效时必须使用此相似性。查询时间为时已晚,无法设定常态。由于压缩,它也非常近似。

更简单的方式(也许):

你知道,现在我想到了,因为只需将最短到最长排序获得相同的排序,你可以在没有新的Similarity类的复杂性的情况下完成这个。 添加文档时,您只需应用字段级提升即可完成相同的操作。只需将这些术语中的每一个增加1 /长度或类似的方法。

如果您插入abcde,请向该字段应用1/5的提升。

完成后,你甚至可以查询'term:abc * ^ 3',这样你就可以得到你之前指出的百分比(尽管效果大致相同,只有一个查询词)。

如果你使用像这样的提升得分,我认为你应该能够在你的CustomSimilarity中存根。在这种情况下,'idf'和'tf'可能就是你真正需要担心的一切。