SpringBoot整合elasticsearch-rest-client实战

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: SpringBoot整合elasticsearch-rest-client实战

前言


很多人在Spring boot项目中都已经习惯采用Spring家族封装的spring-data-elasticsearch来操作elasticsearch,而官方更推荐采用rest-client。

今天给大家介绍下在spring boot中如何整合rest-client操作elasticsearch。


一、为什么不使用Spring家族封装的spring-data-elasticsearch?


主要是灵活性和更新速度。

spring将elasticsearch过度封装,让开发者很难跟ES的DSL查询语句进行关联。再者就是更新速度,ES的更新速度是非常快的,但是spring-data-elasticsearch更新速度比较缓慢。

另外,spring-data-elasticsearch底层依赖的是TransportClient。而TransportClient在ES7中已被弃用,取而代之的是 Java 高级 REST 客户端,并将在 Elasticsearch 8.0 中删除。

62.png


ElasticsearchRepository的优缺点:

优点: 简单,SpringBoot无缝对接,配置简单

缺点: 基于即将废弃的TransportClient, 不能支持复杂的业务


基于此,强烈建议采用官方推出的java客户端elasticsearch-rest-high-level-client,它的代码写法跟DSL语句很相似,懂ES查询的使用其上手很快。


二、低级REST客户端和高级REST客户端的关系


使用Elasticsearch服务,则要先获取一个Elasticsearch客户端。获取Elasticsearch客户端的方法很简单,最常见的就是创建一个可以连接到集群的传输客户端对象。


在Elasticsearch中,客户端有初级客户端和高级客户端两种,它们均使用Elasticsearch提供了RESTful风格的API,在使用RESTful API时,一般通过9200端口与Elasticsearch进行通信。


初级客户端是Elasticsearch为用户提供的官方版初级客户端。初级客户端允许通过HTTP与Elasticsearch集群进行通信,它将请求封装发给Elasticsearch集群,将Elasticsearch集群的响应封装返回给用户。初级客户端与所有Elasticsearch版本都兼容。


高级客户端是用于弹性搜索的高级客户端,它基于初级客户端。高级客户端公开了API特定的方法,并负责处理未编组的请求和响应。


官网对java-rest客户端的特性介绍:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-low.html


java low-level client特性:


最小依赖

针对可用节点,负载均衡

针对错误和故障节点可以进行故障转移

针对某个节点连接失败次数越多,客户端就会等待更长的时间,才会再次尝试这个节点

持久连接

请求日志追踪

原子性操作

java High-level client特性:


在 Java 低级 REST 客户端之上运行

主要目标是公开 API 特定的方法

每个API都有同步和异步调用

Java High Level REST Client 依赖于 Elasticsearch 核心项目

简单来说:

low-level client 最小依赖,兼容性更好,使用更灵活。

High-level client基于low-level client ,它的主要目标是公开 API 特定的方法,封装性更好,使用更方便。


三、实战


示例主要演示low-level client 和High-level client的基本用法,所以只包含客户端的获取和简单的查询示例。


1、添加maven依赖

<properties>
        <java.version>1.8</java.version>
        <es.version>7.10.2</es.version>
        <monitor.version>1.2.7.5.RELEASE</monitor.version>
        <skipTests>true</skipTests>
    </properties>
        <!-- es的starter, 主要是为了实现自动化配置,方便快捷的获取rest client -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.data</groupId>
                    <artifactId>spring-data-elasticsearch</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- low-level client -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>${es.version}</version>
        </dependency>
        <!-- high-level client ,默认依赖的elasticsearch存在版本差异,排除后添加统一的es版本-->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${es.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
     <!-- 使用low-level client不需要,但是high-level client需要依赖-->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${es.version}</version>
        </dependency>


2、配置ES连接属性

#es配置
spring.elasticsearch.rest.uris = http://localhost:9200
spring.elasticsearch.rest.username = elastic
spring.elasticsearch.rest.password = 123456
spring.elasticsearch.rest.connection-timeout = 10s
spring.elasticsearch.rest.read-timeout = 30s

3、RestClient、RestHighLevelClient使用

@SpringBootTest
@Slf4j
public class EsTest {
    @Autowired
    private RestClient restClient;
    @Autowired
    private RestHighLevelClient highLevelClient;
    /**
     * low-rest client测试类
     * 说明:根据DSL语句发起请求
     * 同步请求  performRequest
     * 异步请求  performRequestAsync
     */
    @Test
    public void lowClientTest() {
        try{
            //DSL查询语句
            String queryString = "{\"query\":{\"match_all\":{}},\"sort\":{\"crawler_time\":{\"order\":\"desc\"}},\"from\":0,\"size\":2}";
            HttpEntity entity = new NStringEntity(queryString, ContentType.APPLICATION_JSON);
            //指定请求方法和索引
            Request request = new Request("GET", "/user_info_*/_search");
            request.setEntity(entity);
            Map<String, String> params = Collections.emptyMap();
            request.addParameters(params);
            //发起请求
            Response response = restClient.performRequest(request);
            if(response!=null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()){
                String responseBody = EntityUtils.toString(response.getEntity());
                JSONObject jsonObject = JSON.parseObject(responseBody);
                JSONObject jsonObject1 = (JSONObject)((JSONObject)jsonObject.get("hits")).get("total");
                if(jsonObject1.get("value")!=null){
                    Integer total = (Integer) jsonObject1.get("value");
                    System.out.println("总记录数:" + total);
                }
                //处理返回结果
                JSONArray jsonArray = (JSONArray)((JSONObject)jsonObject.get("hits")).get("hits");
                List<UserInfo> infoList = jsonArray.stream().map(e->{
                    JSONObject source = (JSONObject) ((JSONObject)e).get("_source");
                    return  JSON.parseObject(JSON.toJSONString(source), UserInfo.class);
                }).collect(Collectors.toList());
                infoList.forEach(e->{
                    System.out.println(e.toString());
                });
            }
        }catch (Exception e){
            log.error("lowClientTest fail",e);
        }
    }
    /**
     * high-rest Client测试类
     * 说明:通过SearchRequest、SearchSourceBuilder、QueryBuilders构建请求,API封装的更丰富
     */
    @Test
    public void highRestClientTest(){
        String indice = "user_info_*";
        SearchRequest searchRequest = new SearchRequest(indice);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        log.info("ES查询DSL语句:\nGET  {}\n{}", String.format("/%s/_search",searchRequest.indices()[0]),sourceBuilder);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse response = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Arrays.stream(response.getHits().getHits())
                    .forEach(i -> {
                        //索引名称
                        System.out.println(i.getIndex());
                        System.out.println(i.getSourceAsString());
                    });
            System.out.println("记录总数:" + response.getHits().getTotalHits().value);
        } catch (Exception e) {
            log.error("highRestClientTest fail",e);
        }
    }
    }


