springboot+mybatisPlus集成ES(RestClient方式)

目前springboot整合ES主要有四种方法,分别是TransportClient、RestClient、SpringData-Es、Elasticsearch-SQL。其中官方推荐的是RestClient,本文主要也是说明下RestClient方式的集成,该方式配置同时支持ES单机和ES集群。(MybatisPlus仅在下文的分页查询用到了MybatisPlus的包)
一、环境及版本说明
ES运行方式:ES集群启动(三个节点)
ES组件版本:7.4.2
ES中创建索引:test_index ,包含哪些字段参考下文的实体类TestIndex.java
二、搭建过程
1,pom文件中引入依赖,需要注意:引入的ES依赖版本需要和安装的ES组件版本一致,restClient依赖的版本中包含ES,但是不一定和restClient版本一致,所以需要移除restClient依赖中的ES,然后自己引入ES对应版本的依赖

<!-- Java High Level REST Client -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <exclusions>
    	<exclusion>
        	<groupId>org.elasticsearch</groupId>
        	<artifactId>elasticsearch</artifactId>
     	</exclusion>
     </exclusions>
     <version>7.4.2</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.4.2</version>
</dependency>

2,yaml配置文件中关于ES的配置

# ElasticSearch配置
es:
  ip: 192.168.1.1,192.168.1.2,192.168.1.3  #ES为集群时多个IP用英文逗号分隔;若为单机时只填写一个IP即可
  port: 9200
  protocal: http
  username: elastic       #若没有设置账号则用双引号代替 ("")
  password: elastic1234   #若没有设置密码则用双引号代替 ("")

3,SpringBoot项目中关于ES的配置文件

package com.demo.config;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ESRestClientConfig {
    @Value("${es.ip}")
    private String esIps;
    @Value("${es.port}")
    private int esPort;
    @Value("${es.protocal}")
    private String protocal;
    @Value("${es.username}")
    private String username;
    @Value("${es.password}")
    private String password;

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        // 1,若有多个从节点可以持续在内部new多个HttpHost,参数1是IP,参数2是端口,参数3是通信协议
        String[] esIpArray = esIps.split(",");
        HttpHost[] httpHostList = new HttpHost[esIpArray.length];
        for (int i=0;i<esIpArray.length;i++) {
            httpHostList[i] = new HttpHost(esIpArray[i],esPort,protocal);
        }

        RestClientBuilder builder = RestClient.builder(httpHostList);
        
        // 2,若存在账号密码,则初始化账号密码
        if(username != null && username != ""){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(username, password));

            builder.setHttpClientConfigCallback((httpClientBuilder) -> {
                httpClientBuilder.disableAuthCaching();
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                return httpClientBuilder;
            });
        }

		// 3, 创建客户端
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);

        return restHighLevelClient;
    }
}

4,ES索引对应实体类创建

package com.demo.domain;

import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;

@Data
public class TestIndex implements Serializable {
    private static final long serialVersionUID = 3199902908452021663L;
    /**
     * 测试字段1
     */
    private String id;
     /**
     * 测试字段2
     */
    private String endpoint;
    /**
     * 测试字段3
     */
    private String metric;
    /**
     * 测试字段4
     */
    private Date ts;
    /**
     * 测试字段5
     */
    private Integer step;
}

5,ES操作接口及实现

package com.demo.service;

import com.demo.domain.TestIndex ;

import java.io.IOException;

public interface IESOperateService {

    /**
     * 添加索引内容
     * @throws IOException
     */
    public void addIndexData(TestIndex testIndex) throws IOException;

    /**
     * 根据ID删除索引内容
     * @throws IOException
     */
    public void deleteIndexData(String id) throws IOException;

    /**
     * 根据文件ID查询文件
     * @throws IOException
     */
    public TestIndex getIndexDataById(String id) throws IOException;
   
    /**
     * 分页查询索引数据
     */
    public Page<TestIndex> pageIndexData() throws Exception;
}

package com.demo.service;

