ES(Elasticsearch)里的"分片(Shard)" ,本质上是把一个索引的数据拆成多份存储的单位 。
每个分片其实就是一个 独立的 Lucene 索引,可以被放到不同的节点上,从而实现:
- 数据水平扩展(数据太大时拆开存)
- 并行查询(多个分片一起查,速度更快)
- 高可用(副本分片可以容灾)
简单理解:
- Index(索引) :逻辑概念,比如
order_index - Shard(分片):物理存储单元
- Document(文档):具体数据
关系大概是:
Index → 被拆成多个 Shard → 每个 Shard 存一部分 Document
一、写入数据时 ES 怎么决定放哪个分片
ES 默认用一个 hash 路由算法:
shard = hash(_id) % number_of_primary_shards
如果有 3 个主分片:
hash(id) % 3
结果可能是:
- 0 → shard0
- 1 → shard1
- 2 → shard2
二、一个真实的 3 分片案例
假设我们有一个电商订单索引:
index: order_index primary_shards: 3 replicas: 1
订单数据:
{ "order_id": "1001", "user": "Tom", "amount": 120 } { "order_id": "1002", "user": "Lucy", "amount": 80 } { "order_id": "1003", "user": "Jack", "amount": 200 } { "order_id": "1004", "user": "Amy", "amount": 50 } { "order_id": "1005", "user": "David", "amount": 300 } { "order_id": "1006", "user": "Bob", "amount": 90 }
经过 hash 路由后,可能分布如下:
| shard | 数据 |
|---|---|
| shard0 | 1001, 1004 |
| shard1 | 1002, 1005 |
| shard2 | 1003, 1006 |
每个 shard 实际上是一个独立索引。
例如:
Shard0
doc1: { "order_id": "1001", "user": "Tom", "amount": 120 } doc2: { "order_id": "1004", "user": "Amy", "amount": 50 }
Shard1
doc1: { "order_id": "1002", "user": "Lucy", "amount": 80 } doc2: { "order_id": "1005", "user": "David", "amount": 300 }
Shard2
doc1: { "order_id": "1003", "user": "Jack", "amount": 200 } doc2: { "order_id": "1006", "user": "Bob", "amount": 90 }
三、查询时发生什么
当你执行:
GET order_index/_search
ES 会做三步:
- 把查询广播给所有分片
- 每个 shard 独立查询
- 汇总结果返回
流程:
client ↓ coordinator node ↓ shard0 shard1 shard2 ↓ ↓ ↓ 结果1 结果2 结果3 ↓ merge + sort ↓ 返回最终结果
四、再看一个真实集群结构例子
假设有 3 台机器:
node1 node2 node3
索引:
order_index primary_shards: 3 replicas: 1
分布可能是:
node1 shard0 (primary) shard1 (replica) node2 shard1 (primary) shard2 (replica) node3 shard2 (primary) shard0 (replica)
特点:
- 每个 primary 都有 replica
- primary 和 replica 不会在同一节点
这样即使一台机器挂了,数据也不会丢。
五、一句话理解
可以把 ES 想象成:
一个大表 → 自动拆成多个小表 → 分布到不同机器 → 查询时一起查再合并。
===================================================================
假设我们要建一个 订单索引 order_index。
一、创建索引请求
PUT /order_index { "settings": { "number_of_shards": 3, "number_of_replicas": 1 }, "mappings": { "properties": { "order_id": { "type": "keyword" }, "user_id": { "type": "keyword" }, "user_name": { "type": "text", "analyzer": "ik_max_word" }, "amount": { "type": "double" }, "status": { "type": "keyword" }, "product_name": { "type": "text", "analyzer": "ik_smart" }, "create_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } } } }
二、结构解释
1 settings(索引配置)
"settings": { "number_of_shards": 3, "number_of_replicas": 1 }
含义:
- number_of_shards:3
- 主分片数量
- number_of_replicas:1
- 每个主分片有一个副本
所以最终会有:
3 primary shard 3 replica shard 共 6 个 shard
2 mappings(字段结构)
这里类似 数据库表结构。
例如:
order_id -> keyword user_id -> keyword user_name -> text amount -> double status -> keyword create_time-> date
字段类型说明:
-
keyword
- 不分词
- 适合:ID、状态、标签
-
text
- 会分词
- 适合:搜索字段
-
double
- 数值
-
date
- 时间
三、插入一条真实数据
POST /order_index/_doc { "order_id": "10001", "user_id": "u1001", "user_name": "张三", "amount": 299.5, "status": "paid", "product_name": "荣耀手机", "create_time": "2026-05-11 10:23:00" }
ES 实际存储时会变成类似:
_index: order_index _id: 自动生成或指定 _source: { order_id: "10001", user_id: "u1001", user_name: "张三", amount: 299.5, status: "paid", product_name: "荣耀手机", create_time: "2026-05-11 10:23:00" }
四、真实公司常见的索引结构
很多业务索引会长这样:
user_index order_index product_index log_index
例如日志索引通常:
log-2026.05.11 log-2026.05.12 log-2026.05.13
每天一个索引,方便管理和删除。