17、ES实战:Java客户端

本学习笔记基于ElasticSearch 7.10版本,旧版本已经废弃的功能暂时不做笔记,以后有涉及到再做补充。

前面十六篇学习笔记,把 ElasticSearch 的基础知识都学了一遍,接下来我们开始学习如何使用 Java 操作 ElasticSearch。

一、Java 客户端简介

1、Java Http 请求

我们前面分享的 Es 基本操作都是 RESTful 风格的,也就是说,如果你掌握了 Es 基本操作,即使不学习 Es 的 Java 客户端,利用一些常见的 Java 网络请求工具都可以去操作 Es 了,例如 JDK 里边的 HttpUrlConnection,或者一些外部工具如 HttpClient、RestTemplate、OkHttp 等。

以HttpUrlConnection 为例,请求方式如下:

public class HttpRequestTest {
   
     
    public static void main(String[] args) throws IOException {
   
     
        URL url = new URL("http://localhost:9200/books/_search?pretty=true");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        if (con.getResponseCode() == 200) {
   
     
            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String str = null;
            while ((str = br.readLine()) != null) {
   
     
                System.out.println(str);
            }
        }
    }
}

上面的查询代码中,构造 Http 请求、构造请求参数、构造请求体等,然后手动发送请求,最后只是将响应数据打印到控制台,实际开发中还需要对 Json 结果进行解析。

而Java 客户端可以将上面一系列操作都封装成 API,减少重复的代码,提高开发效率。

2、常见客户端

目前ElasticSearch 的 Java 客户端大致上有如下几种:

  • TransportClient
  • Jest
  • Spring Data Elasticsearch
  • Java Low Level REST Client
  • Java High Level REST Client

TransportClient

大家在网上搜索 ElasticSearch 资料时,如果找到的是两年前的资料,应该会很容易看到 TransportClient。不过从 ElasticSearch7.0 开始,官方已经不再推荐使用 TransportClient,并且表示会在 ElasticSearch8.0 中完全移除相关支持。

我们本系列学习笔记,都是基于ElasticSearch7.10,就不考虑 TransportClient。

Jest

Jest 提供了更流畅的 API 和更容易使用的接口,并且它的版本是遵循 ElasticSearch 的主版本号的,这样可以确保客户端和服务端之间的兼容性。

早期的ElasticSearch 官方客户端对 RESTful 支持不够完美, Jest 在一定程度上弥补了官方客户端的不足,但是随着近两年官方客户端对 RESTful 功能的增强,Jest 早已成了明日黄花,最近的一次更新也停留在 2018 年 4 月,所以 我们也不必花时间去学习,知道曾经有过这么一个东西就行了。

Spring Data Elasticsearch

Spring Data 是 Spring 的一个子项目,用于简化数据库访问,支持NoSQL 和关系数据存储。

Spring Data 项目支持 NoSQL 存储:

  • MongoDB (文档数据库)
  • Neo4j(图形数据库)
  • Redis(键/值存储)
  • Hbase(列族数据库)
  • ElasticSearch

Spring Data 项目所支持的关系数据存储技术:

  • JDBC
  • JPA

Spring Data 其实是对一些既有的框架进行封装,从而使对数据的操作变得更加容易。Spring Data Elasticsearch 也是如此,它底层封装的就是官方的客户端 Java High Level REST Client,这个我们从它的依赖关系中就可以看出来:
*

Java Low Level REST Client

从字面上来理解,这个叫做低级客户端。

它允许通过 Http 与一个 Elasticsearch 集群通信。将请求的 JSON 参数拼接和响应的 JSON 字符串解析留给用户自己处理。低级客户端最大的优势在于兼容所有的 ElasticSearch 的版本(因为它的 API 并没有封装 JSON 操作,所有的 JSON 操作还是由开发者自己完成),同时低级客户端要求 JDK 为 1.7 及以上。

低级客户端主要包括如下一些功能:

  • 最小的依赖
  • 跨所有可用节点的负载均衡
  • 节点故障和特定响应代码时的故障转移
  • 连接失败重试(是否重试失败的节点取决于它失败的连续次数;失败次数越多,客户端在再次尝试同一节点之前等待的时间越长)
  • 持久连接
  • 跟踪请求和响应的日志记录
  • 可选自动发现集群节点

Java High Level REST Client

从字面上来理解,这个叫做高级客户端,也是目前使用最多的一种客户端。

