设置
安装
Requirements: 要求:
- Java 8 或更高版本。
- 一个 JSON 对象映射库,允许您的应用程序类与 Elasticsearch API 无缝集成。 Java 客户端支持 Jackson 或 Eclipse Yasson 等 JSON-B 库。
版本托管在 Maven Central 上。如果您正在寻找 SNAPSHOT 版本,可以在 https://snapshots.elastic.co/maven/ 上找到 Elastic Maven Snapshot 存储库。
使用 Jackson 在 Gradle 项目中安装
dependencies {
implementation 'co.elastic.clients:elasticsearch-java:8.13.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
}
使用 Jackson 在 Maven 项目中安装
在项目的 pom.xml
中,添加以下存储库定义和依赖项:
<project>
<dependencies>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
</dependencies>
</project>
如果出现 ClassNotFoundException:jakarta.json.spi.JsonProvider
设置依赖项后,您的应用程序可能会失败并显示 ClassNotFoundException: jakarta.json.spi.JsonProvider
。
如果发生这种情况,您必须显式添加 jakarta.json:jakarta.json-api:2.0.1
依赖项。
Gradle:
dependencies {
...
implementation 'jakarta.json:jakarta.json-api:2.0.1'
}
Maven:
<project>
<dependencies>
...
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
</project>
为什么需要这个?
Spring Boot 或 Helidon 等一些框架附带了 Gradle 和 Maven 插件或 Maven BOM 文件,以简化开发和依赖项管理。这些插件和 BOM 定义了许多知名库使用的版本。
这些库之一可以是定义标准 Java JSON API 的 jakarta.json:json-api
。在版本 1.x
中,该库使用 javax.json
包,而在版本 2.x
中,从 JavaEE 转换到 JakartaEE 后,它使用 jakarta.json
包。
Java API 客户端依赖于该库的版本 2.0.1
,以便使用更新且面向未来的 jakarta.json
包。但某些构建插件和 BOM 会覆盖 Java API 客户端的依赖项,以在旧的 javax.json
命名空间中使用版本 1.x
,从而导致 ClassNotFoundException: jakarta.json.spi.JsonProvider
。
添加正确的版本作为顶级项目依赖项可以解决该问题。
如果您的应用程序还需要 javax.json
,您可以添加 javax.json:javax.json-api:1.1.4
依赖项,它相当于 jakarta.json:jakarta.json-api:1.1.6
。
连接
Java API 客户端围绕三个主要组件构建:
API 客户端类。它们为 Elasticsearch API 提供强类型数据结构和方法。由于 Elasticsearch API 很大,因此它是按功能组(也称为“命名空间”)构建的,每个功能组都有自己的客户端类。 Elasticsearch 核心功能在 ElasticsearchClient
类中实现。
JSON 对象映射器。这会将您的应用程序类映射到 JSON,并将它们与 API 客户端无缝集成。
传输层实现。这是所有 HTTP 请求处理发生的地方。
此代码片段创建这三个组件并将其连接在一起:
// URL and API key
String serverUrl = "https://localhost:9200";
String apiKey = "VnVhQ2ZHY0JDZGJrU...";
// Create the low-level client
RestClient restClient = RestClient
.builder(HttpHost.create(serverUrl))
.setDefaultHeaders(new Header[]{
new BasicHeader("Authorization", "ApiKey " + apiKey)
})
.build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient esClient = new ElasticsearchClient(transport);
身份验证由 Java 低级 REST 客户端管理。有关配置身份验证的更多详细信息,请参阅其文档。
第一个请求
下面的代码片段从“product”索引中搜索名称与“bicycle”匹配的所有项目,并将它们作为 Product
应用程序类的实例返回。
它说明了如何使用流畅的函数构建器将搜索查询编写为简洁的类似 DSL 的代码。 API 约定中更详细地解释了此模式。
SearchResponse<Product> search = esClient.search(s -> s
.index("products")
.query(q -> q
.term(t -> t
.field("name")
.value(v -> v.stringValue("bicycle"))
)),
Product.class);
for (Hit<Product> hit: search.hits().hits()) {
processProduct(hit.source());
}
使用安全连接
Java Low Level REST Client 文档详细解释了如何设置加密通信。
在自我管理安装中,Elasticsearch 将从启用身份验证和 TLS 等安全功能开始。要连接到 Elasticsearch 集群,您需要将 Java API 客户端配置为使用 HTTPS 和生成的 CA 证书,以便成功发出请求。
当您第一次启动 Elasticsearch 时,您会在 Elasticsearch 的输出中看到一个明显的块,如下所示(如果已经有一段时间了,您可能需要向上滚动):
-> Elasticsearch security features have been automatically configured!
-> Authentication is enabled and cluster connections are encrypted.
-> Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
lhQpLELkjkrawaBoaz0Q
-> HTTP CA certificate SHA-256 fingerprint:
a52dd93511e8c6045e21f16654b77c9ee0f34aea26d9f40320b531c474676228
...
记下弹性用户密码和 HTTP CA 指纹,以供后续部分使用。在下面的示例中,它们将分别存储在变量 password
和 fingerprint
中。
根据上下文,您有两种验证 HTTPS 连接的选项:使用 CA 证书本身进行验证或使用 CA 证书指纹。对于这两种情况,Java API Client 的 TransportUtils
类提供了方便的方法来轻松创建 SSLContext
。
使用证书指纹验证 HTTPS
这种验证 HTTPS 连接的方法使用前面记下的证书指纹值。
String fingerprint = "<certificate fingerprint>";
SSLContext sslContext = TransportUtils
.sslContextFromCaFingerprint(fingerprint); //使用证书指纹创建 SSLContext 。
BasicCredentialsProvider credsProv = new BasicCredentialsProvider(); //设置身份验证。
credsProv.setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials(login, password)
);
RestClient restClient = RestClient
.builder(new HttpHost(host, port, "https")) //不要忘记将协议设置为 https !
.setHttpClientConfigCallback(hc -> hc
.setSSLContext(sslContext) //使用 SSL 和身份验证配置配置 http 客户端。
.setDefaultCredentialsProvider(credsProv)
)
.build();
// Create the transport and the API client
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);
请注意,证书指纹也可以使用 openssl x509
和证书文件来计算:
openssl x509 -fingerprint -sha256 -noout -in /path/to/http_ca.crt
如果您无权访问 Elasticsearch 生成的 CA 文件,您可以使用以下脚本通过 openssl s_client
输出 Elasticsearch 实例的根 CA 指纹:
openssl s_client -connect localhost:9200 -servername localhost -showcerts </dev/null 2>/dev/null \
| openssl x509 -fingerprint -sha256 -noout -in /dev/stdin
使用 CA 证书验证 HTTPS
生成的根 CA 证书可以在 Elasticsearch 配置位置的 certs
目录中找到。如果您在 Docker 中运行 Elasticsearch,则还有用于检索 CA 证书的附加文档。
一旦您的应用程序可以使用 http_ca.crt
文件,您就可以使用它来设置客户端:
File certFile = new File("/path/to/http_ca.crt");
SSLContext sslContext = TransportUtils
.sslContextFromHttpCaCrt(certFile); //使用 http_ca.crt 文件创建 SSLContext 。
BasicCredentialsProvider credsProv = new BasicCredentialsProvider(); //设置身份验证
credsProv.setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials(login, password)
);
RestClient restClient = RestClient
.builder(new HttpHost(host, port, "https")) //不要忘记将协议设置为 https !
.setHttpClientConfigCallback(hc -> hc
.setSSLContext(sslContext) //使用 SSL 和身份验证配置配置 http 客户端。
.setDefaultCredentialsProvider(credsProv)
)
.build();
// Create the transport and the API client
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);
从高级 Rest 客户端迁移
Elasticsearch Java API 客户端是一个全新的客户端库,与旧的高级 Rest 客户端 (HLRC) 没有关系。这是一个经过深思熟虑的选择,旨在提供一个独立于 Elasticsearch 服务器代码的库,并为所有 Elasticsearch 功能提供非常一致且更易于使用的 API。
因此,从 HLRC 迁移需要在应用程序中重写一些代码。然而,这种转变可以逐步发生,因为两个客户端库可以在单个应用程序中共存,而无需任何操作开销。
兼容模式:使用 7.17 客户端和 Elasticsearch 8.x
通过启用 HLRC 的兼容模式,HLRC 版本 7.17
可以与 Elasticsearch 版本 8.x
一起使用(请参阅下面的代码示例)。在此模式下,HLRC 会发送额外的标头,指示 Elasticsearch 8.x
的行为类似于 7.x
服务器。
Java API 客户端不需要此设置,因为兼容模式始终处于启用状态。
您可以将 HLRC 版本 7.x
与 Java API 客户端版本 8.x
结合使用:
dependencies {
implementation 'co.elastic.clients:elasticsearch-java:8.13.2'
implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client:7.17.4'
// other dependencies
}
使用与 HLRC 和 Java API 客户端相同的 http 客户端
为了避免应用程序同时使用 HLRC 和新 Java API 客户端的过渡阶段的任何操作开销,两个客户端可以共享相同的低级 Rest 客户端,该客户端是管理所有连接、循环策略的网络层,节点嗅探等等。
下面的代码显示了如何使用相同的 HTTP 客户端初始化两个客户端:
// Create the low-level client
RestClient httpClient = RestClient.builder(
new HttpHost("localhost", 9200)
).build();
// Create the HLRC
RestHighLevelClient hlrc = new RestHighLevelClientBuilder(httpClient)
.setApiCompatibilityMode(true) //启用兼容模式,允许 HLRC 7.17 与 Elasticsearch 8.x 配合使用。
.build();
// Create the Java API Client with the same low level client
ElasticsearchTransport transport = new RestClientTransport(
httpClient,
new JacksonJsonpMapper()
);
ElasticsearchClient esClient = new ElasticsearchClient(transport);
// hlrc and esClient share the same httpClient
过渡策略
您可以通过多种方式开始在应用程序代码中摆脱 HLRC。
例如:
- 保持现有代码不变,并使用新的 Java API 客户端来实现应用程序中的新功能,然后迁移现有代码,
- 重写应用程序中新的 Java API 客户端比 HLRC 更容易使用的部分,例如与搜索相关的所有内容,
- 通过利用新的 Java API 客户端与 JSON 对象映射器的紧密集成,重写需要将应用程序对象映射到 JSON 或从 JSON 映射的部分。
使用OpenTelemetry
您可以使用 OpenTelemetry 通过 Java API 客户端监控 Elasticsearch 请求的性能和行为。 Java API 客户端附带内置 OpenTelemetry 工具,默认情况下会发出分布式跟踪跨度。这样,使用 OpenTelemetry 进行检测或运行 OpenTelemetry Java 代理的应用程序本质上就可以通过包含有关 Elasticsearch 请求执行的深入信息的附加跨度来丰富。
Java API 客户端中的本机检测遵循 Elasticsearch 的 OpenTelemetry 语义约定。特别是,客户端中的检测涵盖了逻辑 Elasticsearch 请求层,因此,为服务针对 Java API 客户端执行的每个请求创建一个跨度。下图显示了执行三个不同 Elasticsearch 请求的结果跟踪,即 index
、 get
和搜索 request
:
通常,OpenTelemetry 代理和自动检测模块附带对 HTTP 级通信的检测支持。在这种情况下,除了逻辑 Elasticsearch 客户端请求之外,还将捕获客户端发出的物理 HTTP 请求的跨度。下图显示了包含 Elasticsearch 跨度(蓝色)和相应的 HTTP 级别跨度(红色)的跟踪:
高级 Java API 客户端行为(例如节点循环和请求重试)通过逻辑 Elasticsearch 跨度和物理 HTTP 跨度的组合来显示。以下示例显示了具有两个 Elasticsearch 节点的场景中的 index
请求:
第一个节点不可用并导致 HTTP 错误,而重试第二个节点会成功。两个 HTTP 请求都包含在逻辑 Elasticsearch 请求范围(蓝色)中。
设置 OpenTelemetry 仪器
手动使用 OpenTelemetry Java SDK 或使用 OpenTelemetry Java 代理时,默认情况下启用 Java API 客户端的 OpenTelemetry 检测并使用全局注册的 OpenTelemetry SDK 实例(即 GlobalOpenTelemetry
)。因此,如果您不使用自定义的本地 OpenTelemetry SDK 实例,则无需进行显式设置即可使用 Java API 客户端的 OpenTelemetry 工具。(有默认自带的)
使用自定义 OpenTelemetry 实例
如果您将手动 OpenTelemetry 检测与未全局注册的自定义 OpenTelemetry SDK 实例结合使用,则可以使用自定义 OpenTelemetry 实例创建 Java API 客户端。以下代码片段显示了使用自定义 OpenTelemetry 实例的示例。
// URL and API key
String serverUrl = "https://localhost:9200";
String apiKey = "VnVhQ2ZHY0JDZGJrU...";
// Create the low-level client
RestClient restClient = RestClient
.builder(HttpHost.create(serverUrl))
.setDefaultHeaders(new Header[]{
new BasicHeader("Authorization", "ApiKey " + apiKey)
})
.build();
// Create and configure custom OpenTelemetry instance
OpenTelemetry customOtel = OpenTelemetrySdk.builder().build();
// Create Instrumentation instance using the custom OpenTelemetry instance
// Second constructor argument allows to enable/disable search body capturing
OpenTelemetryForElasticsearch esOtelInstrumentation =
new OpenTelemetryForElasticsearch(customOtel, false);
// Create the transport with the custom Instrumentation instance
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper(), null, esOtelInstrumentation
);
// And create the API client
ElasticsearchClient esClient = new ElasticsearchClient(transport);
配置 OpenTelemetry 仪器
您可以通过 Java 系统属性或环境变量配置 OpenTelemetry 工具。可以使用以下配置选项。
启用/禁用 OpenTelemetry 检测
Default: true
默认值: true
Java System Property |
|
Environment Variable |
|
捕获搜索请求正文
默认情况下,出于数据隐私原因,内置 OpenTelemetry 工具不会捕获请求正文。如果您希望捕获此信息,您可以使用此选项来从 Elasticsearch 搜索请求的请求正文中捕获搜索查询。
Default: false
默认值: false
Java System Property |
|
Environment Variable |
|
Overhead 高架
OpenTelemetry 仪器(与任何其他监控方法一样)可能会在 CPU、内存和/或延迟方面带来一些开销。仅当启用检测(默认)并且 OpenTelemetry SDK(或 OpenTelemetry Agent)在目标应用程序中处于活动状态时,才可能出现开销。如果检测被禁用或目标应用程序没有激活 OpenTelemetry SDK(或 OpenTelemetry Agent),则使用客户端时不会产生监视开销。
即使仪器已启用并正在积极使用(通过 OpenTelemetry SDK),在绝大多数情况下,开销也非常小且可以忽略不计。在存在明显开销的边缘情况下,可以显式禁用检测,以消除检测的任何潜在开销影响。