我有一个文档,其中包含在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);
}
}
但 保存 方法会覆盖整个文档:
{
"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);
}
}
但有两个类似的引用(存储库和ElasticsearchTemplate)似乎有点多余。
有人能建议我更好的解决方案吗?
答案 0 :(得分:6)
您可以实现自己的自定义存储库,而不是将 ElasticsearchTemplate 和 UserElasticsearchRepository 注入 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>, MessageRepositoryCustom {
....
}
最后,您的服务代码应如下所示。
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和地址。希望这有用。
答案 1 :(得分:1)
您也可以使用ElasticSearchTemplate来获取User对象而不是存储库接口。您可以使用NativeSearchQueryBuilder和其他类来构建查询。有了这个,你可以避免从你的班级两个类似的参考。如果这可以解决您的问题,请告诉我。