Elasticsearch源码分析八--如何根据查询语句确定查询类型并解析查询语句

  • 问题描述
  • 源码分析

问题描述

已知查询query如下,Elasticsearch如果根据该字符串判断是哪种查询类型,如何对其进行解析?

(1)不带boost参数
{
    "wildcard" : 
    {
        "title" : "cr?me"
    }
}
(2)带boost参数
{
    "wildcard" : 
    {
        "title" : 
        {
            "value" : "cr?me",
            "boost" : 20.0
        }
    }
}

源码分析

'''(1)测试代码'''
public void testWildcardQuery() throws IOException {
        IndexQueryParserService queryParser = queryParser();
        '''wildcard.json文件内容如问题描述中所示'''
        '''此函数将文件内容读入String类型的字符串'''
        String query = copyToStringFromClasspath("/org/elasticsearch/test/unit/index/query/wildcard.json");
        '''对String类型的查询query进行解析---关键步骤'''
        Query parsedQuery = queryParser.parse(query).query();
        '''解析后得到的是WildcardQuery类的对象'''
        assertThat(parsedQuery, instanceOf(WildcardQuery.class));
        WildcardQuery wildcardQuery = (WildcardQuery) parsedQuery;
        assertThat(wildcardQuery.getTerm(), equalTo(new Term("name.first", "sh*")));
    }

'''(2)确定查询文本格式(JSON/SMILE/YAML)和文本解析器JsonXContentParser'''
public class IndexQueryParserService extends AbstractIndexComponent {
    public ParsedQuery parse(String source) throws QueryParsingException {
        XContentParser parser = null;
        try {
            '''1.根据source内容判断是JSON/SMILE/YAML类型的格式,
                 第一个字符是花括号即认为是JSON,
                 参考XContentFactory类方法xContentType(...)
               2.根据类型格式返回相应的内容解析器,在此返回JsonXContentParser(implements XContentParser)'''
            parser = XContentFactory.xContent(source).createParser(source);
            '''利用JsonXContentParser对String进行解析'''
            return **parse**(cache.get(), parser);
        } catch (QueryParsingException e) {
            throw e;
        } catch (Exception e) {
            throw new QueryParsingException(index, "Failed to parse [" + source + "]", e);
        } finally {
            if (parser != null) {
                parser.close();
            }
        }
    }
 }
'''(3)调用JsonXContentParser将String类型的query解析成Token,例如:{、wildcard、}等等'''
public class IndexQueryParserService extends AbstractIndexComponent {
      private ParsedQuery parse(QueryParseContext parseContext, XContentParser parser) throws IOException, QueryParsingException {
        parseContext.reset(parser);
        Query query = parseContext.**parseInnerQuery**();
        if (query == null) {
            query = Queries.NO_MATCH_QUERY;
        }
        return new ParsedQuery(query, parseContext.copyNamedFilters());
    }
}
'''(4)确定查询类型'''
public class QueryParseContext {

    public Query parseInnerQuery() throws IOException, QueryParsingException {
        // move to START object
        XContentParser.Token token;
        '''找到第一个花括号({)'''
        if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
            token = parser.nextToken();
            if (token != XContentParser.Token.START_OBJECT) {
                throw new QueryParsingException(index, "[_na] query malformed, must start with start_object");
            }
        }
        '''花括号后的Token即是FIELD_NAME(标识查询类型,在此即为wildcard)'''
        token = parser.nextToken();
        if (token != XContentParser.Token.FIELD_NAME) {
            throw new QueryParsingException(index, "[_na] query malformed, no field after start_object");
        }
        '''取得wildcard,至此得到查询类型'''
        String queryName = parser.currentName();
        // move to the next START_OBJECT
        token = parser.nextToken();
        if (token != XContentParser.Token.START_OBJECT && token != XContentParser.Token.START_ARRAY) {
            throw new QueryParsingException(index, "[_na] query malformed, no field after start_object");
        }

        '''根据查询类型wildcard得到相应的查询解析器WildcardQueryParser'''
        '''查询类型和查询解析器的映射关系注册参考另一篇文章'''
        QueryParser queryParser = indexQueryParser.queryParser(queryName);
        if (queryParser == null) {
            throw new QueryParsingException(index, "No query registered for [" + queryName + "]");
        }

        '''调用WildcardQueryParser解析查询串,返回Lucene的WildcardQuery'''
        '''至此,已经根据String类型的query得到Lucene的WildcardQuery,确定了具体的查询query类,进而可以进行查询处理'''
        Query result = queryParser.parse(this);
        if (parser.currentToken() == XContentParser.Token.END_OBJECT || parser.currentToken() == XContentParser.Token.END_ARRAY) {
            // if we are at END_OBJECT, move to the next one...
            parser.nextToken();
        }
        return result;
    }
}
'''(5)调用WildcardQueryParser具体解析查询'''
public class WildcardQueryParser implements QueryParser {

    public static final String NAME = "wildcard";

    @Override
    '''进入该函数时,当前Token已经指向“wildcatd”之后的花括号'''
    public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
        XContentParser parser = parseContext.parser();

        /*  (1)不带boost
            {
                "wildcard":
                { **--currentToken**
                    "title":"cr?me" 
                }
            }

            (2)带boost
            {
                "wildcard" : 
                { **--currentToken**
                    "title" : 
                    {
                        "value" : "cr?me",
                        "boost" : 20.0
                    }
                }
            }
        */
        '''Token指向“title”'''
        XContentParser.Token token = parser.nextToken();
        if (token != XContentParser.Token.FIELD_NAME) {
            throw new QueryParsingException(parseContext.index(), "[wildcard] query malformed, no field");
        }

        '''取得“title”'''
        String fieldName = parser.currentName();
        String rewriteMethod = null;

        String 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 ("wildcard".equals(currentFieldName)) {
                        value = parser.text();
                    }
                    '''取得“:”后面的字段值''' 
                    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(), "[wildcard] 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");
        }

        BytesRef valueBytes;
        MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
        if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
            fieldName = smartNameFieldMappers.mapper().names().indexName();
            valueBytes = smartNameFieldMappers.mapper().indexedValueForSearch(value);
        } else {
            valueBytes = new BytesRef(value);
        }

        '''构造Lucene的WildcardQuery,参数为(title, cr?me)'''
        WildcardQuery query = new WildcardQuery(new Term(fieldName, valueBytes));
        QueryParsers.setRewriteMethod(query, rewriteMethod);
        query.setRewriteMethod(QueryParsers.parseRewriteMethod(rewriteMethod));
        query.setBoost(boost);
        return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
    }
}

你可能感兴趣的:(Elasticsearch,源码分析,elasticsearch)