4. Elasticsearch 基础操作:RESTful API 介绍、索引的创建与删除、文档的增删改查
好,咱们进入实战环节了。说实话,很多新手学 Elasticsearch 容易卡在概念上,什么分片、副本、倒排索引…… 我建议你先别管那么多。先学会怎么跟 ES 对话,把数据塞进去、查出来,这才是第一步。
ES 的对话方式,就是 RESTful API。说白了,就是通过 HTTP 请求来操作它。你发一个 GET,它就给你查数据;发一个 POST,它就给你写数据。跟浏览网页差不多,只不过返回的是 JSON 格式的结构化数据。
4.1 RESTful API 基础
RESTful API 不是什么高深的东西。你可以把它想象成一个「遥控器」。每个请求由三部分组成:
- 请求方法:GET(查)、POST(增)、PUT(改/增)、DELETE(删)
- 请求路径:比如
/index_name/_doc/1 - 请求体:JSON 格式的数据,放在请求的 body 里
我个人习惯用 curl 来测试,当然你也可以用 Kibana 的 Dev Tools,或者 Postman。怎么顺手怎么来。
核心概念对应关系
| 关系型数据库 | Elasticsearch |
|---|---|
| 数据库(Database) | 索引(Index) |
| 表(Table) | 类型(Type)—— 7.x 后废弃,8.x 已移除 |
| 行(Row) | 文档(Document) |
| 列(Column) | 字段(Field) |
| 主键(Primary Key) | 文档 ID(_id) |
嗯,这里要注意:ES 7.x 之后,一个索引下只有一个默认的 _doc 类型。你不需要再纠结类型名了,直接操作索引和文档就行。
4.2 索引的创建与删除
索引,你可以理解成数据库里的「表」。但 ES 的索引更灵活,它自带 schema,也可以动态映射。
4.2.1 创建索引
最简单的创建方式,什么都不指定,直接 PUT 一个索引名:
PUT /my_first_index
返回结果:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "my_first_index"
}
看到 acknowledged: true,就说明创建成功了。但这样创建的索引,用的是默认配置——5个主分片、1个副本。我在项目中遇到过,有人直接拿默认配置上生产,结果数据量一上来,查询慢得不行。所以,我建议创建索引时,最好指定分片数和副本数:
PUT /my_custom_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
为什么是 3 个分片?这取决于你的数据量和节点数。一般经验是:分片数 = 节点数 × 1.5 左右。当然,这不是死规矩,得根据实际情况调。
4.2.2 查看索引
创建完了,怎么确认它存在?用 GET:
GET /my_custom_index
会返回索引的详细信息,包括 settings、mappings 等。想看所有索引?
GET /_cat/indices?v
这个 _cat 接口很实用,返回的是表格形式,一目了然。我平时排查问题,第一件事就是跑这个命令,看看索引状态是不是 green。
4.2.3 删除索引
删除索引要小心。ES 没有「回收站」的概念,删了就真没了。
DELETE /my_first_index
警告:千万不要在生产环境执行 DELETE /_all 或 DELETE /*。我曾经见过有人手滑,把整个集群的索引全删了…… 那场面,真是欲哭无泪。建议在 elasticsearch.yml 中设置 action.destructive_requires_name: true,禁止通配符删除。
4.3 文档的增删改查
索引建好了,接下来就是往里塞数据。ES 里的数据叫「文档」,格式是 JSON。每个文档都有一个唯一的 _id,你可以自己指定,也可以让 ES 自动生成。
4.3.1 新增文档(Create)
两种方式:指定 ID 和不指定 ID。
指定 ID:
PUT /my_custom_index/_doc/1
{
"title": "Elasticsearch 入门",
"content": "这是一篇关于 ES 的文章",
"author": "张三",
"publish_date": "2024-01-15",
"views": 1200
}
自动生成 ID:
POST /my_custom_index/_doc
{
"title": "搜索引擎原理",
"content": "倒排索引是核心",
"author": "李四",
"publish_date": "2024-02-20",
"views": 850
}
注意区别:PUT 必须指定 ID,POST 可以不指定。返回结果里会有一个 _id 字段,就是 ES 自动生成的。
小技巧:如果你用 PUT 指定了一个已存在的 ID,ES 会直接覆盖原文档。这不是新增,而是「全量替换」。想避免覆盖?用 _create 端点:PUT /my_custom_index/_create/1,如果 ID 已存在,会返回 409 冲突错误。
4.3.2 查询文档(Retrieve)
查文档很简单,知道 ID 就行:
GET /my_custom_index/_doc/1
返回结果:
{
"_index": "my_custom_index",
"_id": "1",
"_version": 1,
"_source": {
"title": "Elasticsearch 入门",
"content": "这是一篇关于 ES 的文章",
"author": "张三",
"publish_date": "2024-01-15",
"views": 1200
}
}
注意 _source 字段,里面存的就是你当初写入的原始 JSON。ES 默认会把原始文档存下来,方便你取用。如果你只想看 _source 里的内容,可以:
GET /my_custom_index/_source/1
这样返回的就是纯 JSON,没有那些元数据了。
4.3.3 更新文档(Update)
更新有两种方式:全量替换和局部更新。
全量替换:其实就是重新 PUT 一遍,把整个文档覆盖掉。
PUT /my_custom_index/_doc/1
{
"title": "Elasticsearch 进阶",
"content": "这是一篇关于 ES 进阶的文章",
"author": "张三",
"publish_date": "2024-01-15",
"views": 1500
}
这样做的问题是,如果你漏掉了某个字段,那个字段就没了。比如上面我没写 author,那更新后 author 就变成 null 了。
局部更新:用 _update 端点,只修改指定字段。
POST /my_custom_index/_update/1
{
"doc": {
"views": 1600
}
}
这样只更新 views 字段,其他字段保持不变。我在项目中经常用这种方式,比如更新文章的阅读量、点赞数,只改一个字段,效率高,也不容易出错。
4.3.4 删除文档(Delete)
删除文档用 DELETE:
DELETE /my_custom_index/_doc/1
删除后,再查询会返回 found: false。但注意,ES 的删除是「逻辑删除」,不会立即释放磁盘空间。ES 会在后台的段合并过程中,真正把数据清理掉。所以,如果你删了大量数据,磁盘空间不会立刻降下来,别慌,等一会就好了。
4.4 批量操作
单个操作太慢?ES 提供了批量接口 _bulk,可以一次发多个请求。
POST /_bulk
{ "index": { "_index": "my_custom_index", "_id": "2" } }
{ "title": "批量操作", "content": "一次搞定多个文档", "author": "王五", "views": 300 }
{ "index": { "_index": "my_custom_index", "_id": "3" } }
{ "title": "ES 性能优化", "content": "调优技巧", "author": "赵六", "views": 500 }
{ "delete": { "_index": "my_custom_index", "_id": "1" } }
注意格式:每个操作占两行,第一行是操作类型(index、create、update、delete),第二行是数据(delete 不需要数据)。最后一定要有一个空行结尾。
批量操作的优势:减少网络往返次数。如果你要写入 10000 条数据,一条一条发,要发 10000 次 HTTP 请求。用 bulk,可能 10 次就搞定了。我做过测试,bulk 的吞吐量是单条写入的 5-10 倍。
4.5 避坑指南
最后,分享几个我踩过的坑:
- 索引名不能大写:ES 的索引名必须是小写字母。我曾经用驼峰命名,结果创建失败,报错信息还不明显,排查了半天。
- 文档 ID 不要用自增数字:ES 的 ID 是字符串,用自增数字会导致分片分布不均匀。我建议用 UUID 或业务唯一标识。
- 批量操作不要太大:每个 bulk 请求建议控制在 5-15 MB 之间,或者 1000-5000 条文档。太大容易导致内存溢出,太小又浪费网络。
- 更新操作是「先删后增」:ES 的文档是不可变的。你看到的「更新」,实际上是先标记旧文档为删除,再写入新文档。所以频繁更新会产生大量垃圾数据,需要定期做段合并。
好了,这一章的内容就到这里。你想想看,其实 ES 的基础操作并不复杂,就是 HTTP 请求加 JSON 数据。但正是这些简单的操作,构成了搜索引擎的基石。下一章,我们会深入查询语法,到时候你会发现,ES 的搜索能力才是它的真正魅力所在。