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 /_allDELETE /*。我曾经见过有人手滑,把整个集群的索引全删了…… 那场面,真是欲哭无泪。建议在 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 的搜索能力才是它的真正魅力所在。