已知查询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);
}
}