它的内部基于低级客户端,只不过针对 ElasticSearch 它提供了更多的 API,将请求参数和响应参数都封装成了相应的 API,开发者只需要调用相关的方法就可以拼接参数或者解析响应结果。

Java High Level REST Client 中的每个 API 都可以同步或异步调用,同步方法返回一个响应对象,而异步方法的名称则以 Async 为后缀结尾,异步请求一般需要一个监听器参数,用来处理响应结果。

相对于低级客户端,高级客户端的兼容性就要差很多(因为 JSON 的拼接和解析它已经帮我们做好了)。高级客户端需要 JDK1.8 及以上版本并且依赖版本需要与 ElasticSearch 版本相同(主版本号需要一致,次版本号不必相同)。

举个简单例子:
7、 0客户端能够与任何7.xElasticSearch节点进行通信,而7.1客户端肯定能够与7.1,7.2和任何后来的7.x版本进行通信,但与旧版本的ElasticSearch节点通信时可能会存在不兼容的问题;

二、Java Low Level REST Client

前面我们尝试使用 Java Http 请求来操作 Es,下面使用 Es 的低级客户端来操作。
首先创建一个普通的 Maven 工程,添加如下依赖

<dependencies>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>7.10.0</version>
    </dependency>
</dependencies>

创建一个测试类,添加如下代码,发起一个简单的请求:

public class LowLevelTest {
   
     
    public static void main(String[] args) throws IOException {
   
     
        // 1.构建一个 RestClientBuilder 对象,里面添加三台 ElasticSearch 服务信息
        RestClientBuilder builder = RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http"),
                new HttpHost("localhost", 9202, "http")
        );
        // 2.如果需要在请求头中设置认证信息,可以通过 builder 来设置
        // builder.setDefaultHeaders(new Header[]{new BasicHeader("key", "value")});
        // 3.构建 RestClient 对象
        RestClient restClient = builder.build();
        // 4.构建请求
        Request request = new Request("Get", "/books/_search");
        // 5.添加请求参数
        request.addParameter("pretty","true");
        // 添加请求体
        request.setEntity(new NStringEntity("{\"query\": {\"term\": {\"name\": {\"value\": \"java\"}}}}", ContentType.APPLICATION_JSON));
        // 6.发起同步请求,同步请求会阻塞后面的代码
        Response response = restClient.performRequest(request);
        // 7.解析 response,获取响应结果
        BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String str = null;
        while ((str = br.readLine()) != null) {
   
     
            System.out.println(str);
        }
        br.close();
        // 8.关闭 RestClient
        restClient.close();
    }
}

上面这个查询请求,是一个同步请求,在请求的过程中,后面的代码会被阻塞。如果不希望后面的代码被阻塞,可以使用异步请求。异步请求需要配置响应监听器,采用回调的方式处理响应:

public class LowLevelTestAsync {
   
     
    public static void main(String[] args) throws IOException {
   
     
        // 1.构建一个 RestClientBuilder 对象,里面添加三台 ElasticSearch 服务信息
        RestClientBuilder builder = RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http"),
                new HttpHost("localhost", 9202, "http")
        );
        // 2.如果需要在请求头中设置认证信息,可以通过 builder 来设置
        // builder.setDefaultHeaders(new Header[]{new BasicHeader("key", "value")});
        // 3.构建 RestClient 对象
        RestClient restClient = builder.build();
        // 4.构建请求
        Request request = new Request("Get", "/books/_search");
        // 5.添加请求参数
        request.addParameter("pretty","true");
        // 添加请求体
        request.setEntity(new NStringEntity("{\"query\": {\"term\": {\"name\": {\"value\": \"java\"}}}}", ContentType.APPLICATION_JSON));
        // 6.发起异步请求,配置响应监听器
        restClient.performRequestAsync(request, new ResponseListener() {
   
     
            //请求成功的回调
            @Override
            public void onSuccess(Response response) {
   
     
                // 7.解析 response,获取响应结果
                try {
   
     
                    BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                    String str = null;
                    while ((str = br.readLine()) != null) {
   
     
                        System.out.println(str);
                    }
                    br.close();
                    // 8.关闭 RestClient
                    restClient.close();
                } catch (IOException e) {
   
     
                    e.printStackTrace();
                }
            }

            //请求失败的回调
            @Override
            public void onFailure(Exception e) {
   
     
                e.printStackTrace();
            }
        });
    }
}

版权声明:

本文仅记录ElasticSearch学习心得,如有侵权请联系删除。
更多内容请访问原创作者:江南一点雨
*

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: