【问题标题】:Partial update with Spring Data Elasticsearch repository使用 Spring Data Elasticsearch 存储库进行部分更新
【发布时间】:2016-11-22 12:49:44
【问题描述】:

我有一个文档,其中包含在 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

}

在服务类中,我想使用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 似乎不支持部分 udpdate。于是我用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);
  } 
}

但是有两个相似的引用(repository 和 ElasticsearchTemplate)似乎有点多余。

谁能给我一个更好的解决方案?

【问题讨论】:

    标签: java spring-data-elasticsearch


    【解决方案1】:

    您可以实现自己的自定义存储库,而不是将 ElasticsearchTemplateUserElasticsearchRepository 注入您的 UserServiceClass并让您现有的 UserElasticsearchRepository 扩展它。

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

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

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

    public interface UserElasticsearchRepositoryCustom {
    
        public void updateAddress(User user, String updatedAddress);
    
    }
    

    然后通过创建一个名为 UserElasticsearchRepositoryImpl 的类来实现您的 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 和地址。希望这会有所帮助。

    【讨论】:

    【解决方案2】:

    您也可以使用 ElasticSearchTemplate 来获取您的用户对象而不是存储库接口。您可以使用 NativeSearchQueryBuilder 和其他类来构建您的查询。有了这个,您可以避免课堂上的两个类似参考。让我知道这是否可以解决您的问题。

    【讨论】:

    • 感谢 Shahnaz,在我的最终解决方案中,我只使用 ElasticSearchTemplate 来读取和更新用户对象。但我希望也可以使用 Spring Data Elasticsearch 存储库进行部分更新。
    • AFAIK 目前没有可用于存储库的部分更新,如果您发现了什么,请告诉我。谢谢
    猜你喜欢
    • 2021-04-21
    • 2013-07-20
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多