1

Solr/Lucene 相当新。我有一个简单的要求,不确定配置 solr 是否容易做到这一点。

假设所有文档只有一个文本字段,未标记。

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

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

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

所以结果应该是:
doc2
doc1

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

谢谢。

4

1 回答 1

5

您可以覆盖 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;
}

注意:范数是在文档被索引时计算的,所以插入文档时必须使用这个相似度才能生效。查询时间为时已晚,无法设定标准。由于压缩,它也非常近似。

一种更简单的方法(也许):

你知道,现在我想起来了,因为相同的排序是通过从最短到最长排序来获得的,你可以在没有新的相似性类的复杂性的情况下做到这一点。当您添加文档时,您可以应用字段级提升来完成同样的事情。只需将这些术语中的每一个提高 1/length 或一些类似的方法。

如果插入 abcde,则对该字段应用 1/5 的提升。

完成此操作后,您甚至可以查询“term:abc*^3”,这将允许您获得之前指定的百分比分数(尽管效果几乎相同,只有一个查询词)。

如果您使用这样的提升得分,我认为您应该能够在您的 CustomSimilarity 中删除所有内容。在这种情况下,'idf' 和 'tf' 可能是您真正需要担心的全部覆盖。

于 2012-11-02T05:02:34.553 回答