1、概览 {#1概览}
Quarkus 是一个现代框架,它能让你轻松高效地地构建高性能应用。
本文将带你了解如何在 Quarkus 中整合 Elasticsearch,一个著名的全文搜索引擎和 NoSQL 数据库。
2、依赖和配置 {#2依赖和配置}
首先,你需要在本地主机上运行 Elasticsearch 实例(推荐用 Docker 的方式)。
然后,在 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 客户端。
在我们的应用中,可以根据需要选择使用合适的客户端。
接下来,将 Elasticsearch HOST 添加到 application.properties 文件中:
quarkus.elasticsearch.hosts=localhost:9200
现在,我们可以开始在 Quarkus 应用中使用 Elasticsearch 了。ElasticsearchRestClientProducer
和 ElasticsearchJavaClientProducer
会自动创建所有必要的 Bean。
3、Elasticsearch 低级 REST 客户端 {#3elasticsearch-低级-rest-客户端}
我们可以使用 Elasticsearch 低级 REST 客户端 将应用与 Elasticsearch 集成。这使得我们可以完全控制序列化和反序列化过程,并允许我们使用 JSON 构建 Elasticsearch 的查询。
创建一个要在应用中索引的文档模型:
public class StoreItem {
private String id;
private String name;
private Long price;
// Getter / Setter 方法省略
}
在这个文档模型中,有一个id
字段。以及其他的一些用于检索的字段。
现在,实现索引 StoreItem
的方法:
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);
}
如上,创建了一个具有随机 id
和特定名称的 StoreItem
。然后,向 /store-items/_doc/{id}
路径执行一个 PUT
请求,以索引我们的文档。现在,我们要创建一个方法来验证我们的文档是否被成功地索引,并根据不同字段进行搜索:
@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);
}
我们使用 indexUsingRestClient()
方法索引了 StoreItem
。然后,创建 JSON 查询并执行搜索请求。最后对每个搜索结果进行反序列化,并验证其中是否包含 StoreItem
。
这样,我们就在 Quarkus 应用中使用底层 REST 客户端实现了与 Elasticsearch 的基本集成。如你所见,我们需要自己处理所有序列化和反序列化过程。
4、Elasticsearch Java 客户端 {#4elasticsearch-java-客户端}
Elasticsearch Java 客户端是更高级别的客户端。我们可以使用它的 DSL 语法更优雅地创建 Elasticsearch 查询。
使用该客户端创建一个方法来索引 StoreItem
:
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);
}
我们创建了另一个 StoreItem
文档,然后构建了 IndexRequest
。最后,调用 Elasticsearch Java 客户端的 index()
方法来执行请求。
现在,检索已保存的项目:
@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);
}
我们使用 indexUsingElasticsearchClient()
方法为新文档编制了索引。然后,创建了 SearchRequest
,并用 Elasticsearch Java 客户端执行了该请求,并将所有搜索结果收集到 StoreItem
集合中。
我们使用 DSL 语法创建查询,因此不必操心序列化和反序列化问题。
5、总结 {#5总结}
如你所见,在 Quarkus 中整合 Elasticsearch 只需添加相关依赖和几行配置即可。你可以选择使用底层的 REST 客户端或高级的 Java 客户端。如果你想要更多控制权,可以自己定义客户端 Bean。
Ref:https://www.baeldung.com/elasticsearch-quarkus-connect