Elasticsearch — 分布式搜索引擎
待复核Elasticsearch 是一个基于 lucene 构建的”分布式 + RESTful API + JSON”搜索引擎。
日常类比:
- postgresql 像图书馆按编号查书——你必须知道这本书在哪个架、哪一行
- Elasticsearch 像 Google 搜索引擎——你输入关键词,它返回所有相关书籍,并按”相关程度”打分排序
它不是要替代关系型数据库,而是补全它的弱项:全文搜索、模糊匹配、海量日志聚合、多维度过滤。Postgres 也能做 LIKE 查询,但一旦数据量上千万行、查询带模糊匹配 + 排序 + 聚合,Postgres 就吃力,而 Elasticsearch 的倒排索引天生为这种场景设计。
下面这些场景,Elasticsearch 是常见默认选型之一:
- 大型应用日志 / 站内搜索:GitHub、Stack Overflow、Wikipedia 等站点曾用或仍在用它做搜索与日志检索(具体栈会随年代变)
- 全文检索 + 评分排序:电商搜索”iPhone 13 256G 黑”要按相关度排,关系库做起来很吃力
- 可观测性(运维监控):ELK Stack(Elasticsearch + Logstash + Kibana)是开源运维监控常见组合
- 8.x 后内置向量搜索:可以存 embedding 做语义搜索,与 Pinecone / Milvus 这类专门向量库正面竞争
- 2021 SSPL 许可争议:Elastic 把许可从 Apache 2.0 改成 SSPL,AWS fork 出 OpenSearch——影响了之后开源数据库圈的许可证选择
理解 Elasticsearch 抓三个概念就够:
倒排索引(Inverted Index)
Section titled “倒排索引(Inverted Index)”普通索引:从”文档 ID”找”内容”。倒排索引:从”词”找”哪些文档包含这个词”。
类比:书末尾的”索引页”,告诉你”分布式”这个词出现在哪些章节。Elasticsearch 把这种结构做到极致——任何字段建索引后都能毫秒级查”包含某词的全部文档”。
分片 + 副本(Shard + Replica)
Section titled “分片 + 副本(Shard + Replica)”每个 index(类似数据库里的表)默认切成多个 shard,自动分布到集群的多台机器上。每个 shard 还可以有副本(replica)做容灾。
- shard 决定水平扩展能力:数据多了加机器就行
- replica 决定可用性:主 shard 挂了,副本顶上
DSL 查询语言
Section titled “DSL 查询语言”用嵌套 JSON 表达复杂查询条件 + 聚合,叫 Query DSL。比 SQL 更适合”模糊 + 多条件 + 聚合”组合,但学习曲线比 SQL 陡。
案例 一:本地启一个单节点集群
Section titled “案例 一:本地启一个单节点集群”docker run -p 9200:9200 -e discovery.type=single-node \ -e xpack.security.enabled=false \ elasticsearch:8.11.0discovery.type=single-node 告诉它”不要去找其他节点”,否则它会一直等集群成员。xpack.security.enabled=false 关掉认证(仅本地玩具用)。
案例 二:索引一个文档
Section titled “案例 二:索引一个文档”PUT /products/_doc/1Content-Type: application/json
{ "name": "iPhone 13", "price": 999, "tags": ["phone", "apple"]}/products 是索引名(相当于表);/_doc/1 是文档 ID。Elasticsearch 自动推断字段类型(name → text,price → long,tags → keyword 数组),这叫动态 mapping。
案例 三:搜索 + 评分
Section titled “案例 三:搜索 + 评分”POST /products/_searchContent-Type: application/json
{ "query": { "match": { "name": "iPhone" } }}返回结果里每个文档都有一个 _score——这就是”相关度评分”,由 BM25 算法算出(默认)。match 会对查询词做分词,所以搜 “iphone 13 black” 能匹配到 “iPhone 13” 文档。
Mapping 一旦定义不能改字段类型
Section titled “Mapping 一旦定义不能改字段类型”字段一旦确定是 text 或 long,改不了。要改只能:
- 新建一个空 index,用对的 mapping
- 用
_reindexAPI 把旧数据全量复制过去 - 切换别名指向新 index
新人最容易踩——动态 mapping 把字段推断错了,几个月后才发现,数据已经几亿条。
分片数 fix 后不能改
Section titled “分片数 fix 后不能改”number_of_shards 在 index 创建时定,之后改不了。设小了没法水平扩展,设大了每个 shard 太小浪费资源。生产经验:单 shard 控制在 10-50GB,按预期数据量算 shard 数。
内存(heap)默认 1G 太小
Section titled “内存(heap)默认 1G 太小”JVM heap 默认 1G,生产环境至少 16-32G。但不要超过 32G——超过后 JVM 失去 compressed oops 优化反而更慢。机器物理内存的另一半留给 Lucene 的文件系统缓存(Lucene 大量使用 mmap)。
慢日志和热索引混在一起影响性能
Section titled “慢日志和热索引混在一起影响性能”把”慢的写入密集型 index”(比如日志)和”快的查询密集型 index”(比如商品搜索)放同一个集群,互相影响。最佳实践:分集群 —— logging 集群和 search 集群独立。
适用 vs 不适用
Section titled “适用 vs 不适用”适用:
- 全文搜索 / 模糊匹配 / 相关度排序(百万~百亿文档级常见)
- 日志与可观测性检索(ELK),写入吞吐高、查询以过滤+聚合为主
- 需要近实时索引(秒级可见),可接受最终一致而非跨文档事务
不适用:
- 需要多行事务 / 强一致主键更新 → 用 postgresql
- 只要精确 KV 快读 → 用 redis
- 数据量很小(万级)且只要简单 LIKE → 关系库或 meilisearch 更轻
历史小故事(可跳过)
Section titled “历史小故事(可跳过)”- 2010 年:Shay Banon 给妻子做菜谱搜索时,对 Lucene 做了分布式封装,开源命名为 Elasticsearch
- 2012 年:Elastic 公司成立,商业化
- 2018 年:Elastic 上市 IPO(NYSE: ESTC)
- 2021 年:许可证从 Apache 2.0 改成 SSPL,不再算 OSI 意义下的”开源”
- 2021-04:AWS fork 出 OpenSearch(保留 Apache 2.0),社区分裂
- 2024 年:Elasticsearch 8.x 主推向量搜索 + 内置 ML 模型(ELSER)做语义搜索
- 关系库 + 搜索引擎是互补关系:写入和事务靠关系库(Postgres),查询和聚合靠搜索引擎(Elasticsearch)。常见架构是 Postgres 写主存储 → CDC(变更数据捕获)同步到 Elasticsearch
- 倒排索引是搜索引擎的命根子:理解它就理解 80% 的搜索引擎设计
- shard / replica 是分布式系统的通用语言:mongodb / cassandra / Kafka 的设计哲学一样
- 开源许可证是商业战略:SSPL 之争之后,Redis / MongoDB / Confluent 都跟进改许可,云厂商也都做了 fork,整个生态都被影响
- 官方文档:Elasticsearch Guide
- 许可分叉对照:opensearch —— AWS 主导的 Apache 2.0 分叉
- 轻量替代:meilisearch / typesense —— 开发者友好的搜索引擎
- 底层引擎血缘:Lucene 倒排索引与 BM25 评分(Elasticsearch 的地基)
- opensearch —— 2021 许可变更后的 Apache 2.0 分叉,运维概念高度同构
- meilisearch —— 更轻的搜索引擎,适合中小站内搜
- postgresql —— 主存储常用关系库;和 Elasticsearch 是互补不是替代
- redis —— 同样常和 Postgres 搭配,但解决的是”快读取”不是”全文搜索”
- kafka —— 日志管道里常作 Logstash/Beats 上游缓冲
- typesense —— 另一条高性能搜索引擎路线,对照选型
- croft-harper-1979 —— Croft-Harper 1979 — 没有相关性反馈也能跑概率检索
- milvus-2021 —— Milvus 2021:把向量搜索做成数据库
- opensearch —— OpenSearch — AWS 主导的 Apache 2.0 搜索引擎分叉
- druid —— Apache Druid — 流批一体的实时分析数据库
- grafana —— Grafana — 监控可视化看板
- jaeger —— Jaeger — 分布式追踪系统
- loki —— Loki — 给日志做 Prometheus,只索引标签不索引内容
- manticoresearch —— Manticore Search — 用 MySQL 协议连的搜索 + OLAP 引擎
- meilisearch —— MeiliSearch — 开发者友好的搜索引擎
- minisearch —— minisearch — 浏览器里的小型全文搜索引擎
- neo4j —— Neo4j — 主流图数据库
- opensearch —— OpenSearch — AWS 主导的 Apache 2.0 搜索引擎分叉
- pino —— pino — 日志不该阻塞热路径
- pouchdb —— PouchDB — 浏览器里的 CouchDB
- prometheus —— Prometheus — 时序监控系统
- ravendb —— RavenDB — .NET 生态首选的 ACID 文档数据库
- sonic —— Sonic — 极简前缀搜索引擎
- tantivy —— Tantivy — Rust 版 Lucene
- typesense —— Typesense — 高性能搜索引擎
- vector —— Vector — Rust 写的统一可观测性数据管道
- vespa —— Vespa — Yahoo 检索 + 排序引擎
- zincsearch —— ZincSearch — 单二进制 Go 写的 ES 替代