乐趣区

关于elasticsearch:解决-Elasticsearch-8x-Java-API-中-Update-写入-null-值无效的问题

前言

Elasticsearch 是一个开源的分布式搜寻和剖析引擎,它能够帮忙用户在大规模数据集中疾速、精确地搜寻、剖析和可视化数据。ES 能够解决各种类型的数据,包含结构化、半结构化和非结构化数据,使其十分实用于大数据利用场景。

本文将具体介绍 Elasticsearch Java API 中 Update 写入 null 值有效的问题,以及如何排查、解决此类问题,同时分享笔者的一些反思。

问题形容

在应用 Elasticsearch 8.x 的 Java API 时,进行新增数据有以下办法:

  • Create:如果文档不存在,那么就创立它;存在会报错,产生异样报错不会影响其余操作。
  • Index:创立一个新文档或者替换一个现有的文档。
  • Update:局部更新一个文档(设置 upsert 为 true)

然而大多数状况下,新增一条数据通常会应用 Update 作为一个操作,因为不心愿做一个更新把整行给笼罩掉,在中间件同步当中通常会遇见多表汇聚的状况,这种状况就强依赖于 Update 更新某一些字段,而不是把整个文档给替换掉。

然而,当笔者在应用 BulkOperation 来结构多个 Update 操作时,将某个值为 null 的字段写入到 Elasticsearch 的 Index 中时,会发现该值无奈被正确地写入到 Index 中。

问题排查

笔者首先在 Kibana 中利用控制台进行试验,发现更新一条带有 null 值文档是没有能够的,也就是说明必定是咱们的代码中有问题,上面我将代码拆出来进行了测试.

首先应用 PUT 命令将一条数据写入到 Elasticsearch 中。

PUT index_test/_doc/1
{
    "age": 12,
    "name": "John Doe"
}

而后应用 Java API 来对 _id 为 1 的数据进行批改。

RestClient restClient = RestClient.builder(new HttpHost("xxx", 9200)).build();
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient client8 = new ElasticsearchClient(transport);

String indexName = "index_test";
String esIdVal = "1";

Map<String, Object> doc = new HashMap<>();
doc.put("age", null);
doc.put("name", null);

BulkOperation op = new BulkOperation.Builder().update(i -> i.action(new UpdateAction.Builder<>()
                    .doc(doc)
                    .docAsUpsert(true)
                    .build()).id(esIdVal)).build();

List<BulkOperation> list = Collections.singletonList(op);
    
BulkResponse response = client8.bulk(builder -> builder.index(indexName).operations(list));

logger.info(response.toString());

client.shutdown();

运行后果为:

{
    ...
    "result":"noop"
    ...
}

返回后果中的 result 为 noop,阐明 Elasticsearch 没有对文档进行理论的更新操作,然而申请的 doc 中携带了 null 值,这十分诡异,笔者还一度狐疑是 Elasticsearch 的 Java API 出了 Bug。

起初在代码 Review 时,发现在初始化 ElasticsearchTransport 时,传入了 new JacksonJsonpMapper()。翻看源码发现,它利用了 Jackson 作为 Json 的序列化器;JacksonJsonpMapper 的默认初始化中有这样一段代码:

this(new ObjectMapper()
    .configure(SerializationFeature.INDENT_OUTPUT, false)
    .setSerializationInclusion(JsonInclude.Include.NON_NULL)
);

笔者看到 setSerializationInclusion(JsonInclude.Include.NON_NULL) 时,豁然开朗,这里配置的序列化默认将 null 值排除了,也就是批改传入的 ObjectMapper 就能够解决这个问题。

ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper(mapper));

代码批改后,null 值可能胜利地写入到 Elasticsearch 中了。

总结

本文介绍了在 Elasticsearch 8.x Java API 中 Update 写入 null 值有效的问题,并提供了一种解决方案。通过自定义 ObjectMapper 并将其传递给 JacksonJsonpMapper,咱们能够胜利地将 null 值写入到 Elasticsearch 中。同时,咱们也须要在应用 Elasticsearch Java API 时留神序列化器的配置,免得呈现相似的问题。

反思

在本文中,我分享了在应用 Elasticsearch 8.x Java API 进行 Update 操作时遇到的一个问题,即写入 null 值有效。通过代码排查,我发现是序列化器的默认配置导致的。解决方案是自定义 ObjectMapper 并将其传递给 JacksonJsonpMapper。这个问题的呈现让我反思了在应用 Elasticsearch 时须要对其外部实现有足够的理解,须要更加审慎地进行代码审核和测试,以及更加器重配置的影响。这些反思能够帮忙咱们更好地应用 Elasticsearch,并且可能防止一些潜在的问题。

退出移动版