Elasticsearch教程(27) ES拼接查询条件的工具类

ES拼接查询条件的工具类

一、前言

在大多数公司产线Elasticsearch还在6.X的时候,ES已经更新到7.10.1了,这更新速度。

目前我手上的项目也做到一套工具类兼容ES6.1到ES7.9+。我用的是原生的ES6.8.12的Java API来实现的工具类。目前功能上线几个月没有出过错。

工作中用ES查询大于插入,所以代码里到处都是拼接ES查询条件的语句,ES本身的Java API已经很强大了,我们利用BoolQueryBuilderQueryBuilders可以组合很多查询条件。

但是如果查询条件多,代码就会显的非常长,有很多行,对ES老鸟可能非常熟悉的味道,但是对ES新鸟可能非常不舒服。所以我尝试着写ES查询条件的帮助类,刚写了一天,功能还比较简单。

二、工具类

package info.pigg.dict.common.builder;

import info.pigg.dict.common.constant.PiggCharConstant;
import info.pigg.dict.common.constant.PiggFieldConstant;

import static info.pigg.dict.common.constant.PiggRelationConstant.*;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


import java.lang.reflect.Array;
import java.text.MessageFormat;
import java.util.*;


public class PiggEsQuery {
    
    

    private int minimumShouldMatch = 1;

    private List<BoolQueryBuilder> shoulds = new ArrayList<>();

    private Map<String, Object> param = new HashMap<>();

