通配符匹配得分与完全匹配
之间存在不匹配我搜索
recording:live OR recording:luve*
这是搜索的解释输出
DocNo:0:1.4196585:11111111-1cf0-4d1f-aca7-2a6f89e34b36
1.4196585 = (MATCH) max plus 0.1 times others of:
0.3763506 = (MATCH) ConstantScore(recording:luve*), product of:
1.0 = boost
0.3763506 = queryNorm
1.3820235 = (MATCH) weight(recording:luve in 0), product of:
0.7211972 = queryWeight(recording:luve), product of:
1.9162908 = idf(docFreq=1, maxDocs=5)
0.3763506 = queryNorm
1.9162908 = (MATCH) fieldWeight(recording:luve in 0), product of:
1.0 = tf(termFreq(recording:luve)=1)
1.9162908 = idf(docFreq=1, maxDocs=5)
1.0 = fieldNorm(field=recording, doc=0)
DocNo:1:0.3763506:22222222-1cf0-4d1f-aca7-2a6f89e34b36
0.3763506 = (MATCH) max plus 0.1 times others of:
0.3763506 = (MATCH) ConstantScore(recording:luve*), product of:
1.0 = boost
0.3763506 = queryNorm
在我的测试中,我有5个文档,一个包含完全匹配,另一个包含通配符匹配,另外三个不匹配全部。对于通配符匹配,精确匹配的得分 1.4 与 0.37 相比,几乎是 4 的因子。使用更大的索引,与通配符搜索相比,罕见术语的完全匹配得分会更高。
整个差异是由于用于通配符与精确匹配的得分机制不同,通配符不考虑tf / idf或lengthnorm,因为每次比赛都得到一个常数得分。现在我对我的数据域中的tf或lengthnorm并不感到困扰它并没有太大的区别,但 idf 得分是一个真正的杀手。因为匹配文档在5个文档中找到一次,其idf贡献是idf平方,即 3.61
我知道这个常数得分比计算每个通配符匹配的tf * idf * lengthnorm要快,但我觉得idf对得分贡献如此之大是没有意义的。我也知道我可以改变重写方法,但这有两个问题。
评分重写方法执行得不太好,因为它们正在计算idf,tf和lengthnorm。 idf是我唯一需要的值。
那些计算分数的人也没有多大意义,因为他们会计算匹配词的idf,即使这不是实际搜索的内容,这个词可能比我实际搜索的内容更少见因为,可能会提高它高于完全匹配。
(我也可以更改相似度类来覆盖idf计算,所以它总是返回1但这没有意义,因为idf对于将完全匹配与不同单词进行比较非常有用
即录音:luve OR录音:luve *或录音:OR录音:*
我希望 luve 的匹配得分高于常用字的匹配 )
所以重写方法已经存在或者可能只计算它试图匹配的术语的idf,所以例如在这种情况下我搜索'luve'并且通配符匹配'luvely'它会通过luve(3.61)的idf多次匹配。这样我的通配符匹配就可以与完全匹配相提并论,我可以更改我的查询以略微提升完全匹配,因此完全匹配总是会得分高于通配符但不会高得多
即
recording:live^1.2 OR recording:luve*
并使用这种神秘的重写方法,这将给出(取决于queryNorm):
答案 0 :(得分:0)
答案 1 :(得分:0)
好的将此设置为前缀查询的重写方法似乎可以正常工作
public static class MultiTermUseIdfOfSearchTerm<Q extends Query> extends TopTermsRewrite<BooleanQuery> {
//public static final class MultiTermUseIdfOfSearchTerm extends TopTermsRewrite<BooleanQuery> {
private final Similarity similarity;
/**
* Create a TopTermsScoringBooleanQueryRewrite for
* at most <code>size</code> terms.
* <p>
* NOTE: if {@link BooleanQuery#getMaxClauseCount} is smaller than
* <code>size</code>, then it will be used instead.
*/
public MultiTermUseIdfOfSearchTerm(int size) {
super(size);
this.similarity = new DefaultSimilarity();
}
@Override
protected int getMaxSize() {
return BooleanQuery.getMaxClauseCount();
}
@Override
protected BooleanQuery getTopLevelQuery() {
return new BooleanQuery(true);
}
@Override
protected void addClause(BooleanQuery topLevel, Term term, float boost) {
final Query tq = new ConstantScoreQuery(new TermQuery(term));
tq.setBoost(boost);
topLevel.add(tq, BooleanClause.Occur.SHOULD);
}
protected float getQueryBoost(final IndexReader reader, final MultiTermQuery query)
throws IOException {
float idf = 1f;
float df;
if (query instanceof PrefixQuery)
{
PrefixQuery fq = (PrefixQuery) query;
df = reader.docFreq(fq.getPrefix());
if(df>=1)
{
idf = (float)Math.pow(similarity.idf((int) df, reader.numDocs()),2);
}
}
return idf;
}
@Override
public BooleanQuery rewrite(final IndexReader reader, final MultiTermQuery query) throws IOException {
BooleanQuery bq = (BooleanQuery)super.rewrite(reader, query);
float idfBoost = getQueryBoost(reader, query);
Iterator<BooleanClause> iterator = bq.iterator();
while(iterator.hasNext())
{
BooleanClause next = iterator.next();
next.getQuery().setBoost(next.getQuery().getBoost() * idfBoost);
}
return bq;
}
}