Elasticsearch:使用 Low Level Java 客户端来创建连接 - Elastic Stack 8.x

320 阅读6分钟

由于在 Elastic Stack 8.x 中天然地添加了安全性,我们在使用 Java 客户端进行连接的时候,我们可以通过不同的途径来完成。在我之前的文章中,我创建了一系列的文章来展示:

在上面,我们可以通过 Java HTTP 的集成来访问 Elasticsearch。这个是不依赖于 Elasticsearch 的版本来进行访问的。我们也可以通过 Elastic 公司所提供的 Elasticsearch Java client 8.x 来进行访问。在通常的情况下,Elasticsearch Java client 会更为高效。它提供了良好的 JSON 支持以及对连接的管理。这样也是被推荐的方法。

在今天的文章中,我将使用另外一种方式来进行展示。我将使用 Low Level client API 来进行连接及访问。

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana。请参阅我之前的文章:

在默认的情况下,Elastic Stack 8.x 的安装已带有安全。如果你是自托管型的集群,那么你的证书应该是自签名的证书。

创建 Low Level Elasticsearch 客户端

有两个官方的 Elasticsearch 客户端:低级客户端和 Elasticsearch 8.x (github.com/elastic/ela…) 提供的新类型客户端。 低级用于与 Elasticsearch 通信,主要特点如下:

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

要创建 RestClient,我们将执行以下步骤:

1)我们需要添加用于执行 HTTP 调用的 Elasticsearch HTTP 客户端库。 该库位于 search.maven.org 的主 Maven 存储库中。 要在 Maven pom.xml 项目中启用编译,只需添加以下代码:

pom.xml



1.  <?xml version="1.0" encoding="UTF-8"?>
2.  <project xmlns="http://maven.apache.org/POM/4.0.0"
3.           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.           xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5.      <modelVersion>4.0.0</modelVersion>

7.      <groupId>org.example</groupId>
8.      <artifactId>ELasticsearchJava-lowlevel</artifactId>
9.      <version>1.0-SNAPSHOT</version>

11.      <properties>
12.          <maven.compiler.source>8</maven.compiler.source>
13.          <maven.compiler.target>8</maven.compiler.target>
14.      </properties>

16.      <dependencies>
17.          <dependency>
18.              <groupId>org.elasticsearch.client</groupId>
19.              <artifactId>elasticsearch-rest-client</artifactId>
20.              <version>8.0.0</version>
21.          </dependency>
22.      </dependencies>

24.  </project>


2)如果我们想实例化一个客户端并使用 get 方法获取一个文档,代码将如下所示:

ElasticsearchJavaLowLevel.java



1.  import org.apache.http.HttpEntity;
2.  import org.apache.http.HttpHost;
3.  import org.apache.http.HttpStatus;
4.  import org.apache.http.auth.AuthScope;
5.  import org.apache.http.auth.UsernamePasswordCredentials;
6.  import org.apache.http.client.CredentialsProvider;
7.  import org.apache.http.conn.ssl.NoopHostnameVerifier;
8.  import org.apache.http.conn.ssl.TrustAllStrategy;
9.  import org.apache.http.impl.client.BasicCredentialsProvider;
10.  import org.apache.http.impl.nio.client.
11.          HttpAsyncClientBuilder;
12.  import org.apache.http.ssl.SSLContextBuilder;
13.  import org.apache.http.util.EntityUtils;
14.  import org.elasticsearch.client.*;

16.  import java.io.IOException;
17.  import java.security.*;
18.  import javax.net.ssl.SSLContext;

20.  public class ElasticsearchJavaLowLevel {
21.      public static void main(String[] args) throws
22.              KeyManagementException, NoSuchAlgorithmException,
23.              KeyStoreException {
24.          RestClientBuilder clientBuilder = RestClient.
25.                  builder(new HttpHost("localhost", 9200, "https"))
26.                  .setCompressionEnabled(true);
27.          final CredentialsProvider credentialsProvider =
28.                  new BasicCredentialsProvider();
29.          credentialsProvider.setCredentials(AuthScope.ANY,
30.                  new UsernamePasswordCredentials(System.
31.                          getenv("ES_USER"), System.getenv("ES_PASSWORD")));
32.          final SSLContext sslContext = new
33.                  SSLContextBuilder().loadTrustMaterial(null,
34.                  TrustAllStrategy.INSTANCE).build();
35.          clientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
36.              public HttpAsyncClientBuilder
37.              customizeHttpClient(HttpAsyncClientBuilder
38.                                          httpClientBuilder) {
39.                  return httpClientBuilder
40.                          .setSSLContext(sslContext)
41.                          .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
42.                          .setDefaultCredentialsProvider(credentialsProvider);
43.              }
44.          });
45.          RestClient client = clientBuilder.build();
46.          try {
47.              Request request = new Request("GET", "/mybooks/_doc/1");
48.                      Response response = client.
49.                      performRequest(request);
50.              if (response.getStatusLine().getStatusCode()
51.                      != HttpStatus.SC_OK) {
52.                  System.err.println("Method failed: " +
53.                          response.getStatusLine());
54.              } else {
55.                  HttpEntity entity = response.getEntity();
56.                  String responseBody = EntityUtils.
57.                          toString(entity);
58.                  System.out.println(responseBody);
59.              }
60.          } catch (IOException e) {
61.              System.err.println("Fatal transport error: "
62.                      + e.getMessage());
63.              e.printStackTrace();
64.          } finally {
65.          // Release the connection.
66.              try {
67.                  client.close();
68.              } catch (IOException e) {
69.                  e.printStackTrace();
70.              }
71.          }
72.      }
73.  }


