Elasticsearch源码分析三--调用Lucene查询接口之词条查询

Elasticsearch源码分析三–调用Lucene查询接口之词条查询

  • 简介
  • 查询语法
  • 源码分析

简介

词条查询是Elasticsearch中的一个简单查询。它仅匹配在给定字段中含有该词条的文档,而且是确切的、未经分析的词条。
记住,词条查询是未经分析的,因此需要提供跟索引文档中的词条完全匹配的词条。
多词条查询允许匹配那些在内容中含有某些词条的文档。

查询语法

例1:查询title字段中含有crime一词的文档,建立索引时转成小写,查询时也用小写
{
“query” : {
“term” : {
“title” : “crime”
}}}
例2:查询所有在tags字段中含有novel或book的文档
{
“query” : {
“terms” : {
“tags” : [“novel”, “book”]
}}}

源码分析

'''(1)Elasticsearch code'''
public class TermQueryParser implements QueryParser {
    public static final String NAME = "term";
    public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
        XContentParser parser = parseContext.parser();

        XContentParser.Token token = parser.nextToken();
        if (token != XContentParser.Token.FIELD_NAME) {
            throw new QueryParsingException(parseContext.index(), "[term] query malformed, no field");
        }
        String fieldName = parser.currentName();

        Object value = null;
        float boost = 1.0f;
        token = parser.nextToken();
        if (token == XContentParser.Token.START_OBJECT) {
            String currentFieldName = null;
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
                if (token == XContentParser.Token.FIELD_NAME) {
                    currentFieldName = parser.currentName();
                } else {
                    if ("term".equals(currentFieldName)) {
                        value = parser.objectBytes();
                    } else if ("value".equals(currentFieldName)) {
                        value = parser.objectBytes();
                    } else if ("boost".equals(currentFieldName)) {
                        boost = parser.floatValue();
                    } else {
                        throw new QueryParsingException(parseContext.index(), "[term] query does not support [" + currentFieldName + "]");
                    }
                }
            }
            parser.nextToken();
        } else {
            value = parser.text();
            // move to the next token
            parser.nextToken();
        }

        if (value == null) {
            throw new QueryParsingException(parseContext.index(), "No value specified for term query");
        }

        Query query = null;
        MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
        if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
            if (smartNameFieldMappers.explicitTypeInNameWithDocMapper()) {
                String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
                try {
                    query = smartNameFieldMappers.mapper().termQuery(value, parseContext);
                } finally {
                    QueryParseContext.setTypes(previousTypes);
                }
            } else {
                query = smartNameFieldMappers.mapper().termQuery(value, parseContext);
            }
        }
        if (query == null) {
            '''构造Lucene的TermQuery对象(Term("title","crime")) '''
            query = new TermQuery(new Term(fieldName, BytesRefs.toBytesRef(value)));
        }
        query.setBoost(boost);
        return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
    }
 }
'''(2)Lucene code'''

public class TermQuery extends Query {
  private final Term term;
  '''创建Weight树,用于计算词的权重Term Weight'''
  public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
    final IndexReaderContext context = searcher.getTopReaderContext();
    final TermContext termState;
    if (perReaderTermState == null
        || perReaderTermState.topReaderContext != context) {
      // make TermQuery single-pass if we don't have a PRTS or if the context
      // differs!
      termState = TermContext.build(context, term);
    } else {
      // PRTS was pre-build for this IS
      termState = this.perReaderTermState;
    }

    return new TermWeight(searcher, needsScores, termState);
  }
  '''Weight树定义'''
  final class TermWeight extends Weight {
     '''生成Scorer对象树,用于计算打分'''
     public Scorer scorer(LeafReaderContext context) throws IOException {
      assert termStates.topReaderContext == ReaderUtil.getTopLevelContext(context) : "The top-reader used to create Weight (" + termStates.topReaderContext + ") is not the same as the current reader's top-reader (" + ReaderUtil.getTopLevelContext(context);
      final TermsEnum termsEnum = getTermsEnum(context);
      if (termsEnum == null) {
        return null;
      }
      PostingsEnum docs = termsEnum.postings(null, needsScores ? PostingsEnum.FREQS : PostingsEnum.NONE);
      assert docs != null;
      return new TermScorer(this, docs, similarity.simScorer(stats, context));
    }
  }
}

你可能感兴趣的:(Elasticsearch源码分析三--调用Lucene查询接口之词条查询)