使用 Spring 数据 Elasticsearch 存储库进行部分更新

Partial update with Spring Data Elasticsearch repository

我有一个文档,其中包含很多字段(有些是嵌套的)在 elasticsearch 上建立了索引。例如:

{
  "id" : 1,
  "username" : "...",
  "name" : "...",
  "surname" : "...",
  "address" : "...",
  "age": 42,
  ...
  "bookmarks" : [{...}, {...}],
  "tags" : [{...}, {...}]
}

我的实体中只映射了一些文件(我不想映射整个文档):

@Document(indexName = "...", type = "...")
public class User {
  @Id
  private int id;
  private String username;
  private String address;

  // getter/setter methods

}

在服务 class 中,我想使用 ElasticsearchRepository 进行部分更新,而不映射实体中的所有文档字段:

public class UserServiceClass {

  @Autowired
  private UserElasticsearchRepository userElasticsearchRepository;

  public void updateAddress(int id, String updatedAddress) {
    User user = userElasticsearchRepository.findOne(id);
    user.setAddress(updatedAddress);
    userElasticsearchRepository.save(user);
  } 
}

但是save方法覆盖了整个文档:

{
  "id" : 1,
  "username" : "...",
  "address" : "..."
}

ElasticsearchRepository 似乎不支持部分更新。所以我使用了ElasticsearchTemplate,进行了部分更新,例如:

public class UserServiceClass {

  @Autowired
  private UserElasticsearchRepository userElasticsearchRepository;

  @Autowired
  private ElasticsearchTemplate elasticsearchTemplate;

  public void updateAddress(int id, String updatedAddress) {
    User user = userElasticsearchRepository.findOne(id);
    if (user.getUsername().equals("system")) {
      return;
    }

    IndexRequest indexRequest = new IndexRequest();
    indexRequest.source("address", updatedAddress);
    UpdateQuery updateQuery = new UpdateQueryBuilder().withId(user.getId()).withClass(User.class).withIndexRequest(indexRequest).build();
    elasticsearchTemplate.update(updateQuery);
  } 
}

但有两个相似的引用(存储库和 ElasticsearchTemplate)似乎有点多余。

谁能建议我更好的解决方案?

您也可以使用 ElasticSearchTemplate 来获取您的用户对象而不是存储库接口。您可以使用 NativeSearchQueryBuilder 和其他 classes 来构建您的查询。有了这个,您可以避免来自 class 的两个相似引用。如果这能解决您的问题,请告诉我。

无需将 ElasticsearchTemplateUserElasticsearchRepository 都注入您的 UserServiceClass,您可以实施您自己的 自定义存储库 并让您现有的 UserElasticsearchRepository 扩展它。

我假设您现有的 UserElasticsearchRepository 看起来像这样。

public interface UserElasticsearchRepository extends ElasticsearchRepository<User, String> {
   ....
}

您必须创建新的接口名称 UserElasticsearchRepositoryCustom。在此界面中,您可以列出您的自定义查询方法。

public interface UserElasticsearchRepositoryCustom {

    public void updateAddress(User user, String updatedAddress);

}

然后通过创建一个名为 UserElasticsearchRepositoryImpl 的 class 来实现您的 UserElasticsearchRepositoryCustom 并在内部实现您的自定义方法并注入 ElasticsearchTemplate

public class UserElasticsearchRepositoryImpl implements UserElasticsearchRepositoryCustom {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public void updateAddress(User user, String updatedAddress){
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.source("address", updatedAddress);
        UpdateQuery updateQuery = new UpdateQueryBuilder().withId(user.getId()).withClass(User.class).withIndexRequest(indexRequest).build();
        elasticsearchTemplate.update(updateQuery);
    }
}

之后,只需使用 UserElasticsearchRepositoryCustom 扩展您的 UserElasticsearchRepository,它应该看起来像这样。

public interface UserElasticsearchRepository extends ElasticsearchRepository<User, String>, UserElasticsearchRepositoryCustom {
   ....
}

最后,您的服务代码应该如下所示。

public class UserServiceClass {

  @Autowired
  private UserElasticsearchRepository userElasticsearchRepository;

  public void updateAddress(int id, String updatedAddress) {
    User user = userElasticsearchRepository.findOne(id);
    if (user.getUsername().equals("system")) {
      return;
    }
    userElasticsearchRepository.updateAddress(user,updatedAddress);
  } 
}

您也可以将用户查找逻辑移至自定义存储库逻辑中,这样您就可以在方法中仅传递用户 ID 和地址。希望这对您有所帮助。