01 · Elasticsearch 核心概念与 PostgreSQL 对照
阶段:第一阶段 / 核心概念
目标:用 PostgreSQL 的心智模型快速建立 Elasticsearch 的世界观。
1. 概念
Elasticsearch(下称 ES)是一个分布式搜索与分析引擎 ,底层是 Lucene 的倒排索引。
它不是关系型数据库,但很多概念可以和 PostgreSQL 一一对应,帮你快速上手。
术语对照表
| Elasticsearch | PostgreSQL | 说明 |
|---|---|---|
| Index(索引) | Table(表) | 一类文档的集合,如 orders_idx |
| Document(文档) | Row(行) | 一条 JSON 记录 |
| Field(字段) | Column(列) | JSON 里的 key |
| Mapping(映射) | Table Schema / DDL | 定义字段类型 |
_id |
主键 | 文档唯一标识 |
| Shard(分片) | 表分区(近似) | 索引水平切分,分布到多节点 |
| Replica(副本) | 流复制/备库(近似) | 分片的冗余拷贝,用于高可用与读扩展 |
| 倒排索引 | B-Tree / GIN 索引 | ES 默认所有字段都建索引 |
| Node / Cluster | 实例 / 集群 | 多节点组成集群 |
关键差异:在 PostgreSQL 里「先建表,数据默认没索引,需要时才
CREATE INDEX」;在 ES 里「几乎所有字段默认就是可检索的」,因为它的定位就是搜索。
2. PostgreSQL 对照
一张销售数据表在 PG 里是这样的:
sql
CREATE TABLE salesdata_master_info (
record_id bigint PRIMARY KEY,
invoice_number varchar(64),
material varchar(64),
net_amount numeric(18,2),
invoice_dt date
);
INSERT INTO salesdata_master_info
VALUES (1001, 'INV-2026-001', 'ThinkPad-X1', 8999.00, '2026-07-01');
在 ES 里,同样一条数据是一个 JSON 文档:
json
{
"record_id": 1001,
"invoice_number": "INV-2026-001",
"material": "ThinkPad-X1",
"net_amount": 8999.00,
"invoice_dt": "2026-07-01"
}
- PG 的「表结构」= ES 的 mapping
- PG 的「一行」= ES 的 一个 document
- PG 的「主键」= ES 的
_id
3. ES DSL(在 Kibana Dev Tools 里跑)
查看集群健康(相当于「数据库还活着吗」):
GET _cluster/health
查看索引列表(相当于 \dt 列出所有表):
GET _cat/indices?v
查看某个索引的 mapping(相当于查看表结构 \d salesdata_master_info):
GET salesdata_idx/_mapping
查一条文档(相当于 SELECT * FROM t WHERE id = 1001):
GET salesdata_idx/_doc/1001
查全部(相当于 SELECT * FROM t LIMIT 10):
GET salesdata_idx/_search
{
"query": { "match_all": {} },
"size": 10
}
4. Spring Boot 实现
通过 ElasticsearchClient(官方 co.elastic.clients 客户端)访问 ES,
把它声明为 Spring Bean(见第 04 篇),直接注入即可。
java
@Slf4j
@Component
public class ClusterInfoDemo {
@Autowired
private ElasticsearchClient elasticsearchClient;
/** 相当于 SELECT * FROM salesdata_idx WHERE _id = ? */
public Map<String, Object> getById(String indexName, String id) throws IOException {
GetResponse<Map> resp = elasticsearchClient.get(
g -> g.index(indexName).id(id), Map.class);
return resp.found() ? resp.source() : null;
}
/** 相当于 SELECT * FROM salesdata_idx LIMIT 10 */
public List<Map> matchAll(String indexName) throws IOException {
SearchResponse<Map> resp = elasticsearchClient.search(s -> s
.index(indexName)
.query(q -> q.matchAll(m -> m))
.size(10), Map.class);
return resp.hits().hits().stream()
.map(Hit::source)
.collect(Collectors.toList());
}
}
生产落地:用
SearchRequest.of(req -> ...)构建请求,Query.of(q -> q.matchAll(...))兜底空条件(完整骨架见第 42 篇)。
5. 坑与最佳实践
- ES 不是事务型数据库 :没有 PG 那样的 ACID 多行事务,别拿它当主库写业务。
典型模式是:数据先落 PostgreSQL,再同步写入 ES 供查询(批量 bulk 写,见 31/42 篇)。 - 近实时(NRT) :写入后默认 1s 才可被搜索到(
refresh_interval),不是立即可见。 - 分片数创建后不可改:类似 PG 分区策略要提前规划。副本数可以动态调整。
- 不要把 ES 当唯一数据源:它是查询/分析加速层,权威数据仍在 PG。
下一篇
02-Mapping与数据类型.md:重点讲 text vs keyword------这是从 SQL 转 ES 最容易踩的坑。