美文网首页
ES 7.x (ElasticSearch) 与Java集成使用

ES 7.x (ElasticSearch) 与Java集成使用

作者: 一个忙来无聊的人 | 来源:发表于2020-07-25 15:45 被阅读0次

本文介绍:本文介绍ES 7.7 (ElasticSearch) 版本与springboot集成使用,包含多种条件查询,同时将命令行操作展示。若有表述错误地方欢迎指出;
理论知识某度上太多,就不过多解释。
ES 以及kibana 下载可直接通过官网下载:https://www.elastic.co/cn/downloads/elasticsearch

7.8 版本 附网盘链接: 链接:https://pan.baidu.com/s/1GrUEHtkxGnD5FVA7RKR4EA
提取码:7gxd

一、命令行操作 (kibana)

1.1、 新增操作

  • 1.1.1 、命令行新增2条数据(不含子类)

命令行新增两条数据 , 启动 customer为索引名称, "_doc"后 数字为id;
请注意 索引名称只支持小写, 索引id有大小写区分

PUT /customer/_doc/1
{
 "id":"1",
 "name": "xiaoxiao",
 "age":28,
 "date":"2020-07-07 20:00:01",
 "address": "广东深圳福田"
}

PUT /customer/_doc/2
{
 "id":"2",
 "name": "xiaoAoJiangHu",
 "age":31,
 "date":"2020-07-07 20:00:01",
 "address": "广东深圳福田"
}
  • 1.1.2 、命令行新增两条数据(有子类)

    如下所示 cuostomer_detail 为索引名称, a 和A 为ES id , 此处为了便于区分。将实体类id设置和索引id 不一致。实体类id分别为 a1 和A1
PUT /cuostomer_detail/_doc/a
{
    "id":"a1",
    "name":"xiao_xiao",
    "address":"广东深圳福田",
    "age":18,
    "demoList":[
        {
            "id":"s1",
            "name":"小张的大儿子"
        },
        {
            "id":"S2",
            "name":"小张的小儿子"
        }
    ],
    "listStr":[
        "str1",
        "str2"
    ]
}
PUT /cuostomer_detail/_doc/A
{
    "id":"A1",
    "name":"小张",
    "address":"广东深圳福田翰林院",
    "age":18,
    "demoList":[
        {
            "id":"D1",
            "name":"小张的哥哥"
        },
        {
            "id":"s1",
            "name":"小张的大儿子"
        }
    ],
    "listStr":[
        "str1",
        "str2"
    ]
}
  • 1.1.2 、新增数据和修改数据返回说明。 kibana put之后如果id在当前索引不存在则是新增 直接返回成功,若是ES索引id已经存在,则修改,如下分别为新增和修改的返回数据

新增返回说明: _index--索引名称
_type -- 索引类型
_id -- 索引ID
_version -- 版本号,修改了多少次
result 表示创建或者修改
_shards -- 分片信息

{
  "_index" : "cuostomer_detail",
  "_type" : "_doc",
  "_id" : "a12",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 4,
  "_primary_term" : 1
}

修改返回: result 和新增不一致

{
  "_index" : "cuostomer_detail",
  "_type" : "_doc",
  "_id" : "A",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 5,
  "_primary_term" : 1
}

1.2、 查询操作

  • 1.2.1、 指定id 查询

查询语句, 查询索引名称为 cuostomer_detail 索引id 为A的数据

GET /cuostomer_detail/_doc/A
  • 1.2.2 、 指定ID返回结果 _source 就是实际数据信息

{
  "_index" : "cuostomer_detail",
  "_type" : "_doc",
  "_id" : "A",
  "_version" : 3,
  "_seq_no" : 5,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "id" : "A1",
    "name" : "小张",
    "address" : "广东深圳福田翰林院",
    "age" : 24,
    "demoList" : [
      {
        "id" : "D1",
        "name" : "小张的哥哥"
      },
      {
        "id" : "s1",
        "name" : "小张的大儿子"
      }
    ],
    "listStr" : [
      "str1",
      "str2"
    ]
  }
}
  • 1.2.3、 多条件查询, 分词查询数据信息,并且按照年龄排序, 从第1条开始查询,总共查询3条

