使用批量更新 elasticsearch 实体

Updating elasticsearch entities with bulk

我有以下数据库数据 (ES 7.xx) 版本

    {
   "id":"1234",
   "expirationDate":"17343234234",
   "paths":"http:localhost:9090",
   "work":"software dev",
   "family":{
      "baba":"jams",
      "mother":"ela"
   }
},
{
   "id":"00021",
   "expirationDate":"0123234",
   "paths":"http:localhost:8080",
   "work":"software engi",
   "family":{
      "baba":"stev",
      "mother":"hela"
   }
}

如何更新到期日期小于当前时间的实体?例如当前时间:

ID 00021 已过期,因为它的过期日期比今天小,因此应更新为当前时间。

类似 void updateExpiredEntity(List<ids> ids,Long currentTime) 起诉 void bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index);

请提供一些代码实现

这样正确吗?

    public void update(UUID id,Long currentDate) {
        UpdateQuery updateQuery = UpdateQuery.builder(id.toString()).withRouting("expirationDate=currentDate")
            .build();
        elasticsearchTemplate.bulkUpdate(List.of(updateQuery), IndexCoordinates.of("index"));
    }
}

如果您使用的是 Elasticsearch 7.xx,我假设您使用的是 Spring Data Elasticsearch 版本 4。0.x 随 Spring boot 2.3.x。因为是支持Elasticsearch的版本7.xx.

此 Spring Data Elasticsearch 版本中有很多更改。通过查询更新文档就是其中之一。与之前我们自动装配 ElasticsearchTemplate 不同,我们现在必须改用 ElasticsearchRestTemplate 和 RestHighLevelClient。

在您的情况下,您可能希望使用 RestHighLevelClient 通过查询更新文档。假设您将 expirationDate 存储为以秒为单位的数字映射类型,那么您要求的代码应该如下所示。

public class ElasticsearchService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private RestHighLevelClient highLevelClient;

    public void updateExpireDateDemo() throws IOException {
        String indexName = "test";
        Date currentDate = new Date();
        Long seconds = (Long) (currentDate.getTime() / 1000);
        UpdateByQueryRequest request = new UpdateByQueryRequest(indexName);
        request.setQuery(new RangeQueryBuilder("expirationDate").lte(seconds));
        Script updateScript = new Script(
                ScriptType.INLINE, "painless",
                "ctx._source.expirationDate=" + seconds + ";",
                Collections.emptyMap());
        request.setScript(updateScript);
        highLevelClient.updateByQuery(request, RequestOptions.DEFAULT);
    }
}

我不太明白为什么您真的需要使用 bulkUpdate,但如果是这样的话。您必须首先从 Elasticsearch 查询需要更新的记录以获取每个文档的 ID。然后您可以使用 UpdateQuery 列表进行更新。所以您的代码将如下所示。

@Service
public class ElasticsearchService {
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public void updateExpireDateByBulkDemo() throws IOException {
        String indexName = "test";
        Date currentDate = new Date();
        Long seconds = (Long) (currentDate.getTime() / 1000);
        List<UpdateQuery> updateList = new ArrayList();
        RangeQueryBuilder expireQuery = new RangeQueryBuilder("expirationDate").lte(seconds);
        NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(expireQuery).build();
        SearchHits<Data> searchResult = elasticsearchRestTemplate.search(query, Data.class, IndexCoordinates.of(indexName));
        for (SearchHit<Data> hit : searchResult.getSearchHits()) {
            String elasticsearchDocumentId = hit.getId();
            updateList.add(UpdateQuery.builder(elasticsearchDocumentId).withScript("ctx._source.expirationDate=" + seconds + ";").build());
        }
        if (updateList.size() > 0) {
            elasticsearchRestTemplate.bulkUpdate(updateList, IndexCoordinates.of(indexName));
        }
    }
}

但是,这只会更新搜索结果的第一页。如果您需要更新与您的查询匹配的每条记录,那么您必须使用 searchScroll 方法来获取每个文档 ID。