Elastic 中国社区官方博客

Elastic 中国社区官方博客

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

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

Elasticsearch:使用 Low Level Java 客户端来创建连接 - Elastic Stack 8.x-LMLPHP在今天的文章中,我将使用另外一种方式来进行展示。我将使用 Low Level client API 来进行连接及访问。

安装

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

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

创建 Low Level Elasticsearch 客户端

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

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

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

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

pom.xml

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

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

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

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

</project>

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

ElasticsearchJavaLowLevel.java

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.
        HttpAsyncClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.*;

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

public class ElasticsearchJavaLowLevel {
    public static void main(String[] args) throws
            KeyManagementException, NoSuchAlgorithmException,
            KeyStoreException {
        RestClientBuilder clientBuilder = RestClient.
                builder(new HttpHost("localhost", 9200, "https"))
                .setCompressionEnabled(true);
        final CredentialsProvider credentialsProvider =
                new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(System.
                        getenv("ES_USER"), System.getenv("ES_PASSWORD")));
        final SSLContext sslContext = new
                SSLContextBuilder().loadTrustMaterial(null,
                TrustAllStrategy.INSTANCE).build();
        clientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            public HttpAsyncClientBuilder
            customizeHttpClient(HttpAsyncClientBuilder
                                        httpClientBuilder) {
                return httpClientBuilder
                        .setSSLContext(sslContext)
                        .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                        .setDefaultCredentialsProvider(credentialsProvider);
            }
        });
        RestClient client = clientBuilder.build();
        try {
            Request request = new Request("GET", "/mybooks/_doc/1");
                    Response response = client.
                    performRequest(request);
            if (response.getStatusLine().getStatusCode()
                    != HttpStatus.SC_OK) {
                System.err.println("Method failed: " +
                        response.getStatusLine());
            } else {
                HttpEntity entity = response.getEntity();
                String responseBody = EntityUtils.
                        toString(entity);
                System.out.println(responseBody);
            }
        } catch (IOException e) {
            System.err.println("Fatal transport error: "
                    + e.getMessage());
            e.printStackTrace();
        } finally {
        // Release the connection.
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

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

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

GET mybooks/_doc/1

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

PUT mybooks/_doc/1
{
  "uuid": "1",
  "title": "Great math"
}

解释

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

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

RestClientBuilder clientBuilder = RestClient.builder(new HttpHost("localhost", 9200, "https"))
// some stuff to setup SSL and auth as seen in previous
example
…
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<HttpResponse> 响应消费者:
    这用于管理异步请求中的响应(请参阅 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 响应。

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

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

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

07-13 19:42