    public PiggEsQuery term(String field, Object value) {
    
    

        String key = initKey(true, TERM, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery notTerm(String field, Object value) {
    
    

        String key = initKey(false, TERM, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery terms(String field, Object value) {
    
    

        String key = initKey(true, TERMS, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery notTerms(String field, Object value) {
    
    

        String key = initKey(false, TERMS, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery ids(Object ids) {
    
    

        String key = initKey(true, IDS, PiggFieldConstant.ID);
        this.param.put(key, ids);
        return this;
    }

    public PiggEsQuery notIds(Object ids) {
    
    

        String key = initKey(false, IDS, PiggFieldConstant.ID);
        this.param.put(key, ids);
        return this;
    }

    public PiggEsQuery prefix(String field, Object value) {
    
    

        String key = initKey(true, PREFIX, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery notPrefix(String field, Object value) {
    
    

        String key = initKey(false, PREFIX, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery wildcard(String field, Object value) {
    
    

        String key = initKey(true, WILDCARD, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery notWildcard(String field, Object value) {
    
    

        String key = initKey(false, WILDCARD, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery exists(String field) {
    
    

        String key = initKey(true, EXISTS, field);
        this.param.put(key, field);
        return this;
    }

    public PiggEsQuery notExists(String field) {
    
    

        String key = initKey(false, EXISTS, field);
        this.param.put(key, field);
        return this;
    }

    public PiggEsQuery rangeGt(String field, Object value) {
    
    

        String key = initKey(true, RANGE_GT, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery rangeGte(String field, Object value) {
    
    

        String key = initKey(true, RANGE_GTE, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery rangeLt(String field, Object value) {
    
    

        String key = initKey(true, RANGE_LT, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery rangeLte(String field, Object value) {
    
    

        String key = initKey(true, RANGE_LTE, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery match(String field, Object value) {
    
    

        String key = initKey(true, MATCH, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery matchPhrase(String field, Object value) {
    
    

        String key = initKey(true, MATCH_PHRASE, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery matchPhrasePrefix(String field, Object value) {
    
    

        String key = initKey(true, MATCH_PHRASE_PREFIX, field);
        this.param.put(key, value);
        return this;
    }

    public PiggEsQuery withParam(Map<String, Object> param) {
    
    
        if (param != null && !param.isEmpty()) {
    
    
            this.param.putAll(param);
        }
        return this;
    }

    public PiggEsQuery should(BoolQueryBuilder boolQueryBuilder) {
    
    
        shoulds.add(boolQueryBuilder);
        return this;
    }

    public PiggEsQuery minimumShouldMatch(int minimumShouldMatch) {
    
    
        if (minimumShouldMatch > 0) {
    
    
            this.minimumShouldMatch = minimumShouldMatch;
        }
        return this;
    }

    public BoolQueryBuilder getQuery() {
    
    

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if ((this.param == null || param.isEmpty())
                && CollectionUtils.isEmpty(shoulds)
        ) {
    
    
            return boolQueryBuilder;
        }

        this.param.forEach((k, v) -> {
    
    

            String isOrNot = "";
            String field = "";
            String relation = "";

            if (StringUtils.hasText(k) && k.contains(PiggCharConstant.COLON)) {
    
    

                String[] split = k.split(PiggCharConstant.COLON);
                if (!(split != null && split.length == 3)) {
    
    
                    //do nothing
                }

                isOrNot = split[0];
                field = split[1];
                relation = split[2];

                if (StringUtils.hasText(isOrNot)
                        && StringUtils.hasText(field)
                        && StringUtils.hasText(relation)
                ) {
    
    

                    QueryBuilder queryBuilder = null;

                    switch (relation) {
    
    
                        case TERM: {
    
    
                            queryBuilder = QueryBuilders.termQuery(field, v);
                            break;
                        }
                        case TERMS: {
    
    
                            Collection thisValue = getCollectionFromValue(v);
                            if (thisValue != null && !thisValue.isEmpty()) {
    
    
                                queryBuilder = QueryBuilders.termsQuery(field, thisValue);
                            }
                            break;
                        }
                        case IDS: {
    
    
                            List<String> thisValueList = new ArrayList<>();
                            Collection thisValue = getCollectionFromValue(v);
                            if (!CollectionUtils.isEmpty(thisValue)) {
    
    
                                thisValue.stream().distinct().forEach(a -> thisValueList.add(a.toString()));
                                String[] ids = thisValueList.toArray(new String[thisValueList.size()]);
                                queryBuilder = QueryBuilders.idsQuery().addIds(ids);
                            }
                            break;
                        }
                        case PREFIX: {
    
    
                            queryBuilder = QueryBuilders.prefixQuery(field, v.toString());
                            break;
                        }
                        case WILDCARD: {
    
    
                            queryBuilder = QueryBuilders.wildcardQuery(field, "*" + v.toString() + "*");
                            break;
                        }
                        case EXISTS: {
    
    
                            queryBuilder = QueryBuilders.existsQuery(field);
                            break;
                        }
                        case RANGE_GT: {
    
    
                            queryBuilder = QueryBuilders.rangeQuery(field).gt(v);
                            break;
                        }
                        case RANGE_GTE: {
    
    
                            queryBuilder = QueryBuilders.rangeQuery(field).gte(v);
                            break;
                        }
                        case RANGE_LT: {
    
    
                            queryBuilder = QueryBuilders.rangeQuery(field).lt(v);
                            break;
                        }
                        case RANGE_LTE: {
    
    
                            queryBuilder = QueryBuilders.rangeQuery(field).lte(v);
                            break;
                        }
                        case MATCH: {
    
    
                            queryBuilder = QueryBuilders.matchQuery(field, v);
                            break;
                        }
                        case MATCH_PHRASE: {
    
    
                            queryBuilder = QueryBuilders.matchPhraseQuery(field, v);
                            break;
                        }
                        case MATCH_PHRASE_PREFIX: {
    
    
                            queryBuilder = QueryBuilders.matchPhrasePrefixQuery(field, v);
                            break;
                        }
                    }

                    if (queryBuilder != null) {
    
    
                        if (isOrNot.equals(IS)) {
    
    
                            boolQueryBuilder.filter(queryBuilder);
                        } else {
    
    
                            boolQueryBuilder.mustNot(queryBuilder);
                        }
                    }
                }
            }
        });

        shoulds.forEach(thisShould -> {
    
    
            boolQueryBuilder.should(thisShould);
        });

        if (!CollectionUtils.isEmpty(shoulds)) {
    
    
            boolQueryBuilder.minimumShouldMatch(minimumShouldMatch);
        }


        return boolQueryBuilder;
    }

    private String initKey(boolean isOrNot, String relation, String field) {
    
    

        return MessageFormat.format("{0}:{1}:{2}",
                isOrNot ? IS : NOT,
                field,
                relation);
    }

    private static Collection getCollectionFromValue(Object v) {
    
    
        Collection thisValue = null;

        if (v instanceof List) {
    
    
            thisValue = (List) v;
        } else if (v instanceof Set) {
    
    
            thisValue = (Set) v;
        } else if (v instanceof Array) {
    
    
            thisValue = Arrays.asList((Array) v);
        } else if (v instanceof String) {
    
    
            thisValue = Arrays.asList(((String) v).split(","));
        }
        return thisValue;
    }
}

三、测试

//【1】 如果根据条件拼接可以这样new一个PiggEsQuery对象
PiggEsQuery esQuery = new PiggEsQuery();

if (true){
    
    
    esQuery.term("code", "1");
}

//【2】 直接在new PiggEsQuery()后添加查询条件
BoolQueryBuilder builder = new PiggEsQuery()
        .term("code", "1")
        .terms("pets", Arrays.asList("dog","cat","cow"))
        .notTerm("state", 0)
        .notTerms("state", 200)
        .prefix("name", "hehe")
        .notPrefix("name2", "hehe")
        .exists("age")
        .ids(Arrays.asList("1","2","3"))
        .should(
                new PiggEsQuery()
                        .term("state", "2")
                        .getQuery()

        )
        .should(
                new PiggEsQuery()
                        .term("code", "2")
                        .getQuery()
        ).minimumShouldMatch(2)
        .getQuery();

System.out.println(builder.toString());

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withFilter(builder).build();
SearchHits<PiggDictType> dictTypes = operations.search(searchQuery, PiggDictType.class);

System.out.println(dictTypes.getMaxScore());

四、总结

目前还是感觉Spring Data Elasticsearch使用最方便,功能最强,也紧更ES的最新版本,再项目中可以使用Spring Data Elasticsearch4.1.2,它支持到ES7.9.3,再结合自己写的工具类,可以应对大多数查询语句。对于一些特别复杂的聚合查询语句,得用原生ES Java API处理好。

猜你喜欢

转载自blog.csdn.net/winterking3/article/details/111933692