查找地址 “广福东田”的数据 (此处由于有IK分词,没有找到完全匹配的,查询出相似的)

GET /cuostomer_detail/_search
{
    "query":{
        "match":{
            "address":"广福东田"
        }
    },
    "sort":[
        {
            "age":"asc"
        }
    ],
    "from":0,
    "size":3
}

返回结果
说明: 第一个 “hits” 表示命中信息

{
  "took" : 880,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "cuostomer_detail",
        "_type" : "_doc",
        "_id" : "A",
        "_score" : null,
        "_source" : {
          "id" : "A1",
          "name" : "小张",
          "address" : "广东深圳福田翰林院",
          "age" : 18,
          "demoList" : [
            {
              "id" : "D1",
              "name" : "小张的哥哥"
            },
            {
              "id" : "s1",
              "name" : "小张的大儿子"
            }
          ],
          "listStr" : [
            "str1",
            "str2"
          ]
        },
        "sort" : [
          18
        ]
      },
      {
        "_index" : "cuostomer_detail",
        "_type" : "_doc",
        "_id" : "a",
        "_score" : null,
        "_source" : {
          "id" : "a1",
          "name" : "xiao_xiao",
          "address" : "广东深圳福田",
          "age" : 24,
          "demoList" : [
            {
              "id" : "s1",
              "name" : "小张的大儿子"
            },
            {
              "id" : "S2",
              "name" : "小张的小儿子"
            }
          ],
          "listStr" : [
            "str1",
            "str2"
          ]
        },
        "sort" : [
          24
        ]
      }
    ]
  }
}
  • 1.2.4、 多条件查询,必须和非必须 (由于篇幅有限,后面数据都不在列举返回结果)

查找 age 为 18 且 name 不等于 “xiao”的

GET /cuostomer_detail/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "18" } }
      ],
      "must_not": [
        { "match": { "name": "xiao" } }
      ]
    }
  }
}
  • 1.2.5、 多条件查询,必须(查询子类)和非必须 ,并且包含模糊查询

GET /cuostomer_detail/_search
{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "demoList.id":"D1"
                    }
                }
            ],
            "must_not":[
                {
                    "match":{
                        "name":"xiao"
                    }
                }
            ],
            "should": [
              {
                "match": {
                  "name": "张"
                }
              }
            ]
        }
    }
}

二、Java代码集成使用

2.0 、springboot集成ES 需要引入全部jar包信息如下

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <elasticsearch.version>7.7.0</elasticsearch.version>
        <fastjson.version>1.2.70</fastjson.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--ES 引入pom文件信息 start -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <!--ES 引入pom文件信息 end -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

    </dependencies>

2.1 创建链接 链接ES ,此处提供了ES有用户密码的链接方式

此处创建的是高级搜索,如果高级搜索满足不了要求,也可以使用低级搜索。

   /**
     * 获取高级链接
     *
     * @return
     */
    private RestHighLevelClient getHighClient() {
      //  getHost() 为获取链接集群的地址 
        HttpHost[] host = getHost(); // getHost() -- ["http://127.0.0.1:9200"]
        RestClientBuilder builder = RestClient.builder(host);
      // 设置ES 链接密码
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esProperties.getUserName(), esProperties.getPassword()));
        builder.setHttpClientConfigCallback(f -> f.setDefaultCredentialsProvider(credentialsProvider));
  // 创建高级搜索链接,请注意改链接使用完成后必须关闭,否则使用一段时间之后将会抛出异常
        RestHighLevelClient restClient = new RestHighLevelClient(builder);
        return restClient;
    }

2.2 、使用通用接收数据类便于进行批量新增。请注意,批量新增索引的大小在 1000-5000条数据为最佳,数据量大小在 5MB-10MB 为最佳;超过可能会影响性能。

@Data
public class EsBatchAddReq<T> {
    /**
     * 业务系统编码
     */
    @NotBlank(message = "系统编码不能为空")
    private String systemCode;

    /**
     * 业务编码,类似表名
     */
    @NotBlank(message = "业务编码不能为空")
    private String businessCode;