我们需要在环境变量中设置你访问 Elasticsearch 集群的用户名及密码。

上面的代码实现的功能相当于我们在 Kibana 下打入如下的命令:

GET mybooks/_doc/1

为了能够让上面的代码顺利执行,我们首先在 Kibana 中创建如下的一个索引:



1.  PUT mybooks/_doc/1
2.  {
3.    "uuid": "1",
4.    "title": "Great math"
5.  }


解释

在内部,Elasticsearch RestClient 客户端使用 Apache HttpComponents 库并用更方便的方法包装它。如果你想了解如何使用 Apache HttpComponents 来建立和 Elasticsearch 的连接,请参考我之前的文章 “ Elasticsearch:使用标准 Java HTTP 的集成 - Elastic Stack 8.x”。 我们执行了前面的步骤来创建和使用 RestClient。 让我们更详细地看一下它们:

 1)第一步是初始化 RestClient 对象。 这是通过以下代码片段完成的:



1.  RestClientBuilder clientBuilder = RestClient.builder(new HttpHost("localhost", 9200, "https"))
2.  // some stuff to setup SSL and auth as seen in previous
3.  example
4.  …
5.  RestClient client = clientBuilder.build();


builder 方法接受一个多值 HttpHost 主机(通过这种方式,你可以传递一个 HTTP 地址列表)并在后台返回 RestClientBuilder。

 2)RestClientBuilder 对象允许通过多种方法自定义客户端通信,例如:

  • setDefaultHeaders(Header[] defaultHeaders):这允许必须为要提供的每个请求发送的自定义标头。
  • setMaxRetryTimeoutMillis(int maxRetryTimeoutMillis):如果对同一请求有多次尝试,这允许定义最大重试超时。
  • setPathPrefix(String pathPrefix):这允许为每个请求定义自定义路径前缀。
  • setFailureListener(FailureListener failureListener):这允许提供自定义故障侦听器,在节点故障实例中调用该侦听器。 这可用于在节点故障的情况下提供用户定义的行为。
  • setHttpClientConfigCallback(RestClientBuilder.HttpClientConfigCallback httpClientConfigCallback):这允许修改 HTTP 客户端通信,例如添加压缩或加密层。
  • setRequestConfigCallback(RestClientBuilder.RequestConfigCallback requestConfigCallback):这允许配置请求身份验证、超时和其他可以在请求级别设置的属性。

3)创建 RestClient 后,我们可以通过几种 performRequest 方法对它执行一些请求,用于同步调用和 performRequestAsync 方法用于异步调用。这些方法允许你设置参数,例如:

  •  String method:这是要在调用中使用的 HTTP 方法或动词(必需)。
  •  String endpoint:这是 API 端点(必需)。 在前面的示例中,它是 /test-index/_doc/1。
  •  Map<String, String> params:这是要作为查询参数传递的值的映射。
  •  HttpEntity entity:这是请求的正文。 它是 org/apache/http/HttpEntity(有关更多详细信息,请参阅HttpEntity - httpcore 4.4.15 javadoc)。
  • HttpAsyncResponseConsumer 响应消费者:
    这用于管理异步请求中的响应(请参阅 HttpAsyncResponseConsumer (Apache HttpCore NIO 4.4.14 API)了解更多详细信息)。 默认情况下,它用于将所有响应保存在堆内存中(内存上限为 100 MB)。
  • ResponseListener responseListener:这用于在异步调用期间注册回调。
  • Header...header:这些是在调用期间传递的附加 header。

在前面的示例中,我们使用以下代码执行了 GET REST 调用:

Response response = client.performRequest(request);

响应对象是 org.elasticsearch.client.Response,它包装了 Apache HttpComponents 响应。

运行上面的代码,我们可以看到的结果为:



1.  {"_index":"mybooks","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{
2.    "uuid": "1",
3.    "title": "Great math"
4.  }
5.  }


我们可以看到它的结果和我们之前的是没有什么不同。