ElasticSearch JavaRestClient之文档批处理

一、引言

在Elasticsearch中,当需要对大量文档进行增、删、改操作时,单个请求逐个处理会造成效率低下。为了提高处理效率,Elasticsearch 提供了批量操作接口,允许一次性提交多个请求。通过这种方式,可以减少网络往返次数,显著提升操作效率。

接下来,将使用 Elasticsearch Java 客户端实现批量操作(Bulk Request),该方法可以批量处理文档的新增、删除和修改。



二、批处理概述

批处理的核心思想是将多个单个文档操作(增、删、改)合并成一个请求,通过一次 HTTP 请求提交多个操作。Elasticsearch 提供了一个名为 Bulk Request 的 API 来处理这种批量操作。

批处理的基本流程:

  1. 创建 BulkRequest 对象BulkRequest 用于封装多次单独的操作,类似于 SQL 中的批量插入。
  2. 添加单个请求到 BulkRequest: 使用 BulkRequest.add() 方法将每个单独的操作请求(如 IndexRequestDeleteRequest 等)添加到 BulkRequest 中。每个操作都可以指定索引库名、文档ID、文档内容等信息。
  3. 执行 BulkRequest: 使用 Elasticsearch 客户端的 bulk() 方法提交请求。执行完毕后,返回批量操作的结果。



四、批量操作示例代码

1. 批量新增文档
@Test
void testBulkDoc() throws IOException {
    int pageNo = 1, pageSize = 500;
    while (true) {
        // 1.准备文档数据
        Page<Item> page = iItemService.lambdaQuery()
                .eq(Item::getStatus, 1)
                .page(Page.of(pageNo, pageSize));
        List<Item> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return;
        }
        
        // 2.准备Request
        BulkRequest request = new BulkRequest();
        // 3.准备请求参数
        for (Item item : records) {
            request.add(new IndexRequest("items")
                    .id(item.getId().toString())
                    .source(JSONUtil.toJsonStr(BeanUtil.copyProperties(item, ItemDoc.class)), XContentType.JSON));
        }
        // 4.发送请求
        client.bulk(request, RequestOptions.DEFAULT);
        // 5.翻页
        pageNo++;
    }
}
  • IndexRequest:用于执行文档新增操作,必须指定索引库名、文档ID和文档内容(以 JSON 格式传入)。
  • XContentType.JSON:指定请求内容的类型为 JSON。

通过运行 GET /items/_countSELECT COUNT(*) FROM item WHERE STATUS = 1,得出结果一致,说明添加成功:


2. 批量删除文档
@Test
void testBulkDelete() throws IOException {
    int pageNo = 1, pageSize = 500;  // 每页500条记录
    while (true) {
        // 1.准备文档数据
        Page<Item> page = iItemService.lambdaQuery()
                .eq(Item::getStatus, 1)  // 删除条件是状态为 1 的商品
                .page(Page.of(pageNo, pageSize));  // 分页查询
        List<Item> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return;  // 数据为空,结束
        }

        // 2.准备BulkRequest
        BulkRequest request = new BulkRequest();
        // 3.准备删除请求参数
        for (Item item : records) {
            request.add(new DeleteRequest("items")
                    .id(item.getId().toString()));  // 指定要删除的文档 ID
        }
        // 4.发送请求
        client.bulk(request, RequestOptions.DEFAULT);
        // 5.翻页
        pageNo++;  // 页码加1,查询下一页
    }
}

  • DeleteRequest:用于执行文档删除操作,必须指定索引库名和文档ID。
  • 通过运行 GET /items/_count验证得到 count = 0,说明批量删除成功。



3. 批量更新文档
@Test
void testBulkUpdate() throws IOException {
    int pageNo = 1, pageSize = 500;  // 每页500条记录
    while (true) {
        // 1.准备文档数据
        Page<Item> page = iItemService.lambdaQuery()
                .eq(Item::getStatus, 1)  // 更新条件是状态为 1 的商品
                .page(Page.of(pageNo, pageSize));  // 分页查询
        List<Item> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return;  // 数据为空,结束
        }

        // 2.准备BulkRequest
        BulkRequest request = new BulkRequest();
        // 3.准备更新请求参数
        for (Item item : records) {
            // 构建更新内容(假设更新价格字段)
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put("price", item.getPrice());  // 假设要更新价格字段

            request.add(new UpdateRequest("items", item.getId().toString())
                    .doc(updateMap)  // 更新内容
                    .docAsUpsert(true));  // 如果文档不存在,则插入
        }
        // 4.发送请求
        client.bulk(request, RequestOptions.DEFAULT);
        // 5.翻页
        pageNo++;  // 页码加1,查询下一页
    }
}

  • UpdateRequest:用于执行文档更新操作,必须指定索引库名、文档ID,并传入更新内容。
  • 由于刚刚批量删除了文档,此时进行更新文档操作实则为新增操作,因此运行 GET /items/_count得到与批量新增文档的结果以一样。



五、批量操作的注意事项

  1. 一次提交的请求数量:批量请求的大小应控制在合理范围内,避免请求过大导致内存溢出或超时。通常,单个批次的请求数量可以在几百到几千之间,具体取决于文档大小和系统负载。
  2. 分页查询数据:由于我们可能需要批量操作大量文档,因此在从数据库获取数据时,必须采用分页查询。一次查询少量数据,避免查询所有数据导致内存溢出。
  3. 分批发送请求:如果需要处理的数据量非常大,可以通过分页分批查询并发送多个批次请求,直到所有数据处理完毕。
  4. 处理失败的请求:在执行批量操作时,可能会发生某些请求失败的情况。需要检查 BulkResponsehasFailures() 方法,并根据返回的失败信息进行相应的处理。



六、批量操作与单文档操作的区别

  • 单文档操作:每次执行一个增、删、改操作,适合处理小量数据。
  • 批量操作:一次执行多个操作,适合处理大量数据。可以显著提高操作效率,但需要注意请求大小及内存管理。



七、代码优化与实践

  1. 批量操作的性能优化
    • 将批量操作的请求分成小批次(例如每批处理 500 条数据),避免内存消耗过大。
    • 定期提交批量操作,避免长时间保持大规模数据在内存中。
  2. 错误处理
    • BulkResponse 可以返回批量请求的执行结果。如果某个请求失败,BulkResponse 提供了详细的错误信息,开发者需要根据具体情况决定是重试还是跳过失败请求。
  3. 数据库查询优化
    • 使用分页查询来分批获取需要导入的数据,避免一次性加载所有数据。
    • 根据具体条件(例如商品状态)进行查询,避免导入无效数据。



八、总结

通过 BulkRequest 实现批量操作,能够显著提高 Elasticsearch 中大规模文档处理的效率。批量请求可以包括多个增、删、改操作,简化了操作流程,减少了网络请求次数,提高了系统的性能。在实际应用中,合理设计批量操作的大小、优化数据查询和处理流程,可以有效提升数据处理效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值