    @Valid
    @NotEmpty(message = "插入的数据不能为空")
    private List<T> beanList;

/**
     * 此处生成的是ES的索引名称,请注意此处没有检验系统编码和业务编码大小写,只能是小写字母,也可以在此处设置转换为小写字母
     * @return
     */
    public String getEsCode() {
        return new StringBuilder(systemCode).append("_").append(businessCode).toString();
    }
}

2.3 、批量新增索引, 批量新增的类和获取链接的类请参考上

具体说明已经在下面代码上

public EsResponse upsetIndex(EsBatchAddReq requestParam) throws IOException {
    // 获取链接
        RestHighLevelClient highClient = getHighClient();
        BulkRequest request = new BulkRequest();
      // 设置索引名称,索引名称由系统编码和业务编码组成。若业务比较简单,也可以仅设置为一个字段。此处是为了方便多系统多业务使用
        request.routing(requestParam.getEsCode());
        for (Object o : requestParam.getBeanList()) {
            JSONObject jsonObject = (JSONObject) JSON.toJSON(o);
            String id = jsonObject.getString(EsConstant.ES_ID);
            Assert.notNull(id, "实体类必须包含id");
        // 将数据转换为String类型,批量插入时设置为JSON格式
            String data = JSONObject.toJSONString(o);
          // 实体类必须包含ES自定义主键,搜索引擎ES将根据自定义ID进行重复新验证。
            request.add(new IndexRequest(requestParam.getEsCode()).id(id).source(data, XContentType.JSON));
        }
    // 批量新增数据
        BulkResponse bulk = highClient.bulk(request, RequestOptions.DEFAULT);
  // TODO 此处缺少是否新增成功判断。可以自行增加    
    RestStatus status = bulk.status();
      // 关闭链接
        highClient.close();
 
        return EsResponse.successRes(status.toString());
    }

2.4、ES 搜索通用请求类

  • 系统编码和业务编码确定索引使用
  • fieldsList 表示需要模糊搜索的String类型字段(日期格式推荐使用format转换之后进行搜索),
  • numberFieldsList 表示数字类型的字段,为了避免搜索类型错误,支持整数搜索
  • 其他各类型map 的key值表示字段名称,value根据场景不同数量可能是1-N个,参加下方代码注释
public class EsSearchReq {
    /**
     * 业务系统编码
     */
    @NotBlank(message = "系统编码不能为空")
    private String systemCode;
    /**
     * 业务编码,类似表名
     */
    @NotBlank(message = "业务编码不能为空")
    private String businessCode;
    /**
     * 第几页
     */
    private Integer page = 1;
    /**
     * 每页展示的梳理
     */
    private Integer size = 10;
    /**
     * 从第几条开始(不传)
     */
    private Integer from;
    /**
     * 搜索值
     */
    private String searchValue;
    /**
     * 搜索字段列表,此处的字段类型必须为String类型 或者 date类型且在上面加上 @JSONField(format="yyyy-MM-dd HH:mm:ss") 才行
     */
    private List<String> fieldsList;
    /**
     * 搜索的数字列表
     */
    private List<String> numberFieldsList;
    /**
     * 必须相等
     */
    private Map<String, Object> mustMap;
    /**
     * 必须不等
     */
    private Map<String, Object> mustNotMap;
   /**
     * in条件字符串查询, 字段属性值必须为字符串类型
     */
    private Map<String, Object[]> containMap;
    /**
     *  not in条件字符串查询, 字段属性值必须为字符串类型
     * key 是字段名称, 
     */
    private Map<String, Object[]> notContainMap;

    /**
     * 数字in条件查询, 请注意,value必须能转换为数字
     */
    private Map<String, Long[]> numberContainMap;

    /**
     * 数字not in条件查询.请注意,value必须能转换为数字
     */
    private Map<String, Long[]> numberNotContainMap;

    /**
     * 在....之间
     * key 是字段名称, list只能且必须是两个相同的值
     */
    private Map<String, List<Object>> betweenMap;

    /**
     * 排序字段列表信息
     */
    private List<OrderItem> sortFields;

    /**
     * 是否高亮
     */
    private boolean highlight = false;

    /**
     * 模糊搜索
     */
    private Map<String, Object> shouldMap;

