ElasticSearch 数据查询

0. 概述

本文主要介绍ElasticSearch 基本的查询方式,包括in、等于、不等于、大于等于、小于等于等类似SQL查询方式。主要使用BooleanQuery,所谓的BooleanQuery 就是在搜索时候使用 AND,OR或NOT运算符多个查询结果的文件(must:AND,must_not,NOT,should:OR)。

1.定义操作符

package com.hsc.study;

import java.util.*;

/**
 * Created by hsc on 17/4/30.
 */
public enum FieldOperator {
    /**
     * 等于
     */
    EQ("=", "等于"),


    /**
     * 不等于
     */
    NE("!=", "不等于"),

    /**
     *
     */
    IN("in", "包含"),

    /**
     *
     */
    NOT_IN("!in", "不包含"),

    /**
     * 区间值 大于多少 小于多少
     */
    RANGE("range", "区间值"),

    /**
     * 大于等于
     */
    GE(">=", "大于等于"),
    /**
     * 小于等于
     */
    LE("<=", "小于等于");

    /**
     * 运算符
     */
    private final String operator;
    /**
     * 描述
     */
    private final String description;

    FieldOperator(String operator, String description) {
        this.operator = operator;
        this.description = description;
    }

    public String getOperator() {
        return this.operator;
    }

    public String getDescription() {
        return this.description;
    }

    public static final Map<String, FieldOperator> enumOperatorsMap;

    static {
        final FieldOperator[] operators = FieldOperator.values();
        Map<String, FieldOperator> innerEnumInsHolder =new HashMap<>(operators.length);
        for (FieldOperator operator : operators) {
            innerEnumInsHolder.put(operator.operator, operator);
        }
        enumOperatorsMap = Collections.unmodifiableMap(innerEnumInsHolder);
    }

}

2. 查询处理

FieldObject 类用于描述在使用哪个字段按照什么样操作方式进行查询。

public class FieldObject {

    private String fieldName;//字段名称
    private Object fieldValue;//字段值
    private FieldOperator operator;//操作类型 in 查询 还是 等于查询

    public FieldObject() {
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public Object getFieldValue() {
        return fieldValue;
    }

    public void setFieldValue(Object fieldValue) {
        this.fieldValue = fieldValue;
    }

    public FieldOperator getOperator() {
        return operator;
    }

    public void setOperator(FieldOperator operator) {
        this.operator = operator;
    }
}

字段处理接口,构造ElasticSearch查询语法。

public interface FieldHandler {

    /**
     * 针对单个FieldObject构建查询语法
     * @param queryBuilder  BoolQueryBuilder
     * @param fieldObject
     */
    void buildQuerySyntaxForElasticSearch(BoolQueryBuilder queryBuilder, FieldObject fieldObject);
}

字段处理抽象类,提供了一个注册功能,也就是FieldOperator中的操作符和对应的handler做个映射处理。

public abstract class AbstractFieldHandler implements FieldHandler {

    protected abstract String registryKey();

    @Autowired
    protected FieldHandlerRegistry register;

    @PostConstruct
    protected void registry() {
        /**
         * 注册key
         */
        String registryKey = registryKey();
        /**
         * registryKey不是允许的定义值,异常通知
         */
        if (!FieldOperator.enumOperatorsMap.containsKey(registryKey)) {
            return;
        }
        register.register(registryKey, this);
    }
}
@Component
public class FieldHandlerRegistry {

    private final Map<String, FieldHandler> ruleFieldValueHandlerMap = new ConcurrentHashMap<>(FieldOperator.enumOperatorsMap.size());

    public void register(String registryKey, FieldHandler handler) {
        FieldHandler oldHandler = ruleFieldValueHandlerMap.get(registryKey);
        if (oldHandler != null) {
            return;
        }
        synchronized (ruleFieldValueHandlerMap) {
            ruleFieldValueHandlerMap.put(registryKey, handler);
        }
    }

