首页 > IT基础架构 > > Lucene的搜索打之从理论到源码的分析















它使得两个不同Queries的搜索结果的每个文档的得分可以比较,可以比较意思是它们的比较是有意义的。
ueryNorm不影响排名,也就是不影响评分,就是对于同一个Query来说queryNorm是唯一的。好吧,这说法并不准确,应该是对于同一个Index的同一个Query它的queryNorm是唯一的。如果不能理解就看公式吧,作为查询归一化,那么它作用就是缩小同一个Query在不同Index上产生的影响。这使得分布式查询(同一个Query用在不同的Index上并计算文档的分数)的评分变得有意义和有可比性。
不影响排名,也就是不影响评分,有两层意思:
1、在单个Index而queryNorm是没意义,不会影响评分和排序。
2、对于多个Index,queryNorm实际上是会影响的评分和排序。只是这影响是降低不同的index之间在搜索时的影响,因此可以认为没有影响。


整理可得:


/** Lower-level search API.** <p>{@link LeafCollector#collect(int)} is called for every matching document.** @throws BooleanQuery.TooManyClauses If a query would exceed* {@link BooleanQuery#getMaxClauseCount()} clauses.*/public void search(Query query, Collector results)throws IOException {//search主入口search(leafContexts, createNormalizedWeight(query, results.needsScores()), results);}
/*** Creates a normalized weight for a top-level {@link Query}.* The query is rewritten by this method and {@link Query#createWeight} called,* afterwards the {@link Weight} is normalized. The returned {@code Weight}* can then directly be used to get a {@link Scorer}.* @lucene.internal*/public Weight createNormalizedWeight(Query query, boolean needsScores) throws IOException {query = rewrite(query);//重写查询//生成WeightWeight weight = createWeight(query, needsScores);float v = weight.getValueForNormalization();float norm = getSimilarity(needsScores).queryNorm(v);if (Float.isInfinite(norm) || Float.isNaN(norm)) {norm = 1.0f;}weight.normalize(norm, 1.0f);return weight;}
public class TermQuery extends Query {private final Term term;private final TermContext perReaderTermState;final class TermWeight extends Weight {private final Similarity similarity;private final Similarity.SimWeight stats;private final TermContext termStates;private final boolean needsScores;public TermWeight(IndexSearcher searcher, boolean needsScores, TermContext termStates)throws IOException {super(TermQuery.this);if (needsScores && termStates == null) {throw new IllegalStateException("termStates are required when scores are needed");}this.needsScores = needsScores;this.termStates = termStates;this.similarity = searcher.getSimilarity(needsScores);final CollectionStatistics collectionStats;final TermStatistics termStats;if (needsScores) {collectionStats = searcher.collectionStatistics(term.field());termStats = searcher.termStatistics(term, termStates);} else {// we do not need the actual stats, use fake stats with docFreq=maxDoc and ttf=-1final int maxDoc = searcher.getIndexReader().maxDoc();collectionStats = new CollectionStatistics(term.field(), maxDoc, -1, -1, -1);termStats = new TermStatistics(term.bytes(), maxDoc, -1);}/*** collectionStats 主要包含文档和字段的相关统计信息* termStats: 名字term的统计信息,包括词频docFreq,totalTermFreq* 调用相似度算法,执行计算weight,如果是TFIDFSimilarity相似度,即返回IDFStats对象,这块具体参考 org.apache.lucene.search.similarities.TFIDFSimilarity$IDFStats*/this.stats = similarity.computeWeight(collectionStats, termStats);}....
private static class IDFStats extends SimWeight {private final String field;/** The idf and its explanation */private final Explanation idf;private float queryNorm;private float boost;private float queryWeight;private float value;public IDFStats(String field, Explanation idf) {// TODO: Validate?this.field = field;this.idf = idf;normalize(1f, 1f);}@Overridepublic float getValueForNormalization() {//这里的queryWeight 其实在初始化时调用了normalize已经确定,queryWeight = (queryNorm * boost * idf.getValue()) * (queryNorm * boost * idf.getValue()) ;//公式里其实还有一个求和计算,其实是在BooleanWeight递归计算的return queryWeight * queryWeight; // sum of squared weights}@Overridepublic void normalize(float queryNorm, float boost) {this.boost = boost;this.queryNorm = queryNorm;queryWeight = queryNorm * boost * idf.getValue();value = queryWeight * idf.getValue(); // idf for document}}//BooleanWeight.getValueForNormalization如下:@Overridepublic float getValueForNormalization() throws IOException {float sum = 0.0f;int i = 0;for (BooleanClause clause : query) {// call sumOfSquaredWeights for all clauses in case of side effectsfloat s = weights.get(i).getValueForNormalization(); // sum sub weightsif (clause.isScoring()) {// only add to sum for scoring clausessum += s;}i += 1;}return sum ;}
@Overridepublic float queryNorm(float sumOfSquaredWeights) {return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));}

@Overridepublic void normalize(float queryNorm, float boost) {this.boost = boost;this.queryNorm = queryNorm;queryWeight = queryNorm * boost * idf.getValue();value = queryWeight * idf.getValue(); // idf for document}

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31509949/viewspace-3146198/ ,如需转载,请注明出处,否则将追究法律责任。