    /**
     * 针对时间、数字类型字段处理  可以和 shouldMap 合并
     */
    private Map<String, Object> matchMap;

   public Integer getFrom() {
        if (from == null) {
            from = (page - 1) * size;
        }
        return from;
    }

2.5、ES 的具体执行搜索的代码--重点,包含 (相等、不等、in条件、not in 条件,范围、高亮)等功能

  • 查询相等
  • 查询不等
  • in 条件查询
  • not in 条件查询
  • 范围查询
  • 高亮查询
  • 不分词查询使用MatchPhraseQueryBuilder ,如果要分词查询使用MatchQueryBuilder
public EsResponse query(EsSearchReq searchReq) throws IOException {
        RestHighLevelClient highClient = getHighClient();
// 拼接索引  设置索引名称
        SearchRequest searchRequest = new SearchRequest(searchReq.getEsCode());

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        BoolQueryBuilder shouldBuilder = new BoolQueryBuilder();
        if (!CollectionUtils.isEmpty(searchReq.getShouldMap())) {
            Map<String, Object> shouldMap = searchReq.getShouldMap();
            for (String key : shouldMap.keySet()) {
                MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(key, shouldMap.get(key));
                shouldBuilder.should(matchQueryBuilder );
            }
        }
        List<String> fieldsList = searchReq.getFieldsList();
       String searchValue = searchReq.getSearchValue();
        // 排除空格问题
        if (null != searchValue && !StringUtils.isEmpty(searchValue.trim()) && !CollectionUtils.isEmpty(fieldsList)) {
            List<String> list = fieldsList;
            for (String field : list) {
                MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(field, searchValue);
// 如果不需要分词,则直接使用下面一行代码替换上面这行代码
// MatchPhraseQueryBuilder matchQueryBuilder = new MatchPhraseQueryBuilder(field, searchValue);
                shouldBuilder.should(matchQueryBuilder );
            }
        }
        // 如果搜索的内容为数字 搜索字段列表包含数字字段信息, 此处工具类见下面附录
        if (CommonUtil.isInteger(searchValue) && !CollectionUtils.isEmpty(searchReq.getNumberFieldsList())){
            Integer searchNumber = Integer.valueOf(searchValue.trim());
            for (String field : searchReq.getNumberFieldsList()) {
                MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(field, searchNumber);
                // 新增字段权重搜索功能,需要自行在参数中新增权重字段逻辑,此处直接复制会报错
                if (shouldWeight.containsKey(key)) { // 如果不要权重功能可以删除这个if语句
                    matchQueryBuilder.boost(shouldWeight.get(key));
                }
                
                shouldBuilder.should(matchQueryBuilder );
            }
        }
        boolQueryBuilder.must(shouldBuilder);

        /**
         * 必须相等
         */
        if (!CollectionUtils.isEmpty(searchReq.getMustMap())) {
            Map<String, Object> mustMap = searchReq.getMustMap();
            for (String field : mustMap.keySet()) {
                boolQueryBuilder.must(QueryBuilders.termQuery(field, mustMap.get(field)));
            }
        }

        /**
         * 必须不等
         */
        if (!CollectionUtils.isEmpty(searchReq.getMustNotMap())) {
            Map<String, Object> mustNotMap = searchReq.getMustNotMap();
            for (String field : mustNotMap.keySet()) {
                boolQueryBuilder.mustNot(QueryBuilders.termQuery(field, mustNotMap.get(field)));
            }
        }

       /**
         * in 条件查询  查询的字段属性必须为字符串类型才可以
         */
        if (!CollectionUtils.isEmpty(searchReq.getContainMap())) {
            Map<String, Object[]> containMap = searchReq.getContainMap();
            for (String field : containMap.keySet()) {
                Object[] objects = containMap.get(field);
                Assert.notNull(objects, "containMap 中的值不能为空");
                String searchKey = new StringBuilder(field).append(".keyword").toString();
                boolQueryBuilder.must(QueryBuilders.termsQuery(searchKey, objects));
            }
        }

        /**
         * not in 条件查询  查询的字段属性必须为字符串类型才可以
         */
        if (!CollectionUtils.isEmpty(searchReq.getNotContainMap())) {
            Map<String, Object[]> notInMap = searchReq.getNotContainMap();
            for (String field : notInMap.keySet()) {
                Object[] objects = notInMap.get(field);
                Assert.notNull(objects, "notInMap 中的值不能为空");
                String searchKey = new StringBuilder(field).append(".keyword").toString();
                boolQueryBuilder.mustNot(QueryBuilders.termsQuery(searchKey, objects));
            }
        }

        boolQueryBuilder.must(containBuilder);

        /**
         * in 条件查询   查询的字段属性必须为数字类型才可以
         */
        if (!CollectionUtils.isEmpty(searchReq.getNumberContainMap())) {
            Map<String, Long[]> numberContainMap = searchReq.getNumberContainMap();
            for (String field : numberContainMap.keySet()) {
                Long[] objects = numberContainMap.get(field);
                Assert.notNull(objects, "numberContainMap 中的值不能为空");
                boolQueryBuilder.must(QueryBuilders.termsQuery(field, objects));
            }
        }
        /**
         * not in 条件查询  查询的字段属性必须为数字类型才可以
         */
        if (!CollectionUtils.isEmpty(searchReq.getNumberNotContainMap())) {
            Map<String, Long[]> numberNotContainMap = searchReq.getNumberNotContainMap();
            for (String field : numberNotContainMap.keySet()) {
                Long[] objects = numberNotContainMap.get(field);
                Assert.notNull(objects, "numberNotContainMap 中的值不能为空");
                boolQueryBuilder.mustNot(QueryBuilders.termsQuery(field, objects));
            }
        }

        /**
         * 范围查询
         */
        if (!CollectionUtils.isEmpty(searchReq.getBetweenMap())) {
            Map<String, List<Object>> betweenMap = searchReq.getBetweenMap();
            for (String field : betweenMap.keySet()) {
                List<Object> objects = betweenMap.get(field);
                Assert.notNull(objects, "betweenMap 中的值不能为空");
                Assert.isTrue(objects.size() == 2, "betweenMap的值大小必须为2");
                RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder(field).gte(objects.get(0)).lte(objects.get(1));
                boolQueryBuilder.must(rangeQueryBuilder);
            }
        }
        /**
         * 高亮展示  后续方案可以考虑设置类型或者
         */
        /*if (searchReq.getHighlight() && !CollectionUtils.isEmpty(searchReq.getHighLights())) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            searchReq.getHighLights().forEach(a -> {
                HighlightBuilder.Field field = new HighlightBuilder.Field(a);
                // 此处是设置高亮类型  后续扩展
//            highlightTitle.highlighterType("unified");
                highlightBuilder.field(field);
            });
            sourceBuilder.highlighter(highlightBuilder);
        }*/

        /**
         * 排序功能
         */
        if (!CollectionUtils.isEmpty(searchReq.getSortFields())) {
            sourceBuilder.sort(new FieldSortBuilder("_score").order(SortOrder.DESC));

            searchReq.getSortFields().forEach(a -> {
                SortOrder sortOrder = a.isAsc() ? SortOrder.ASC : SortOrder.DESC;
                sourceBuilder.sort(new FieldSortBuilder(a.getColumn()).order(sortOrder));
            });
        }

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.from(searchReq.getFrom());
        sourceBuilder.size(searchReq.getSize());
        searchRequest.source(sourceBuilder);
        SearchResponse search = highClient.search(searchRequest, RequestOptions.DEFAULT);
        highClient.close();
        log.info("ES查询返回的初始信息为:{}", JSONObject.toJSONString(search));
        EsResponse pageResponse = EsResponseUtil.getPageResponse(search, searchReq.getPage(), searchReq.getSize());
        log.info("ES查询返回的结果信息转换后的数据信息为:{}", JSONObject.toJSONString(pageResponse));
        return pageResponse;
    }

三、附录 ,其他工具类信息

3.1 、判断是否为数字

public class CommonUtil{
    public static boolean isInteger(String str) {
        if (str == null) {
            return false;
        }
        String trim = str.trim();
        if (trim == null || trim.length() > 8) {
            return false;
        }
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(trim).matches();
    }
}

3.2 、反射获取类String类型、Date类型字段列表,如果是子类,则按需求拼接 (父字段名.子字段名);获取数字字段列表

public class EsBeanUtil {