import com.demo.domain.TestIndex ;
import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.delete.DeleteRequest;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class ESOperateServiceImpl implements IESOperateService {
    // ES中的索引名称
    private static final String INDEX_NAME="test_index";

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public void addIndexData(TestIndex testIndex) throws IOException {
        // IndexRequest
        IndexRequest indexRequest = new IndexRequest(INDEX_NAME);
        String source = JSON.toJSONString(testIndex);
        indexRequest.id(testIndex.getId()).source(source, XContentType.JSON);

        restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    }


    @Override
    public void deleteIndexData(String id) throws IOException {
        // DeleteRequest
        DeleteRequest deleteRequest = new DeleteRequest(INDEX_NAME, id);

        // 操作ES
        restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
    }

    @Override
    public TestIndex getIndexDataById(String id) throws IOException {
        // SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(INDEX_NAME);

        // 构建检索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 根据字段匹配
        QueryBuilder queryBuilder = QueryBuilders.matchQuery("id",id);
        searchSourceBuilder.query(queryBuilder);
        searchRequest.source(searchSourceBuilder);

        // 查询ES
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();

        // 遍历封装列表对象
        List<TestIndex> testIndexList = new ArrayList<>();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            testIndexList.add(JSON.parseObject(searchHit.getSourceAsString(), TestIndex.class));
        }

        if (!CollectionUtils.isEmpty(testIndexList )) {
            return testIndexList .get(0);
        } else {
            return null;
        }
    }

	 @Override
    public Page<TestIndex> pageIndexData() throws Exception {
        // SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(INDEX_NAME);

        // 设置分页,含尾不含头(例如第一页为0-10,第二页为10-20)
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.from(0);  // 起始位置
        searchSourceBuilder.size(10); // 结束位置

        // 根据字段匹配
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("metric", "testMetric"));

		// 时间范围匹配,相当于between and ,因ES中日期数据为格林威治时间格式,故需要将日期转为格林威治时间格式
        Date currentDate = new Date();
        String beginTs = DateUtil.beginOfMonth(currentDate).toString().replace(" ","T");
        String endTs = DateUtil.endOfMonth(currentDate).toString().replace(" ","T");
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery("ts").from(beginTs).to(endTs);
        boolQueryBuilder.must(queryBuilder);

        // 模糊匹配
        QueryBuilder queryBuilder1 = QueryBuilders.wildcardQuery("endpoint", ("*test*"));
        boolQueryBuilder.must(queryBuilder1);

        // 放开分页查询最多10000条的限制,ES默认最多能10000条数据,若需要解除限制,下面配置设为true即可
        // 需要注意的是:放开ES最大返回值的限制后,相当于深度分页了,对于ES的性能有很大影响,需慎重使用
        searchSourceBuilder.trackTotalHits(true);
		
		// 结果排序
        searchSourceBuilder.query(boolQueryBuilder).sort("ts", SortOrder.DESC);
        searchRequest.source(searchSourceBuilder);

        // 执行ES查询动作
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();

        // 遍历封装列表对象
        List<TestIndex> testIndexList = new ArrayList<>();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            testIndexList.add(JSON.parseObject(searchHit.getSourceAsString(), TestIndex.class));
        }

        Page<TestIndex> pageDto = new Page();
        // 设置当前页码,我这里是写死的分页数据,应用到实际项目还是需要动态传入参数的
        pageDto.setCurrent(1).setRecords(testIndexList).
                setTotal(hits.getTotalHits().value).setSize(10);

        return pageDto;
    }
}

6,ES操作controller层实现测试代码

package com.demo.controller;

import com.demo.service.IESOperateService;
import com.demo.domain.TestIndex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class ESController
{
    @Autowired
    private IESOperateService esOperateService;

    @GetMapping("/addIndexData")
    public void addIndexData() {
 		TestIndex testIndex= new TestIndex();
        testIndex.setId("123456789");
        testIndex.setMetric("testMetric");
        testIndex.setEndpoint("testEndpoint");
        testIndex.setStep(100);

        esOperateService.addIndexData(testIndex);            
    }

    // 控制层调用service接口比较简单,就不一一都写出来了,测试话都可以参考上例
}

你可能感兴趣的:(elasticsearch,mybatis,spring,boot)