原理图,引用自:一文彻底搞懂 Elasticsearch:原理、场景、避坑与优化
1 Elasticsearch
- Elasticsearch是什么: 是一个基于 Apache Lucene 的分布式搜索和数据分析引擎,常用于全文搜索、日志分析、安全监控、业务分析和运维监控等场景。
- Elasticsearch 应用场景:适合需要快速搜索和分析海量数据的场景,尤其是传统关系型数据库难以高效处理全文检索和大规模日志分析时。
2 起源
这个应用最初叫 iCook,可以理解为:一个给妻子用的“菜谱管理 + 菜谱搜索”小程序。
当时 Shay Banon 刚到伦敦,妻子正在学习烹饪,他需要一个工具帮她管理、查找烹饪课程中收集到的菜谱和烹饪信息。这个应用的核心能力大致包括:
- 菜谱管理:保存菜谱、配料、步骤等信息。
- 关键词搜索:在搜索框里输入食材、菜名、做法或概念,快速找到相关菜谱。(文本分词匹配)
- 字段检索:按配料、菜名、分类等字段查找,而不只是简单匹配文本。 (关键词精准匹配)
| 阶段 | 背景 | 结果 |
|---|---|---|
| 2004 年前后 | Shay Banon 想为正在学厨师的妻子做一个食谱搜索应用 | 直接使用 Lucene 太复杂,于是封装了一个更易用的 Java 搜索框架Compass |
| 2010 年前后 | 他在工作中接触高并发、分布式场景,发现需要一个可扩展、实时、易用的搜索服务 | 重写 Compass,加入分布式架构,发布Elasticsearch首个版本 |
| 2012 年起 | 开源社区快速增长,企业级需求增多 | 成立 Elasticsearch 公司,后更名为Elastic,并与 Logstash、Kibana 组成ELK / Elastic Stack |
它解决了什么问题
- Lucene 强大但难用
- 传统数据库不擅长全文搜索:关系型数据库在模糊匹配、全文检索、海量日志分析上效率较低。(传统数据库)
- 单机搜索不够用:数据量变大后,需要分布式、可水平扩展、近实时搜索。
3 原理
3.1 倒排索引 (快速匹配文本中的内容,返回docId)
把文本拆成词项,再建立“词项 → 文档”的反向映射结构。
正向 vs 倒排
| 索引类型 | 组织方式 | 查询方式 |
|---|---|---|
| 正向索引 | 文档 → 词项 | 要知道文档里有什么,得看文档本身 |
| 倒排索引 | 词项 → 文档 | 知道一个词,就能直接找到包含它的文档 |
例如:
- 写入一条数据
PUT/products/_doc/1{"name":"苹果 iPhone 15 手机","price":5999,"category":"手机"}文本拆成词项
苹果iPhone 15手机建立“词项 → 文档”的反向映射结构。
| 词项 | 文档ID |
|—|—|
| 苹果 | 1 |
| iPhone | 1 |
| 15 | 1 |
| 手机 | 1 |
3.2 Doc Values (根据分类进行查找,配合倒排索引使用)
- 为 price、category 建立 Doc Values,即 docId → 字段值 的正向映射。
- 通过倒排索引或范围索引,分别获得满足 price 条件和 category 条件的 docId 集合。
- 对多个 docId 集合取交集,得到同时满足条件的候选 docId 集合。
- 再根据候选 docId,从 Doc Values 中读取对应的字段值,用于后续排序、聚合或返回。
Doc Values 是按 docId 顺序存储字段值的列式结构,具体实现可能是压缩数组、字典编码或有序值列表。
4 具体命令使用
Elasticsearch 的日常操作几乎都通过 REST API 完成,下面按「查看状态 → 索引管理 → 文档读写 → 搜索查询」的顺序,把最常用的命令整理一遍。示例默认在 Kibana Dev Tools 中执行,用 curl 时把GET /xxx换成curl -XGET 'http://localhost:9200/xxx'即可。
4.1 集群与节点查看_cluster
# 集群健康状态(green/yellow/red)GET _cluster/health# 节点列表与角色GET _cat/nodes?v&h=name,node.role,heap.percent,cpu,load_1m# 集群统计信息GET _cluster/stats# 查看热点线程,排查 CPU 飙高GET _nodes/hot_threads4.2 索引管理 /products/_mapping
# 创建索引,指定分片数和副本数PUT /products{"settings":{"number_of_shards":3,"number_of_replicas":1}}# 查看索引列表GET _cat/indices?v# 查看索引的映射GET /products/_mapping# 修改副本数PUT /products/_settings{"number_of_replicas":2}# 删除索引DELETE /products4.3 文档读写/products/_doc ; /products/_bulk
# 写入一条文档(指定 ID)PUT /products/_doc/1{"name":"苹果 iPhone 15 手机","price":5999,"category":"手机"}# 写入文档(不指定 ID,由 ES 自动生成)POST /products/_doc{"name":"小米 14 手机","price":3999,"category":"手机"}# 按 ID 查询GET /products/_doc/1# 更新部分字段POST /products/_update/1{"doc":{"price":5499}}# 删除文档DELETE /products/_doc/1# 批量写入POST /products/_bulk{"index":{"_id":"2"}}{"name":"华为 Mate 60","price":6999,"category":"手机"}{"index":{"_id":"3"}}{"name":"iPad Air","price":4799,"category":"平板"}4.4 搜索查询/products/_search
# 查询全部GET /products/_search{"query":{"match_all":{}}}# 全文检索:name 字段包含「手机」GET /products/_search{"query":{"match":{"name":"手机"}}}# 精确匹配 + 范围过滤GET /products/_search{"query":{"bool":{"must":[{"match":{"name":"手机"}}],"filter":[{"range":{"price":{"gte":4000,"lte":7000}}}]}}}# 排序 + 分页 + 只返回部分字段GET /products/_search{"query":{"match_all":{}},"sort":[{"price":"desc"}],"from":0,"size":10,"_source":["name","price"]}# 聚合:按分类统计数量与平均价格GET /products/_search{"size":0,"aggs":{"by_category":{"terms":{"field":"category"},"aggs":{"avg_price":{"avg":{"field":"price"}}}}}}