    private final static String SERIAL_VERSION_UID = "serialVersionUID";

    private final static String STRING_VALUE = "java.lang.String";
    private final static String DATE_VALUE = "java.util.Date";
    private final static String INTEGER_VALUE = "java.lang.Integer";
    private final static String SHORT_VALUE = "java.lang.Short";
    private final static String LONG_VALUE = "java.lang.Long";
    private final static String BIGDECIMAL_VALUE = "java.math.BigDecimal";


    /**
     * 获取类的所有字段信息
     *
     * @param clazz
     * @param prefix 前缀
     * @return
     */
    public static Map<String, String> getStringFieldsMap(String prefix, Class clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        Map<String, String> map = new HashMap<>();
        String prefixNam = StringUtils.isEmpty(prefix) ? "" : prefix + ".";
        for (Field field : declaredFields) {
            if (SERIAL_VERSION_UID.equals(field.getName())) {
                continue;
            }

            if (STRING_VALUE.equals(field.getType().getName())) {
                map.put(prefixNam + field.getName(), field.getName());
            } else if (DATE_VALUE.equals(field.getType().getName())) {
                // 日期类型 判断是否有字段
                JSONField annotation = field.getAnnotation(JSONField.class);
                if (annotation != null) {
                    map.put(prefixNam + field.getName(), field.getName());
                }
            }
        }
        return map;
    }

