其实可以减小难度,直接以lucene语法,mod_date:[20020101 TO 20030101],构造一个rangeQuery
或直接构造RangFieldQuery实例
lucene语法的range构造示例
因为主要目标是兼容es,为了复用es的查询语句,减少些工作量,因此想办法实现es的json解析 rangeQuery
方法受保护,不过Builder可以直接用 BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
protected Builder newBooleanQuery() {
return new Builder();
}
@Test
public void textAndRangeQuery() throws Exception {
AbstractBuilderTestCase c = new AbstractBuilderTestCase();
c.beforeTest();
QueryShardContext qc = AbstractBuilderTestCase.createShardContext();
//实例构造
String query =
"{
" +
" "range":{
" +
" "rangeFieldName": {
" +
" "gt": 1
" +
" }
" +
" }
" +
"}";
JsonParser jsonParser=new JsonParser(qc.getXContentRegistry());
org.elasticsearch.index.query.QueryBuilder queryBuilder=jsonParser.parseQuery(query);
Query rqbFromJson=queryBuilder.toQuery(qc);
Query textQuery = EsQueryStringToLucene.parseLuceneQuery("(("中国" OR "美国") NOT ("渔船" OR "调查"))","textFieldName",new StandardAnalyzer());
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
booleanQuery.add(rqbFromJson,BooleanClause.Occur.SHOULD);
booleanQuery.add(textQuery,BooleanClause.Occur.SHOULD);
Query compileQuery=booleanQuery.build();
System.out.println("to Query : "+compileQuery);
}
输出
to Query : rangeFieldName:{1 TO *] ((textFieldName:"中 国" textFieldName:"美 国") -(textFieldName:"渔 船" textFieldName:"调 查"))
任务完成
本来为快速完成queryString 走的作减法的方向,但现在添加RangeQuery等结构化查询,又开始作加法
另外这是分别手动聚合了两类查询,es官方可以将包含多类查询的dsl构造为一个Query的,这个方向又需要做更多加法
之前还留了个尾巴
queryString之前是通过QueryStringQueryParser 直接构建
public static Query parseLuceneQuery(String esQueryStringPharse,String filedName, Analyzer analyzer) throws Exception {
AbstractBuilderTestCase c = new AbstractBuilderTestCase();
c.beforeTest();
QueryShardContext qc = AbstractBuilderTestCase.createShardContext();
QueryStringQueryParser queryStringQueryParser = new QueryStringQueryParser(qc, filedName);
queryStringQueryParser.setForceAnalyzer(analyzer);
queryStringQueryParser.setMultiFields(Arrays.asList(filedName));
Query query = queryStringQueryParser.parse(esQueryStringPharse);
return query;
}
非分词字段,类似RangeQueryBuilder 都不存在对应的Parser ,QueryStringQueryParser 是否也可以通过QueryStringQueryBuilder构造呢,这样和其他的统一
很乐观的觉得应该是可以的
然而翻车了
因为现有的方案需要设置QueryStringQueryParser的属性
官方是QueryStringQueryParser通过mapping 获取analyzer和fileds,我这里跳过了mapping信息,是外部添加的
QueryStringQueryParser queryStringQueryParser = new QueryStringQueryParser(qc, filedName);
queryStringQueryParser.setForceAnalyzer(analyzer);
queryStringQueryParser.setMultiFields(Arrays.asList(filedName));
protected Query doToQuery(QueryShardContext context) throws IOException {
String rewrittenQueryString = this.escape ? QueryParser.escape(this.queryString) : this.queryString;
if (this.fieldsAndWeights.size() > 0 && this.defaultField != null) {
throw this.addValidationError("cannot use [fields] parameter in conjunction with [default_field]", (QueryValidationException)null);
} else {
boolean isLenient = this.lenient == null ? context.queryStringLenient() : this.lenient;
QueryStringQueryParser queryParser;
if (this.defaultField != null) {
if (Regex.isMatchAllPattern(this.defaultField)) {
queryParser = new QueryStringQueryParser(context, this.lenient == null ? true : this.lenient);
} else {
queryParser = new QueryStringQueryParser(context, this.defaultField, isLenient);
}
}
}
而源码里是在doToQuery方法内部new QueryStringQueryParser的实例,我在外部不好为queryParser 添加属性,而且不是一处两种,很多地方都会new QueryStringQueryParser
需要调整QueryStringQueryBuilder和QueryStringQueryParser,真调起来并不难,比如QueryStringQueryBuilder 新增构造参数analyzer和filedNames,再把所有QueryStringQueryBuilder内的QueryStringQueryParser,设置上analyzer和filedNames
只是想尽量和es源码保证一致,越少的变化越好,因此,既然QueryStringQueryParser已经可用,那就不做这类操作了
以后看有没有这样操作的必要
之前只验证了rangeQuery,但是es原生的所有Query 并不完全都支持
目前已知的 exists 和nested类的不支持