单文档读写是什么
文档级的增删改查通过 _doc 接口完成:PUT 指定 ID 时是整篇替换,POST 不指定 ID 时自动生成;_create 在 ID 已存在时返回 409,适合只允许插入一次的语义。GET 按 ID 取文档,读取会带 _source。删除是标记删除,段合并之后空间才真正回收。部分更新要用 _update,不能靠 PUT 覆盖。
基本信息
| 写入 | PUT /<index>/_doc/<id> 指定 ID;POST /<index>/_doc 自动生成 ID |
|---|---|
| 读取 | GET /<index>/_doc/<id>,只要原始内容可加 _source 路径 |
| 删除 | DELETE /<index>/_doc/<id>,段合并后才回收空间 |
| 部分更新 | POST /<index>/_update/<id> 配合 doc 或 script |
| 只插入一次 | PUT /<index>/_create/<id>,已存在返回 409 |
| 适用版本 | Elasticsearch 7.x / 8.x |
典型使用场景
- 按业务主键写入或覆盖单条文档
- 排障时按 ID 精确取回文档内容
- 部分字段更新:只改状态或浏览量
- 幂等写入:用固定 ID 保证重复写入不产生多份数据
- 删除错误写入的文档
- 验证写入结果:写后 GET 确认内容与类型
示例
示例
PUT /my-index/_doc/1
{ "title": "doc one" } # 指定 ID 写入(整篇替换)
POST /my-index/_doc
{ "title": "auto id doc" } # 自动生成 ID
GET /my-index/_doc/1
GET /my-index/_source/1 # 只取原始内容
POST /my-index/_update/1
{ "doc": { "views": 10 } } # 部分更新
DELETE /my-index/_doc/1 # 删除文档接口行为对照
| 接口 | 行为 | 使用注意 |
|---|---|---|
| PUT _doc/<id> | 整篇替换(覆盖) | 漏字段会丢掉原值 |
| POST _doc | 自动生成 ID | 不便于后续更新 |
| PUT _create/<id> | 仅新建 | 已存在返回 409 |
| POST _update/<id> | 部分更新 | 需先取回再重建索引 |
| GET _doc/<id> | 取文档 | 实时读取不受 refresh 影响 |
| DELETE _doc/<id> | 标记删除 | 空间延迟回收 |
读写实践要点
- 覆盖写入前先 GET 原文档,避免漏字段导致数据丢失
- 重复写入同一 ID 用 create 动作能识别冲突,便于幂等控制
- 写入后立刻搜索看不到属于正常现象,需要 refresh 或等待刷新间隔
- 批量场景不要逐条 PUT,改用 _bulk 降低往返开销
- 并发更新同一文档用 _update 配合 retry_on_conflict
- 删除大量文档优先按条件批量删除,而不是逐条 DELETE
PUT 同 ID 是覆盖写入(整篇替换),只想改部分字段请用 POST _update,否则未写到的字段会消失。
GET 按 ID 读取是实时的,不受 refresh 影响;但 _search 在 refresh 之前看不到刚写入的文档,两种接口的可见性语义不同。
删除只是标记,被删文档在段合并前仍占空间并计入 docs.deleted;大批删除后评估 force merge 的时机,避免高峰执行。
批量与并发场景优先用 _bulk 与 _update,单条 PUT 的写入吞吐低,且部分更新在并发下容易出现覆盖丢更新。
写入方式选择
- 按业务主键覆盖写入用 PUT _doc,注意它是整篇替换
- 只允许插入一次用 _create,重复 ID 返回 409
- 部分字段更新用 _update 的 doc 形式
- 数组追加或脚本计算用 _update 的 script 形式
- 大量文档用 _bulk 提交,避免逐条往返
- 并发更新用 _update 配合 retry_on_conflict
读取与排错
- 按 ID 取回文档用 GET _doc,必要时只取 _source 部分路径
- 确认写入是否生效:写后 GET 一次并核对字段类型
- 搜索看不到刚写入的数据属于刷新延迟,不是数据丢失
- 返回 found 为 false 说明文档不存在或已被删除
- 批量取文档用 _mget 减少请求次数
- 核对字段值类型优先看 _source,避免被索引形态误导
同一 ID 的写入会递增版本号,乐观并发控制依赖它;需要按版本更新时用 if_seq_no 配合 if_primary_term,冲突会返回 409。
读取时可用 _source_includes 与 _source_excludes 只取需要的字段,大文档场景能明显减少传输量;但字段过滤发生在取回之后,不会减少磁盘读取。
写入后立即可见
- 需要立刻能搜到就显式 refresh,或用 refresh=wait_for 等待刷新
- 批量提交用 _bulk,而不是循环单条 PUT
- 删除大量文档后评估段合并时机,避开业务高峰
- 按 ID 取多条文档用 _mget,减少请求往返次数