    public FieldHandler getHandler(String registryKey) {
        return ruleFieldValueHandlerMap.get(registryKey);
    }
}

等于查询:值得强调的是这里使用的是matchQuery,因为matchQuery会对这个字段值做分词,如果是term查询则不会做分词处理,这个具体可以见官方文档

@Component
public class EQFieldHandler extends AbstractFieldHandler {

    @Override
    protected String registryKey() {
        return FieldOperator.EQ.getOperator();
    }

    @Override
    public void buildQuerySyntaxForElasticSearch(BoolQueryBuilder queryBuilder, FieldObject fieldObject) {
        //matchQuery 会分词
        queryBuilder.must(QueryBuilders.matchQuery(fieldObject.getFieldName(), fieldObject.getFieldValue()).operator(Operator.AND));
    }

}

不等于处理,如果字段没有分词可以用termQuery,比如用户Id 用户名没有分词的字段。

@Component
public class NEFieldHandler extends AbstractFieldHandler {
    @Override
    protected String registryKey() {
        return FieldOperator.NE.getOperator();
    }

    @Override
    public void buildQuerySyntaxForElasticSearch(BoolQueryBuilder queryBuilder, FieldObject fieldObject) {
        queryBuilder.mustNot(QueryBuilders.matchQuery(fieldObject.getFieldName(), fieldObject.getFieldValue()));
    }
}

大于等于处理

@Component
public class GEFieldHandler extends AbstractFieldHandler {
    @Override
    protected String registryKey() {
        return FieldOperator.GE.getOperator();
    }

    @Override
    public void buildQuerySyntaxForElasticSearch(BoolQueryBuilder queryBuilder, FieldObject fieldObject) {
        queryBuilder.filter(QueryBuilders.rangeQuery(fieldObject.getFieldName()).from(fieldObject.getFieldValue()));

    }
}

小于等于处理

@Component
public class LEFieldHandler extends AbstractFieldHandler {
    @Override
    protected String registryKey() {
        return FieldOperator.LE.getOperator();
    }

    @Override
    public void buildQuerySyntaxForElasticSearch(BoolQueryBuilder queryBuilder, FieldObject fieldObject) {
        queryBuilder.filter(QueryBuilders.rangeQuery(fieldObject.getFieldName()).to(fieldObject.getFieldValue()));

    }
}

3.查询语法构建

@Component
public class ElasticSearchQueryBuilder {

    @Autowired
    private FieldHandlerRegistry registry;

    public SearchRequestBuilder buildQuery(QueryContext queryContext) {
        final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        final String esIndex = queryContext.getIndex();
        //构建查询语法
        buildQuery(queryBuilder, queryContext.getFieldObjects());
        return queryContext.getEsClient().prepareSearch()
                .setIndices(esIndex)
                .setTypes(queryContext.getType())
                .setSize(queryContext.getPageSize())
                .setFrom(queryContext.getOffset())
                .setQuery(queryBuilder);

    }

    private void buildQuery(BoolQueryBuilder queryBuilder, List<FieldObject> fieldObjects) {
        if (fieldObjects == null) {
            return;
        }
        for (FieldObject object : fieldObjects) {
            registry.getHandler(object.getOperator().getOperator()).buildQuerySyntaxForElasticSearch(queryBuilder, object);
        }
    }

}

4 查询类

@Component
public class SearchComponent {

    private static final Logger logger = LoggerFactory.getLogger(SearchComponent.class);
    @Autowired
    private ElasticSearchQueryBuilder elasticSearchQueryBuilder;

    public SearchHits elasticSearch(QueryContext queryContext) {

        // 构造ES 查询条件
        SearchRequestBuilder esSearchRequest = elasticSearchQueryBuilder.buildQuery(queryContext);
        // 实行数据查询
        SearchResponse esResponse = esSearchRequest.get();

        /* 查询ES (数据和总数)*/
        return esResponse.getHits();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值