Elasticsearch Java API Client 使用指南—官方原版

Posted Doker 多克

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch Java API Client 使用指南—官方原版相关的知识,希望对你有一定的参考价值。

以下部分提供了有关 Elasticsearch 最常用和一些不常用的功能的教程。

有关完整参考,请参阅 Elasticsearch 文档,特别是 REST API 部分。Java API 客户端使用 Java API 约定,严格遵循此处描述的 JSON 结构。

如果你是Elasticsearch的新手,请务必阅读Elasticsearch的快速入门,它提供了一个很好的介绍。

  • 为单个文档编制索引

  • 批量:为多个文档编制索引

  • 按 ID 读取文档

  • 搜索文档

  • 聚合

一、为单个文档编制索引

Java API 客户端提供了多种为数据编制索引的方法:您可以提供将自动映射到 JSON 的应用程序对象,也可以提供原始 JSON 数据。使用应用程序对象更适合具有明确定义的域模型的应用程序,而原始 JSON 更适合记录具有半结构化数据的用例。

在下面的示例中,我们使用一个Product域对象,该对象具有sku、name和price财产。

1、使用流利的DSL

构建请求的最直接方法是使用流利的DSL。在下面的示例中,我们使用产品的SKU作为索引中的文档标识符,为产品索引中的产品描述编制索引。产品对象将使用Elasticsearch客户端上配置的对象映射器映射到JSON。

Product product = new Product("bk-1", "City bike", 123.0);

IndexResponse response = esClient.index(i -> i
    .index("products")
    .id(product.getSku())
    .document(product)
);

logger.info("Indexed with version " + response.version());

您还可以将使用DSL创建的对象分配给变量。JavaAPI客户端类有一个静态of()方法,用于创建具有DSL语法的对象。

Product product = new Product("bk-1", "City bike", 123.0);

IndexRequest<Product> request = IndexRequest.of(i -> i
    .index("products")
    .id(product.getSku())
    .document(product)
);

IndexResponse response = esClient.index(request);

logger.info("Indexed with version " + response.version());

2、使用经典构建器

如果您更习惯于经典的构建器模式,它也可用。生成器对象由流畅的 DSL 语法在后台使用。

Product product = new Product("bk-1", "City bike", 123.0);

IndexRequest.Builder<Product> indexReqBuilder = new IndexRequest.Builder<>();
indexReqBuilder.index("product");
indexReqBuilder.id(product.getSku());
indexReqBuilder.document(product);

IndexResponse response = esClient.index(indexReqBuilder.build());

logger.info("Indexed with version " + response.version());

3、使用异步客户端

上面的例子使用了同步的Elasticsearch客户端。所有 Elasticsearch API 在异步客户端中也可用,使用相同的请求和响应类型

ElasticsearchAsyncClient esAsyncClient = new ElasticsearchAsyncClient(transport);

Product product = new Product("bk-1", "City bike", 123.0);

esAsyncClient.index(i -> i
    .index("products")
    .id(product.getSku())
    .document(product)
).whenComplete((response, exception) -> 
    if (exception != null) 
        logger.error("Failed to index", exception);
     else 
        logger.info("Indexed with version " + response.version());
    
);

4、使用原始 JSON 数据

当要编制索引的数据来自外部源时,对于半结构化数据,必须创建域对象可能很麻烦或完全不可能。