4、spring-boot-starter-data-elasticsearch说明

RestClientAutoConfiguration自动化配置类:

61.png

RestClientConfigurations核心源码

class RestClientConfigurations {
     /**
      * 声明RestClient的bean
      */
        @Bean
        @ConditionalOnMissingBean
        RestClient elasticsearchRestClient(RestClientBuilder builder) {
            return builder.build();
        }
    }
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({RestHighLevelClient.class})
    static class RestHighLevelClientConfiguration {
        RestHighLevelClientConfiguration() {
        }
     /**
      * 声明RestHighLevelClient
      */
        @Bean
        @ConditionalOnMissingBean
        RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
            return new RestHighLevelClient(restClientBuilder);
        }
     /**
       * 声明RestClient的bean
       */
        @Bean
        @ConditionalOnMissingBean
        RestClient elasticsearchRestClient(RestClientBuilder builder, ObjectProvider<RestHighLevelClient> restHighLevelClient) {
            RestHighLevelClient client = (RestHighLevelClient)restHighLevelClient.getIfUnique();
            return client != null ? client.getLowLevelClient() : builder.build();
        }
    }


说明:

引入spring-boot-starter-data-elasticsearch自动化配置类,主要是简化配置,更方便的获取RestClient和RestHighLevelClient。


总结


本文主要介绍类如下内容:

1、为什么弃用spring-data-elasticsearch?

2、es中低级RestClient和高级RestHighLevelClient的特性和区别

3、spring boot中如何通过RestClient和RestHighLevelClient访问elasticsearch

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
1月前
|
存储 搜索推荐 Java
|
2月前
|
Java
【极问系列】springBoot集成elasticsearch出现Unable to parse response body for Response
【极问系列】springBoot集成elasticsearch出现Unable to parse response body for Response
|
30天前
|
消息中间件 Java 关系型数据库
【二十】springboot整合ElasticSearch实战(万字篇)
【二十】springboot整合ElasticSearch实战(万字篇)
186 47
|
2月前
|
Java Windows
【极光系列】springBoot集成elasticsearch
【极光系列】springBoot集成elasticsearch
|
2月前
|
Java Docker 容器
springboot整合后台框架(三)整合elasticsearch
springboot整合后台框架(三)整合elasticsearch
31 0
|
3月前
|
Java
Springboot整合Elasticsearch 7.X 复杂查询
这里使用Springboot 2.7.12版本,Elasticsearch为7.15.0。
Springboot整合Elasticsearch 7.X 复杂查询
|
3月前
|
Java
SpringBoot中进行elasticSearch查询,使用QueryBuilders构建各类条件查询
SpringBoot中进行elasticSearch查询,使用QueryBuilders构建各类条件查询
59 0
|
3天前
|
数据可视化 索引
elasticsearch head、kibana 安装和使用
elasticsearch head、kibana 安装和使用
|
16天前
|
存储 负载均衡 索引
linux7安装elasticsearch-7.4.0集群配置
linux7安装elasticsearch-7.4.0集群配置
106 0
|
2月前
|
存储 监控 搜索推荐
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——安装篇(一)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——安装篇(一)