    public final static Map<String, String> numberMap() {
        Map<String, String> numberMap = new HashMap<>(16);
        numberMap.put("java.lang.Double", "1");
        numberMap.put("java.lang.Integer", "1");
        numberMap.put("java.lang.Long", "1");
        numberMap.put("int", "1");
        numberMap.put("long", "1");
        numberMap.put("double", "1");
        numberMap.put("java.math.BigDecimal", "1");
        return numberMap;
    }

    /**
     * 获取类的所有字段信息
     *
     * @param clazz
     * @return
     */
    public static List<String> getStringFieldsList(String prefix, Class clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        List<String> fields = new ArrayList<>();
        String prefixNam = StringUtils.isEmpty(prefix) ? "" : prefix + ".";
        Map<String, String> numberMap = numberMap();
        for (Field field : declaredFields) {
            if (SERIAL_VERSION_UID.equals(field.getName())) {
                continue;
            }
            // 如果是日期类型  则判断是否有做处理  否则不做处理
            if (DATE_VALUE.equals(field.getType().getName())) {
                // 日期类型 判断是否有字段
                JSONField annotation = field.getAnnotation(JSONField.class);
                if (annotation != null) {
                    fields.add(prefixNam + field.getName());
                }
                // 排除数字类型数据
            } else if (!numberMap.containsKey(field.getType().getName())) {
                fields.add(prefixNam + field.getName());
            }
        }
        return fields;
    }

    /**
     * 获取类的所有字段信息
     *
     * @param clazz
     * @return
     */
    public static List<String> getNumberFieldsList(String prefix, Class clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        List<String> fields = new ArrayList<>();
        String prefixNam = StringUtils.isEmpty(prefix) ? "" : prefix + ".";
        Map<String, String> map = numberMap();
        for (Field field : declaredFields) {
            if (SERIAL_VERSION_UID.equals(field.getName())) {
                continue;
            }
            if (map.containsKey(field.getType().getName())) {
                fields.add(prefixNam + field.getName());
            }
        }
        return fields;
    }
}

3.3、 EsResponse 类

public class EsResponse implements Serializable {

    private static final long serialVersionUID = 14284224234985L;
    /**
     * 返回编码  0代表成功
     */
    private String code = "0";

    /**
     * 返回参数信息
     */
    private String message = "操作成功";

    /**
     * 是否成功
     */
    private Boolean success = true;
    /**
     * 数据信息
     */
    private String data;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }


