Spring Data Elasticsearch (4.x) - 在 _source 中使用 @Id 强制 id 字段

Oli*_*ich 6 java elasticsearch spring-data spring-boot spring-data-elasticsearch

概括

最近我们升级到 Spring Data Elasticsearch 4.x。这个主要版本的一部分意味着不再使用 Jackson 将我们的域对象转换为 json(MappingElasticsearchConverter改为使用)[1]。这意味着我们现在被迫id向所有文档添加一个新字段。

以前我们有这样的域对象:

import org.springframework.data.annotation.Id;

public ESDocument {
    @Id
    private String id;

    private String field1;

    @JsonIgnore
    public String getId() {
        return id;
    }

    public String getField1() {
        return field1;
    }
Run Code Online (Sandbox Code Playgroud)

这导致在 ES 中出现这样的文档:

{
  "_index" : "test_index",
  "_type" : "_doc",
  "_id" : "d5bf7b5c-7a44-42f9-94d6-d59fe3988482",
  "_score" : 1.0,
  "_source" : {
    "field1" : "blabla"
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:

  1. @JsonIgnore注释用来确保我们要求有一个id在外地_source
  2. 我们自己设置文档 ID,它以_id.

问题

在 Spring Data Elastic 4.x 中,@JsonIgnore注解不再受到尊重,这意味着我们现在被迫id_source如下所示的字段中有一个字段:

{
  "_index" : "test_index",
  "_type" : "_doc",
  "_id" : "d5bf7b5c-7a44-42f9-94d6-d59fe3988482",
  "_score" : 1.0,
  "_source" : {
    "id": "d5bf7b5c-7a44-42f9-94d6-d59fe3988482",
    "field1" : "blabla"
  }
}
Run Code Online (Sandbox Code Playgroud)

问题

  1. 是否不再可能省略文档标识符的重复(即在_idid字段中)?如果是这样怎么办?(请注意,我们已经尝试过@org.springframework.data.annotation.Transient哪个不起作用,因为 spring-data-elastic 认为我们的文档没有 id)。
  2. 我们之前抑制id场的方法是_source错误的还是有问题的?

版本

java: 1.8.0_252 elasticsearch
: 7.6.2
spring-boot: 2.3.1.RELEASE
spring-data-elastic: 4.0.1.RELEASE

参考

[1] - https://spring.io/blog/2020/05/27/what-s-new-in-spring-data-elasticsearch-4-0

P.J*_*sch 8

问题一:

要从_source中省略 id 字段,您通常会使用@Transient注释,但正如您所写,这对于 id 属性不起作用。Spring Data 模块(不仅是 Spring Data Elasticsearch)中会忽略瞬态属性。

但是你可以使用org.springframework.data.annotation.ReadOnlyProperty注释来实现这一点:

@Id
@ReadOnlyProperty
private String id;
Run Code Online (Sandbox Code Playgroud)

老实说,我到目前为止还不知道它的存在,它也来自 Spring Data Commons,并且isWriteable()MappingElasticsearchConverter.

问题2:

当然不是不正确,但正如您发现的那样,这是有问题的。我们在存储的时候总是考虑整个实体,所以我们从来没有想过不写id。严格来说,这是没有必要的,你是对的,因为我们总是将 id与_source 一起返回到_id字段中,因此我们可以轻松地将实体重新组合在一起,但我们从未认为这是一个必要的功能。

笔记:

当您查看 ES 索引中的数据时,您会发现写入了一个名为_classMappingElasticsearchConverter的附加_source字段,其中包含实体类的名称(或定义的别名)。这允许映射泛型;有关更多信息,请查看文档- 以防万一您想知道它来自哪里。

2022 年 11 月 18 日编辑:

最近(版本 4.4.3)我们进行了一项更改,修复了 Spring Data Elasticsearch 中的错误行为:Spring Data Elasticsearch 不得将数据写入标记为 的属性中@ReadOnlyProperty。这导致建议的解决方案不再起作用,因为从 Elasticsearch 读取数据时,id 属性不再被填充。

要在这种情况下设置 id 属性,有必要向您的应用程序添加AfterConvertCallback

@Id
@ReadOnlyProperty
private String id;
Run Code Online (Sandbox Code Playgroud)