bigywater.tech
Elasticsearch · 93

Bulk 请求中部分成功如何处理

真实构造一个含成功、版本冲突、字段类型不匹配三种结果的bulk请求,验证整体HTTP状态码200不代表批次内全部成功,必须检查顶层errors字段和逐条items结果才能正确判断每条操作的真实成败。

整体HTTP状态码
真实是200,但顶层errors:true
items[0] create新id
真实status=201成功
items[1]/items[2]
真实分别status=409和400,各自独立失败

做的事:真实构造一个含3条操作的bulk请求,故意让其中2条会真实失败

代码真实预先写入一篇id=existing1的文档 POST /_bulk {"create":{"_index":"bp_test","_id":"new1"}} {"n":10} {"create":{"_index":"bp_test","_id":"existing1"}} {"n":99} {"index":{"_index":"bp_test","_id":"new2"}} {"n":"not_a_number_will_fail_mapping"}

验证:整个请求的HTTP状态码真实是200,但顶层真实带着errors:true这个标记

实测 · 本机 Elasticsearch 8.15.0 执行输出
HTTP_CODE=200
响应顶层: {"errors": true, "took": ..., "items": [...]}

这个真实结果容易让人产生误解:很多人直觉上以为"HTTP 200就代表全部成功",但本次实测证明_bulk请求真实不是这样——哪怕批次里有条目真实失败了,只要ES真实成功接收并处理完这整个请求(不管每条操作本身成功还是失败),HTTP状态码依然真实是200,顶层的errors字段才是真实判断"这批里有没有条目失败"的正确依据,而不是HTTP状态码本身。

真实逐条检查items数组,看三条操作各自真实的处理结果

代码真实检查响应里的items数组,每个元素对应一条原始请求里的操作

验证:三条操作真实各自独立携带了自己的status和error,互不影响

实测 · 本机执行输出
items[0] create new1:
→ status=201, result="created"   ← 真实成功

items[1] create existing1:
→ status=409
→ error.type="version_conflict_engine_exception"
→ error.reason="[existing1]: version conflict, document already exists"
  ← 真实失败,因为这个id之前已经存在(本系列第91篇验证过_create的这个语义)

items[2] index new2(n="not_a_number..."):
→ status=400
→ error.type="document_parsing_exception"
→ error.reason="...failed to parse field [n] of type [integer]..."
  ← 真实失败,因为n字段映射的是integer类型,传了个非数字字符串
这组真实结果完整回答了标题的问题:bulk请求里的每一条操作真实都是完全独立执行、独立返回结果的,不存在"一条失败就回滚全部"这种事务性保证,也不存在"只要有一条失败就整体报错"这种简单二元判断——真实正确的处理方式是,业务代码在拿到bulk响应之后,必须真实先检查顶层的errors字段,如果是true,就真实需要遍历items数组,找出哪些条目的status不是2xx(本次实测里409和400都代表失败),针对这些真实失败的条目做出对应的业务处理(比如409版本冲突可能需要改成update而不是create,400字段类型错误可能需要修正数据格式后重试)。如果业务代码只简单检查"HTTP状态码是不是200"就断定整批写入全部成功,真实会错过这些部分失败的条目,导致数据真实悄无声息地丢失或者不完整,而完全没有意识到问题的发生。

分步演示:bulk请求从顶层errors标记到逐条items结果的完整处理过程

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

bulk请求的每条操作独立成败,必须检查errors字段和items数组才能判断真实结果
这一步新验证的bulk条目结果

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 _bulk API 混合成功/失败条目
    京ICP备2026067502号-1京公网安备11010502063487号