1. 概述

Quarkus 是一个现代化框架,能轻松愉快地构建高性能应用。本教程将探讨如何将 Quarkus 与 Elasticsearch 集成——这是一个知名的全文搜索引擎和 NoSQL 数据存储系统。

2. 依赖与配置

确保本地已运行 Elasticsearch 实例 后,向 Quarkus 应用添加以下依赖:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elasticsearch-rest-client</artifactId>
    <version>${quarkus.version}</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elasticsearch-java-client</artifactId>
    <version>${quarkus.version}</version>
</dependency>

我们添加了两个关键依赖:

  • quarkus-elasticsearch-rest-client:提供低级 Elasticsearch REST 客户端
  • quarkus-elasticsearch-java-client:提供高级 Elasticsearch Java 客户端

根据实际需求选择合适的客户端

接下来在 application.properties 中配置 Elasticsearch 主机地址:

quarkus.elasticsearch.hosts=localhost:9200

⚠️ 配置完成后,ElasticsearchRestClientProducerElasticsearchJavaClientProducer 会自动创建必要的 Bean,无需手动干预。

3. Elasticsearch 低级 REST 客户端

使用 低级 REST 客户端 可以完全控制序列化/反序列化过程,并通过 JSON 构建查询。

首先创建索引模型:

public class StoreItem {
    private String id;
    private String name;
    private Long price;
    //getters and setters
}

模型包含文档 ID 字段和用于搜索的附加字段。

实现索引方法:

private void indexUsingRestClient() throws IOException, InterruptedException {
    iosPhone = new StoreItem();
    iosPhone.setId(UUID.randomUUID().toString());
    iosPhone.setPrice(1000L);
    iosPhone.setName("IOS smartphone");

    Request restRequest = new Request(
      "PUT",
      "/store-items/_doc/" + iosPhone.getId());
    restRequest.setJsonEntity(JsonObject.mapFrom(iosPhone).toString());
    restClient.performRequest(restRequest);
}

核心步骤:

  1. 创建带随机 ID 的 StoreItem
  2. 通过 PUT 请求索引到 /store-items/_doc/{id} 路径

验证索引和搜索的测试方法:

@Test
void givenRestClient_whenSearchInStoreItemsByName_thenExpectedDocumentsFound() throws Exception {
    indexUsingRestClient();

    Request request = new Request(
      "GET",
      "/store-items/_search");

    JsonObject termJson = new JsonObject().put("name", "IOS smartphone");
    JsonObject matchJson = new JsonObject().put("match", termJson);
    JsonObject queryJson = new JsonObject().put("query", matchJson);
    request.setJsonEntity(queryJson.encode());

    Response response = restClient.performRequest(request);
    String responseBody = EntityUtils.toString(response.getEntity());

    JsonObject json = new JsonObject(responseBody);
    JsonArray hits = json.getJsonObject("hits").getJsonArray("hits");
    List<StoreItem> results = new ArrayList<>(hits.size());

    for (int i = 0; i < hits.size(); i++) {
        JsonObject hit = hits.getJsonObject(i);
        StoreItem fruit = hit.getJsonObject("_source").mapTo(StoreItem.class);
        results.add(fruit);
    }

    assertThat(results)
      .hasSize(1)
      .containsExactlyInAnyOrder(iosPhone);
}

关键流程:

  1. 索引文档
  2. 构建 JSON 查询
  3. 执行搜索请求
  4. 手动反序列化结果

需要自行处理所有序列化/反序列化逻辑

4. Elasticsearch Java 客户端

使用 高级 Java 客户端 可以通过 DSL 语法更优雅地构建查询。

索引实现方法:

private void indexUsingElasticsearchClient() throws IOException, InterruptedException {
    androidPhone = new StoreItem();
    androidPhone.setId(UUID.randomUUID().toString());
    androidPhone.setPrice(500L);
    androidPhone.setName("Android smartphone");

    IndexRequest<StoreItem> request = IndexRequest.of(
      b -> b.index("store-items")
        .id(androidPhone.getId())
        .document(androidPhone));

    elasticsearchClient.index(request);
}

核心操作:

  1. 创建 StoreItem 实例
  2. 构建 IndexRequest
  3. 通过客户端执行索引

搜索实现方法:

@Test
void givenElasticsearchClient_whenSearchInStoreItemsByName_thenExpectedDocumentsFound() throws Exception {
    indexUsingElasticsearchClient();
    Query query = QueryBuilders.match()
      .field("name")
      .query(FieldValue.of("Android smartphone"))
      .build()
      ._toQuery();

    SearchRequest request = SearchRequest.of(
      b -> b.index("store-items")
        .query(query)
    );
    SearchResponse<StoreItem> searchResponse = elasticsearchClient
      .search(request, StoreItem.class);

    HitsMetadata<StoreItem> hits = searchResponse.hits();
    List<StoreItem> results = hits.hits().stream()
      .map(Hit::source)
      .collect(Collectors.toList());

    assertThat(results)
      .hasSize(1)
      .containsExactlyInAnyOrder(androidPhone);
}

优势对比:

  • ✅ 使用 DSL 语法构建查询
  • ✅ 自动处理序列化/反序列化
  • ✅ 代码更简洁直观

5. 总结

Quarkus 为 Elasticsearch 集成提供了强大支持:

  1. 简单粗暴:只需添加依赖和简单配置即可快速启动
  2. 灵活选择:支持低级 REST 客户端和高级 Java 客户端
  3. 深度定制:可自行定义客户端 Bean 满足特殊需求

⚠️ 实际开发中建议根据场景选择:

  • 需要精细控制 JSON 处理 → 低级 REST 客户端
  • 追求开发效率 → 高级 Java 客户端

完整源码可在 GitHub 获取。


原始标题:Connecting to Elasticsearch Using Quarkus | Baeldung