Reader input = new StringReader(
    "'@timestamp': '2022-04-08T13:55:32Z', 'level': 'warn', 'message': 'Some log message'"
    .replace('\\'', '"'));

IndexRequest<JsonData> request = IndexRequest.of(i -> i
    .index("logs")
    .withJson(input)
);

IndexResponse response = esClient.index(request);

logger.info("Indexed with version " + response.version());

二、批量:为多个文档编制索引

批量请求允许在一个请求中向 Elasticsearch 发送多个与文档相关的操作。当您有多个文档要引入时,这比使用单独的请求发送每个文档更有效。

批量请求可以包含多种操作:

  • 创建一个文档,在确保它不存在后为其编制索引,

  • 为文档编制索引,在需要时创建它并替换它(如果存在),

  • 使用脚本或部分文档更新已存在的文档,

  • 删除文档。

1、为程序对象编制索引

BulkRequest包含一个操作集合,每个操作都是一个具有多个变量的类型。为了创建这个请求,可以方便地为主请求使用构建器对象,为每个操作使用流畅的DSL。

下面的示例显示了如何索引列表或应用程序对象。

List<Product> products = fetchProducts();

BulkRequest.Builder br = new BulkRequest.Builder();

for (Product product : products) 
    br.operations(op -> op         (1)  
        .index(idx -> idx          (2)
            .index("products")     (3) 
            .id(product.getSku())
            .document(product)
        )
    );


BulkResponse result = esClient.bulk(br.build());

// Log errors, if any
if (result.errors()) 
    logger.error("Bulk had errors");
    for (BulkResponseItem item: result.items()) 
        if (item.error() != null) 
            logger.error(item.error().reason());
        
    

(1)添加一个操作(记住列表财产是加法的)。op is是BulkOperation的生成器,BulkOperation是一种变体类型。此类型具有索引、创建、更新和删除变量。

(2)选择索引操作变量,idx是IndexOperation的生成器。

(2)设置索引操作的财产,类似于单个文档索引:索引名称、标识符和文档。

2、为原始 JSON 数据编制索引

批量索引请求的属性可以是可以使用 Elasticsearch 客户端的 JSON 映射器序列化为 JSON 的任何对象。

批量索引请求的文档属性可以是任何可以使用Elasticsearch客户端的JSON映射器序列化为JSON的对象。在下面的示例中,我们将使用JavaAPI客户端的JsonData对象从日志目录中读取json文件,并在批量请求中发送这些文件。

由于JsonData不允许直接从输入流读取(这将在未来版本中添加),因此我们将使用以下函数:

public static JsonData readJson(InputStream input, ElasticsearchClient esClient) 
    JsonpMapper jsonpMapper = esClient._transport().jsonpMapper();
    JsonProvider jsonProvider = jsonpMapper.jsonProvider();

    return JsonData.from(jsonProvider.createParser(input), jsonpMapper);

现在我们可以读取日志目录的内容并将其发送到 Elasticsearch:

File[] logFiles = logDir.listFiles(
    file -> file.getName().matches("log-.*\\\\.json")
);

BulkRequest.Builder br = new BulkRequest.Builder();

for (File file: logFiles) 
    JsonData json = readJson(new FileInputStream(file), esClient);

    br.operations(op -> op
        .index(idx -> idx
            .index("logs")
            .document(json)
        )
    );

三、按 ID 读取文档

Elasticsearch 是关于搜索的,但您可能还想直接访问文档,知道它们的标识符。“get”请求就是为此而设计的。

1、读取域对象

下面的示例从产品索引中读取标识符为bk-1的文档。

get请求有两个参数:

  • 第一个参数是实际请求,在下面使用fluent DSL构建

  • 第二个参数是我们希望将文档的JSON映射到的类。

GetResponse<Product> response = esClient.get(g -> g
    .index("products") (1)
    .id("bk-1"),
    Product.class      (2)
);

if (response.found()) 
    Product product = response.source();
    logger.info("Product name " + product.getName());
 else 
    logger.info ("Product not found");

(1)get 请求,包含索引名称和标识符。

(2)目标类,此处为Product。

2、读取原始 JSON

当您的索引包含半结构化数据或您没有域对象定义时,您还可以将文档作为原始 JSON 数据读取。

原始JSON数据只是另一个类,可以用作get请求的结果类型。在下面的示例中,我们使用Jackson的ObjectNode。我们还可以使用任何可以由与ElasticsearchClient关联的JSON映射器反序列化的JSON表示。

GetResponse<ObjectNode> response = esClient.get(g -> g
    .index("products")
    .id("bk-1"),
    ObjectNode.class     (1)
);

if (response.found()) 
    ObjectNode json = response.source();
    String name = json.get("name").asText();
    logger.info("Product name " + name);
 else 
    logger.info("Product not found");

(1)目标类是一个原始JSON对象。

四、搜索文档

索引文档可用于近乎实时的搜索。

1、简单搜索查询

可以组合多种类型的搜索查询。我们将从简单的文本匹配查询开始,在产品索引中搜索自行车。

搜索结果有一个hits财产,其中包含与查询匹配的文档以及有关索引中存在的匹配总数的信息。

总值带有一个关系,表明总值是否精确(eq — 相等)或近似值(gte — 大于或等于)。

每个返回的文档都带有其相关性得分和有关其在索引中位置的附加信息。

String searchText = "bike";

SearchResponse<Product> response = esClient.search(s -> s
    .index("products") (1)
    .query(q -> q      (2)
        .match(t -> t   (3)
            .field("name")  (4)
            .query(searchText)
        )
    ),
    Product.class     (5) 
);

TotalHits total = response.hits().total();
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;

if (isExactResult) 
    logger.info("There are " + total.value() + " results");
 else 
    logger.info("There are more than " + total.value() + " results");


List<Hit<Product>> hits = response.hits().hits();
for (Hit<Product> hit: hits) 
    Product product = hit.source();
    logger.info("Found product " + product.getSku() + ", score " + hit.score());

(1)我们要搜索的索引的名称。

(2)搜索请求的查询部分(搜索请求还可以具有其他组件,如聚合)。

(3)在众多可用查询变体中选择一个查询变体。我们在这里选择匹配查询(全文搜索)。

(4)配置匹配查询:我们在name字段中搜索术语。

(5)匹配文档的目标类。我们在这里使用Product,就像在get请求示例中一样。

2、嵌套搜索查询

Elasticsearch允许将单个查询组合在一起,以构建更复杂的搜索请求。在下面的示例中,我们将搜索最高价格为 200 的自行车。

String searchText = "bike";
double maxPrice = 200.0;

// Search by product name
Query byName = MatchQuery.of(m -> m (1)
    .field("name")
    .query(searchText)
)._toQuery(); (2)

// Search by max price
Query byMaxPrice = RangeQuery.of(r -> r
    .field("price")
    .gte(JsonData.of(maxPrice)) (3)
)._toQuery();

// Combine name and price queries to search the product index
SearchResponse<Product> response = esClient.search(s -> s
    .index("products")
    .query(q -> q
        .bool(b -> b (4)
            .must(byName) (5)
            .must(byMaxPrice)
        )
    ),
    Product.class
);

List<Hit<Product>> hits = response.hits().hits();
for (Hit<Product> hit: hits) 
    Product product = hit.source();
    logger.info("Found product " + product.getSku() + ", score " + hit.score());

(1)我们将单独为各个条件创建查询。

(2)MatchQuery是一个查询变量,我们必须将其转换为查询联合类型。有关更多详细信息,请参见变量类型。

(3)MatchQuery是一个查询变量,我们必须将其转换为查询联合类型。有关更多详细信息,请参见变量类型。

(4)搜索查询是组合文本搜索和最高价格查询的布尔查询。

(5)这两个查询都必须添加,因为我们希望结果符合所有条件。

文章未完待续,大家如果喜欢,欢迎点赞和评论!或者加微信进入技术群聊!

以上是关于Elasticsearch Java API Client 使用指南—官方原版的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch Java API 很全的整理

Elasticsearch Java API - 客户端连接

java api操作elasticsearch

Elasticsearch Java API简要总汇

第08章 ElasticSearch Java API

elasticsearch java操作 api