1.4 Elasticsearch-CRUD 全实战:PUT/POST/GET/DELETE/_bulk

在这里插入图片描述
1.4 Elasticsearch-CRUD 全实战:PUT/POST/GET/DELETE/_bulk
——从“写一条”到“写一亿条”的 production-ready 路径


  1. 一条文档的“身份证”:_id 与 _source

在 Elasticsearch(后文简称 ES)里,文档(document)等价于关系型数据库里的一行记录,却自带一张“身份证”:
_index/_type/_id(7.0 之后 _type 统一为 _doc)。
CRUD 的所有动作,本质上就是围绕这张身份证做原子操作。牢记下面两条铁律,可以避开 80% 的线上事故:

  1. 写操作默认 1 秒 refresh 后才可见;实时搜索需 ?refresh=true,但会击穿 segment 缓存。
  2. 任何写操作都会先写 translog,再写内存 buffer,因此 bulk 再大也不会丢数据,但 translog 过大时会触发 flush,引起 IO 尖刺。

  1. PUT vs POST:幂等、指定 ID、自动生成 ID

场景 1:指定 ID 全量替换
PUT /shop/_doc/1001
{“title”:“ES 实战指南”,“price”:69.9}
特点:幂等、版本号 _version 自增、全字段覆盖(缺失字段会被删)。

场景 2:不指定 ID,让 ES 自动生成
POST /shop/_doc
{“title”:“ES 实战指南”,“price”:69.9}
返回 _id: u7wQk4sB7y5vfQqF8p4H,24 位 UUID;非幂等,同一行代码执行两次得到两条记录。

场景 3:PUT 带 _create,拒绝覆盖
PUT /shop/_doc/1001/_create
{“title”:“ES 实战指南”}
若 1001 已存在,返回 409 Conflict,防止“误刷”线上数据。


  1. GET:实时读取与“伪实时”

GET /shop/_doc/1001
返回结果包在 _source 里;实时可读,不走 searcher,直接查 translog + versionMap,因此 RT 保证 <1 ms。
只想看部分字段:
GET /shop/_doc/1001?_source_includes=title,price
或者只要存储字段(stored field):
GET /shop/_doc/1001?stored_fields=title


  1. DELETE:逻辑删除与“墓碑”

DELETE /shop/_doc/1001
ES 只在 segment 里写一条 .del 记录,真正的物理删除要等段合并(merge)。
批量删除用 _delete_by_query,会启动一个 scroll + bulk delete 任务,返回 taskId 可异步轮询。
线上大索引删除技巧:

  1. 先设置 index.refresh_interval=-1 关闭自动 refresh,
  2. 再跑 delete-by-query,
  3. 最后打开 refresh 并手动 _forcemerge?max_num_segments=1 回收空间。

  1. UPDATE:脚本更新、upsert、并发控制

POST /shop/_update/1001
{
“script”: {
“source”: “ctx._source.price += params.delta”,
“params”: {“delta”: 10}
},
“upsert”: {“price”: 79.9}
}
脚本在 ES 端执行,避免“先 GET 再 PUT”的 race condition;
upsert 表示文档不存在时插入初始值。
并发版本控制:

  • 内部版本号:if_seq_no=12&if_primary_term=1,利用 sequence number 实现乐观锁;
  • 外部版本号:?version=20&version_type=external,适合 CDC(MySQL binlog)场景,版本号由外部产生。

  1. _bulk:一次 RTT 干 10000 件事

bulk 是 ES 写入的“大杀器”,协议极简:
POST /_bulk
{ “index” : { “_index” : “shop”, “_id” : “2001” } }
{“title”:“Python 进阶”}
{ “update” : { “_index” : “shop”, “_id” : “1001” } }
{“doc”:{“price”:89.9}}
{ “delete” : { “_index” : “shop”, “_id” : “5001” } }
注意:

  1. 两行一条指令,不能换行少一行,否则整包 400;
  2. 末尾必须 \n 结尾;
  3. 单条失败不影响整包,返回体里逐条标记 {"error":...}
  4. 官方建议 5–15 MB/包,或 3000–5000 条/包;
  5. 开 gzip,设置 Content-Encoding: gzip,网络传输可省 70% 流量;
  6. 客户端层做“拒绝重试”:429 只重试写,502/503 幂等操作才重试,避免 update 脚本重复执行。

  1. 生产级 bulk 模板(Java HighLevel Client 示例)

BulkRequest bulk = new BulkRequest();
bulk.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL); // 等本次 bulk 可见
bulk.timeout(TimeValue.timeValueSeconds(30));
bulk.pipeline(“timestamp-pipeline”); // 预置 ingest pipeline 自动加 @timestamp
for (Sku sku : list) {
IndexRequest req = new IndexRequest(“shop”)
.id(sku.getId())
.source(JSON.toJSONString(sku), XContentType.JSON);
bulk.add(req);
}
BulkResponse resp = client.bulk(bulk, RequestOptions.DEFAULT);
if (resp.hasFailures()) {
for (BulkItemResponse item : resp.getItems()) {
if (item.isFailed()) {
log.error(“fail id:{} msg:{}”, item.getId(), item.getFailureMessage());
}
}
}


  1. 性能调优 checklist

  1. 关闭不必要的 _source 存储,省 30% 磁盘;
  2. 把 “string 仅排序/聚合” 字段设 "index":false,"doc_values":true,避免倒排;
  3. 写前把 number_of_replicas 设 0,写完再改回,副本拷贝走 recovery 而非 bulk;
  4. 机械盘务必 index.translog.durability: async + index.translog.sync_interval: 30s,SSD 可默认;
  5. 用 Elasticsearch 官方 Rally 压测,track 选 nyc_taxis,target-throughput 设 100k docs/s,观察 CPU iowait 与 JVM old 区;
  6. 超过 3 亿条/天的业务,直接上 data stream + ILM,按大小 50 GB 滚索引,避免单 shard 过 TB 后 merge 炸盘。

  1. 常见报错速查表

| 现象 | 根因 | 解法 |
| 409 VersionConflict | 并发 update | 用 seq_no+primary_term 重试 |
| 429 EsRejectedEx | 写队列满 | client 退避 + 限流,或扩容 data 节点 |
| 400 illegal_argument | bulk 包格式错 | 检查换行、json 缺括号 |
| 403 cluster_block_exception | 磁盘 95% 只读 | 删冷索引、加磁盘、调 watermark |
| 504 gateway timeout | 负载均衡超时 | 把 client 超时调到 120 s,或直连 data 节点 |


  1. 小结

PUT 是“身份证写”,POST 是“匿名生”,GET 是“毫秒读”,DELETE 是“逻辑埋”,_bulk 是“万箭齐发”。
把 version/seq_no 当乐观锁、把 refresh_interval 当性能开关、把 translog 当数据生命线,
你就拥有了在千亿级文档里“指哪打哪”的 CRUD 能力。
更多技术文章见公众号: 大城市小农民

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值