打通es及lucene应用,lucene应用es Query,结合非queryString查询(二)

其实可以减小难度,直接以lucene语法,mod_date:[20020101 TO 20030101],构造一个rangeQuery

或直接构造RangFieldQuery实例

lucene语法的range构造示例

https://lucene.apache.org/core/7_7_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package.description

因为主要目标是兼容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类的不支持

原文地址:https://www.cnblogs.com/zihunqingxin/p/14471732.html