Elasticsearch调用Lucene查询接口源码分析六:前缀查询(Prefix)

Elasticsearch调用Lucene查询接口源码分析六:前缀查询(Prefix)

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

简介

前缀查询在配置方面来说跟词条查询类似。前缀查询能让我们匹配这样的文档:它们的特定
字段以给定的前缀开始。。

查询语法

例:查找所有title字段以cri开始的文档:
{
“query” : {
“prefix” : {
“title” : {
“value” : “cri”,
“boost” : 3.0
}}}}

源码分析

'''(1)Elasticsearch code'''
public class PrefixQueryParser implements QueryParser {
    public static final String NAME = "prefix";
    @Override
    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(), "[prefix] query malformed, no field");
        }
        String fieldName = parser.currentName();
        String rewriteMethod = null;

        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 (token.isValue()) {
                    if ("prefix".equals(currentFieldName)) {
                        value = parser.objectBytes();
                    } else if ("value".equals(currentFieldName)) {
                        value = parser.text();
                    } else if ("boost".equals(currentFieldName)) {
                        boost = parser.floatValue();
                    } else if ("rewrite".equals(currentFieldName)) {
                        rewriteMethod = parser.textOrNull();
                    }
                } else {
                    throw new QueryParsingException(parseContext.index(), "[prefix] query does not support [" + currentFieldName + "]");
                }
            }
            parser.nextToken();
        } else {
            value = parser.text();
            parser.nextToken();
        }

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

        MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewriteMethod, null);

        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().prefixQuery(value, method, parseContext);
                } finally {
                    QueryParseContext.setTypes(previousTypes);
                }
            } else {
                query = smartNameFieldMappers.mapper().prefixQuery(value, method, parseContext);
            }
        }
        if (query == null) {
            '''构造Lucene的PrefixQuery对象(Term("title","cri"))'''
            PrefixQuery prefixQuery = new PrefixQuery(new Term(fieldName, BytesRefs.toBytesRef(value)));
            '''设置重写方法,将cri重写为索引中以cri开始的词,这些词以或的关系组织'''
            if (method != null) {
                prefixQuery.setRewriteMethod(method);
            }
            query = prefixQuery;
        }
        query.setBoost(boost);
        return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
    }
}

'''(2)Lucene code'''
public class PrefixQuery extends AutomatonQuery {
   ....
}
public class AutomatonQuery extends MultiTermQuery {
   ....
}
public abstract class MultiTermQuery extends Query {
   ....
   @Override
   '''PrefixQuery是MultiTermQuery的子类,调用父类的rewrite方法'''
   public final Query rewrite(IndexReader reader) throws IOException {
    return rewriteMethod.rewrite(reader, this);
  }
}

'''(3)Lucene 常用词查询举例'''
public void testPrefixQuery() throws Exception {
    Directory directory = newDirectory();

    String[] categories = new String[] {"/Computers",
                                        "/Computers/Mac",
                                        "/Computers/Windows"};
    RandomIndexWriter writer = new RandomIndexWriter(random(), directory);
    for (int i = 0; i < categories.length; i++) {
      Document doc = new Document();
      doc.add(newStringField("category", categories[i], Field.Store.YES));
      writer.addDocument(doc);
    }
    IndexReader reader = writer.getReader();

    '''查找category字段中以"/Computers"开始的文档'''
    PrefixQuery query = new PrefixQuery(new Term("category", "/Computers"));
    IndexSearcher searcher = newSearcher(reader);
    ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
    assertEquals("All documents in /Computers category and below", 3, hits.length);

    '''查找category字段中以"/Computers/Mac"开始的文档'''
    query = new PrefixQuery(new Term("category", "/Computers/Mac"));
    hits = searcher.search(query, 1000).scoreDocs;
    assertEquals("One in /Computers/Mac", 1, hits.length);

    '''查找category字段中以任何字符串开始的文档即所有文档'''
    query = new PrefixQuery(new Term("category", ""));
    hits = searcher.search(query, 1000).scoreDocs;
    assertEquals("everything", 3, hits.length);
    writer.close();
    reader.close();
    directory.close();
  }  

你可能感兴趣的:(elasticsearch,Lucene)