    public static EsResponse successRes() {
        return new EsResponse();
    }

 
    public static EsResponse successRes(String data) {
        EsResponse response = new EsResponse();
        response.setData(data);
        return response;
    }

   
    public static EsResponse failRes() {
        EsResponse response = new EsResponse();
        response.setSuccess(Boolean.FALSE);
        response.setCode("999999");
        response.setMessage("ES操作错误,请联系管理员");
        return response;
    }

   
    public static EsResponse failRes(String retMsg) {
        EsResponse response = new EsResponse();
        response.setSuccess(Boolean.FALSE);
        response.setCode("999999");
        response.setMessage(retMsg);
        return response;
    }

   
    public static EsResponse failRes(String retCode, String retMsg) {
        EsResponse response = new EsResponse();
        response.setSuccess(Boolean.FALSE);
        response.setCode(retCode);
        response.setMessage(retMsg);
        return response;
    }
}

EsResponseUtil 工具类

package com.lxzl.es.util;

import com.alibaba.fastjson.JSONObject;
import com.es.common.entity.EsPage;
import com.es.common.entity.EsResponse;
import org.apache.http.HttpStatus;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: xiaoxiao
 * @Date: 2020/7/16 9:48
 * @Desc: Es 处理请求工具类
 */
public class EsResponseUtil {

    public static EsResponse getPageResponse(SearchResponse response, int page, int size){
        EsResponse esResponse;
        List<JSONObject> resultList = new ArrayList<>(size * 2);
        // 如果成功
        if (HttpStatus.SC_OK == response.status().getStatus()) {
            esResponse = new EsResponse();
            SearchHits searchHits = response.getHits();
            Long hitsTotal = searchHits.getTotalHits().value;
            EsPage esPage = new EsPage(page, size, hitsTotal);
            SearchHit[] hits = response.getHits().getHits();
            if (hits != null && hits.length != 0) {
                for (SearchHit searchHit : hits) {
                    Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(sourceAsMap));
                    resultList.add(jsonObject);
                }
            }
            esPage.setList(resultList);
            esResponse.setData(JSONObject.toJSONString(esPage));
        } else {
            esResponse = EsResponse.failRes(String.valueOf(response.status().getStatus()), response.status().toString());
        }
        return esResponse;
    }


}

EsProperties 配置类

@Component
@ConfigurationProperties(prefix = "skull.es")
@Data
public class EsProperties {

    /**
     * ES 的服务地址信息
     */
    private String[] ip_address = {"127.0.0.1:9200"};

    /**
     * 链接超时时间配置,默认1秒
     */
    private Long connectTimeout = 1000L;

    /**
     * 通话超时时间  默认 30秒
     */
    private Long socketTimeout = 300000L;

    /**
     * 访问身份认证, 设置在请求头中,和appKeySecret组合使用
     */
    private String appKeyId = "";

    /**
     * 访问身份认证,设置在请求头中, 和appKeyId组合使用
     */
    private String appKeySecret = "";

    /**
     * 设置批量请求的数量  bulkActions
     */
    private Integer bulkActions = 1000;

    /**
     * 设置批量请求的大小,和 byteSizeType组合使用, 默认5M
     */
    private Long byteSizeValue = 5L;

    /**
     * 设置批量请求大小的衡量单位,可选 BYTES, KB, MB, GB, TB, PB
     */
    private String byteSizeType = "MB";

    /**
     * 设置并发请求的数量。默认是1, 0表示仅运行执行单个请求
     */
    private Integer concurrentRequests = 1;

    /**
     * 设置刷新时间,默认10秒
     */
    private Long flushInterval = 10L;

    /**
     * 设置重试机制时间间隔(秒), 默认1秒重试3次,和 backoffPolicyNumber 重试次数组合使用
     */
    private Long backoffPolicySeconds = 1L;

    /**
     * 设置重试机制的次数,默认1秒重试3次,和 backoffPolicySeconds 组合使用
     */
    private Integer backoffPolicyNumber = 3;

    private String userName = "";

    private String password = "";
}

EsConstant 常量类

public class EsConstant {

    /**
     * 系统编码和业务编码下唯一标识
     */
    public static final String ES_ID = "id";

    public static final String HTTP_STR = "http";
}

以上所有是目前暂时实现的。若有其他可以留言互相探讨

相关文章

网友评论

      本文标题:ES 7.x (ElasticSearch) 与Java集成使用

      本文链接:https://www.haomeiwen.com/subject/savplktx.html