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 实现它?
谢谢。
您可以覆盖 Lucene 评分。
扩展org.apache.lucene.search.DefaultSimilarity,定义您的自定义评分算法。
您可能只想存根 DefaultSimilarity 的许多方法,例如 idf(只返回 1),以便更复杂的评分元素不会影响您的结果。
然后在 solr 中的 schema.xml 中添加一行,将其配置为使用您的评分类,例如:
<similarity class="com.mycompany.MySimilarity" />
Run Code Online (Sandbox Code Playgroud)
这是一个页面,其中包含有关评分如何工作的一些信息,请在此处查看:Lucene Scoring。还有一些关于添加自定义功能的资源,这可能有助于组合一个可用的 Similarily 类。
不过,老实说,特别是如果您是 Lucene/Solr 的新手,您可能会更好地获得一些默认评分的经验。它工作得很好,你通过丢弃它删除了许多有价值的功能。
编辑:
请注意,这提供了一种可能(虽然不是很漂亮)的方式来实现相似性。再往下看另一种方式。您仍然需要一个自定义的 Similarity,但它更简单。
好的,这是一个尝试。我还没有测试过它(现在不是真的有能力这样做),但也许它会为你指明正确的方向。
可能最简单的方法是为每个字段存储一个规范来编码术语的长度。为此,请覆盖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;
}
Run Code Online (Sandbox Code Playgroud)
注意:norm 是在文档被索引时计算的,所以在插入文档时必须使用这个 Similarity 才能有效。查询时间来不及设置规范。由于压缩,它也非常近似。
更简单的方法(也许):
你知道,现在我想起来了,因为相同的排序是通过从最短到最长排序来获得的,所以你可以在没有新的 Similarity 类的复杂性的情况下做到这一点。添加文档时,您只需应用字段级提升即可完成相同的操作。只需将这些术语中的每一个增加 1/length 或一些类似的方法。
如果插入 abcde,则对该字段应用 1/5 的提升。
完成后,您甚至可以像 'term:abc*^3' 这样的查询,这将允许您获得之前指出的百分比分数(尽管两种方式的效果大致相同,只有一个查询词)。
我认为,如果您使用这样的提升进行评分,您应该能够剔除 CustomSimilarity 中的所有内容。在这种情况下,'idf' 和 'tf' 可能是您真正需要担心的覆盖。