Elasticsearch 全文搜索引擎详解:从入门到实战 🔍

Elasticsearch(简称 ES)是一个基于 Lucene 构建的开源分布式全文搜索引擎,提供了强大的全文检索、数据分析和实时处理能力。本文将带你全面了解 Elasticsearch 的核心概念、索引管理、搜索查询以及与 Spring Boot 的集成实战!💪


📚 目录导航


一、Elasticsearch 概述

1.1 什么是 Elasticsearch?

Elasticsearch 是一个基于 Apache Lucene 构建的开源分布式全文搜索引擎,它主要特点包括:

为什么选择 Elasticsearch?

  • 🌐 全球最流行的搜索引擎:在 DB-Engines 排名中稳居前三
  • 📦 开箱即用:安装简单,配置友好
  • 🔍 强大的搜索能力:支持全文检索、模糊匹配、短语搜索等
  • 📊 实时分析:秒级聚合分析和数据可视化
  • 🌐 分布式原生支持:天然支持海量数据水平扩展
  • 🔌 丰富的客户端:支持 Java、Python、Go 等多种语言

1.2 Elasticsearch 能做什么?

应用场景 说明 典型案例
全文搜索 关键词搜索、模糊匹配、同义词搜索 电商商品搜索、站内搜索、文档检索
日志分析 集中收集、搜索和分析日志 ELK 日志系统、Splunk 替代方案
应用性能监控 监控应用指标、追踪请求链路 APM 系统、性能分析
安全分析 安全日志分析、威胁检测 SIEM 系统、入侵检测
业务分析 数据聚合分析、BI 报表 用户行为分析、运营统计

1.3 Elasticsearch vs 关系型数据库

概念对应关系:

关系型数据库 Elasticsearch 说明
Database Index 索引,数据的逻辑容器
Table Type(已废弃) 类型,ES 7.x 后一个 Index 就是一个 Type
Row Document 文档,JSON 格式的基本数据单元
Column Field 字段,文档中的键值对
Schema Mapping 映射,定义字段类型和索引方式
SQL Query DSL 查询 DSL,ES 的查询语言

二、核心概念与架构

2.1 核心概念详解

2.2 Elasticsearch 集群架构

节点类型详解:

节点类型 说明 配置
Master Node 负责集群管理、索引创建删除、分片分配 node.master: true
Data Node 存储数据、执行查询 node.data: true
Coordinating Node 接收请求、分发到数据节点 node.master: false, node.data: false
Ingest Node 数据预处理、转换 node.ingest: true

2.3 倒排索引原理

倒排索引是 ES 实现快速全文搜索的核心技术,理解它对于更好地使用 ES 至关重要。

正向索引工作方式:

  • 文档1 → 关键词1、关键词2、关键词3
  • 搜索关键词1 时,需要遍历所有文档

倒排索引工作方式:

  • 关键词1 → 文档1、文档3
  • 搜索关键词1 时,直接定位到包含该词的文档

2.4 分词器(Analyzer)

ES 的分词器决定了文本如何被切分成词条:

常见分词器:

分词器 说明 适用场景
standard ES 默认分词器,按单词边界切分 英文
ik_smart 粗粒度分词,快速分词 中文搜索
ik_max_word 细粒度分词,最大程度切分 中文搜索(全面覆盖)
pinyin 中文拼音分词 拼音搜索

三、快速入门

3.1 安装 Elasticsearch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 下载 Elasticsearch 8.x
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.0-linux-x86_64.tar.gz

# 2. 解压
tar -xzf elasticsearch-8.11.0-linux-x86_64.tar.gz
cd elasticsearch-8.11.0

# 3. 配置 JVM 内存(可选)
vim config/jvm.options.d/heap.options
-Xms4g
-Xmx4g

# 4. 创建非 root 用户(ES 不允许 root 启动)
useradd elasticsearch
chown -R elasticsearch:elasticsearch elasticsearch-8.11.0
su elasticsearch

# 5. 启动
./bin/elasticsearch

# 6. 后台启动
./bin/elasticsearch -d -p pid

# 7. 验证启动
curl http://localhost:9200

启动响应示例:

1
2
3
4
5
6
7
8
9
{
"name": "node-1",
"cluster_name": "elasticsearch",
"cluster_uuid": "abc123...",
"version": {
"number": "8.11.0"
},
" tagline": "You Know, for Search"
}

3.2 安装 Kibana(可视化工具)

Kibana 是 ES 官方提供的可视化平台,用于查询、分析和可视化 ES 数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 下载 Kibana
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.11.0-linux-x86_64.tar.gz

# 2. 解压
tar -xzf kibana-8.11.0-linux-x86_64.tar.gz

# 3. 配置(连接到 ES)
vim config/kibana.yml
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://localhost:9200"]

# 4. 启动
./bin/kibana

# 5. 访问 http://localhost:5601

3.3 集群健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 检查集群健康状态
GET _cluster/health

# 返回:
{
"cluster_name": "my-cluster",
"status": "green", # green(完美)/yellow(副本有问题)/red(主分片有问题)
"number_of_nodes": 3,
"active_shards": 21,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}

# 查看节点列表
GET _cat/nodes?v

# 查看分片状态
GET _cat/shards?v

3.4 安全配置(ES 8.x 新增)

ES 8.x 默认开启了安全特性,需要配置认证:

1
2
3
4
5
6
7
8
9
# 生成密码(首次安装时)
./bin/elasticsearch-setup-passwords interactive

# 使用用户名密码访问
curl -u elastic:password http://localhost:9200

# 或关闭安全认证(开发环境)
vim config/elasticsearch.yml
xpack.security.enabled: false

四、索引与文档操作

4.1 创建索引

索引是 ES 中存储文档的逻辑容器,类似于关系型数据库中的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 创建索引(设置分片数和副本数)
PUT /my_index
{
"settings": {
"number_of_shards": 3, # 主分片数量
"number_of_replicas": 1, # 每个主分片的副本数
"refresh_interval": "1s", # 刷新间隔
"analysis": { # 分析器配置
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword" # 支持精确查询
}
}
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"author": {
"type": "keyword" # 关键字类型,不分词,精确匹配
},
"tags": {
"type": "keyword" # 标签,可多值
},
"created_at": {
"type": "date", # 日期类型
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"views": {
"type": "long" # 长整型
},
"price": {
"type": "double" # 双精度浮点型
},
"is_published": {
"type": "boolean" # 布尔类型
},
"location": {
"type": "geo_point" # 地理位置
}
}
}
}

4.2 查看索引信息

1
2
3
4
5
6
7
8
# 查看索引信息
GET /my_index

# 查看所有索引
GET _cat/indices?v

# 查看索引映射
GET /my_index/_mapping

4.3 文档操作(CRUD)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# ➕ 新增文档(自动生成 ID)
POST /my_index/_doc
{
"title": "Elasticsearch 入门教程",
"content": "本文介绍 Elasticsearch 的基本使用方法,包括索引、文档操作和搜索查询...",
"author": "张三",
"tags": ["ES", "搜索引擎", "入门"],
"created_at": "2026-05-24",
"views": 1000,
"price": 99.00,
"is_published": true
}

# ➕ 新增文档(指定 ID)
PUT /my_index/_doc/1
{
"title": "Elasticsearch 进阶指南",
"content": "深入学习 Elasticsearch 的高级特性...",
"author": "李四",
"tags": ["ES", "进阶"],
"created_at": "2026-05-25",
"views": 2000
}

# 📖 查询文档
GET /my_index/_doc/1

# 📖 查询文档(包含源数据)
GET /my_index/_doc/1?_source=title,author

# 📋 批量操作
POST /_bulk
{"index":{"_index":"my_index","_id":"10"}}
{"title":"批量文档1","author":"王五"}
{"index":{"_index":"my_index","_id":"11"}}
{"title":"批量文档2","author":"赵六"}

# ✏️ 更新文档(全部更新)
PUT /my_index/_doc/1
{
"title": "Elasticsearch 进阶教程(更新版)",
"views": 3000
}

# 🔄 部分更新
POST /my_index/_update/1
{
"doc": {
"views": 5000,
"updated_at": "2026-05-26"
}
}

# 🔄 使用脚本更新
POST /my_index/_update/1
{
"script": {
"source": "ctx._source.views += params.count",
"params": {
"count": 100
}
}
}

# 🗑️ 删除文档
DELETE /my_index/_doc/1

# 🗑️ 删除索引
DELETE /my_index

4.4 批量操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 批量新增
POST /_bulk
{"index":{"_index":"my_index"}}
{"title":"文章1","author":"作者A"}
{"index":{"_index":"my_index"}}
{"title":"文章2","author":"作者B"}
{"index":{"_index":"my_index"}}
{"title":"文章3","author":"作者A"}

# 混合操作
POST /_bulk
{"index":{"_index":"my_index"}}
{"title":"新文章1","author":"作者C"}
{"update":{"_index":"my_index","_id":"1"}}
{"doc":{"views":9999}}
{"delete":{"_index":"my_index","_id":"2"}}

五、搜索查询详解

5.1 全文搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 📝 单字段全文搜索
GET /my_index/_search
{
"query": {
"match": {
"title": "Elasticsearch 入门"
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
}
}
}
}

# 📝 多字段全文搜索
GET /my_index/_search
{
"query": {
"multi_match": {
"query": "Elasticsearch 教程",
"fields": ["title^2", "content"], # ^2 表示 title 权重更高
"type": "best_fields" # 最佳字段匹配
}
}
}

5.2 精确查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 🎯 精确匹配(term 查询不分词)
GET /my_index/_search
{
"query": {
"term": {
"author": "张三"
}
}
}

# 🎯 多值精确匹配
GET /my_index/_search
{
"query": {
"terms": {
"tags": ["ES", "搜索引擎"]
}
}
}

5.3 范围查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 📊 数值范围查询
GET /my_index/_search
{
"query": {
"range": {
"views": {
"gte": 100, # greater than or equal
"lte": 1000, # less than or equal
"boost": 2.0 # 权重提升
}
}
}
}

# 📅 日期范围查询
GET /my_index/_search
{
"query": {
"range": {
"created_at": {
"gte": "2026-01-01",
"lte": "2026-05-31",
"format": "yyyy-MM-dd"
}
}
}
}

5.4 布尔查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 🔗 组合多个查询条件
GET /my_index/_search
{
"query": {
"bool": {
"must": [ # 必须匹配(AND)
{ "match": { "title": "Elasticsearch" } }
],
"should": [ # 应该匹配(OR)
{ "match": { "content": "教程" } },
{ "match": { "content": "入门" } }
],
"must_not": [ # 不能匹配(NOT)
{ "term": { "author": "测试用户" } }
],
"filter": [ # 过滤(不计分缓存)
{ "range": { "views": { "gte": 100 } } },
{ "term": { "is_published": true } }
]
}
}
}

5.5 高亮和排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 🎨 高亮显示匹配词
GET /my_index/_search
{
"query": {
"match": { "title": "Elasticsearch" }
},
"highlight": {
"fields": {
"title": {},
"content": {
"fragment_size": 150, # 摘要长度
"number_of_fragments": 3 # 片段数量
}
},
"pre_tags": ["<mark>"],
"post_tags": ["</mark>"]
}
}

# 📊 排序
GET /my_index/_search
{
"query": { "match_all": {} },
"sort": [
{ "views": "desc" }, # 按浏览量降序
{ "created_at": "asc" }, # 按时间升序
"_score" # 按相关性得分
]
}

六、聚合分析

6.1 聚合查询概述

ES 的聚合功能非常强大,支持多种聚合分析:

6.2 桶聚合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 📈 按作者分桶统计文章数量
GET /my_index/_search
{
"size": 0,
"aggs": {
"by_author": {
"terms": {
"field": "author",
"size": 10, # 返回前 10 个桶
"order": { "_count": "desc" } # 按文档数降序
}
}
}
}

# 📅 按月份分桶统计
GET /my_index/_search
{
"size": 0,
"aggs": {
"by_month": {
"date_histogram": {
"field": "created_at",
"calendar_interval": "month",
"format": "yyyy-MM"
}
}
}
}

# 💰 按价格范围分桶
GET /my_index/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "key": "free", "to": 0 },
{ "key": "cheap", "from": 0, "to": 50 },
{ "key": "normal", "from": 50, "to": 100 },
{ "key": "expensive", "from": 100 }
]
}
}
}
}

6.3 指标聚合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 📊 多指标统计
GET /my_index/_search
{
"size": 0,
"aggs": {
"views_stats": {
"stats": {
"field": "views"
}
},
"max_views": {
"max": { "field": "views" }
},
"avg_price": {
"avg": { "field": "price" }
}
}
}

# 🧮 去重统计
GET /my_index/_search
{
"size": 0,
"aggs": {
"unique_authors": {
"cardinality": {
"field": "author"
}
}
}
}

6.4 嵌套聚合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 🔗 桶 + 指标嵌套聚合
GET /my_index/_search
{
"size": 0,
"aggs": {
"by_author": {
"terms": {
"field": "author",
"size": 10
},
"aggs": {
"avg_views": {
"avg": { "field": "views" }
},
"total_views": {
"sum": { "field": "views" }
}
}
}
}
}

七、分布式特性

7.1 分片与副本机制

分片数量的选择建议:

数据量 推荐分片数 说明
< 10GB 1-2 小数据集
10-50GB 3-5 中等数据集
50-100GB 5-10 大数据集
> 100GB 根据节点数决定 通常 20-30GB/分片

7.2 数据写入流程

7.3 数据一致性级别

级别 说明 性能
consistency=one 主分片和至少一个副本确认 较快
consistency=quorum 半数以上分片确认 中等
consistency=all 所有副本确认 较慢

八、Spring Boot 集成 ES

8.1 添加依赖

1
2
3
4
5
<!-- Spring Data Elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

8.2 配置

1
2
3
4
5
6
7
8
# application.yml
spring:
elasticsearch:
uris: http://localhost:9200
username: elastic
password: password
connection-timeout: 5s
socket-timeout: 30s

8.3 实体类定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 博客文章实体类
*/
@Document(indexName = "blog_index") // 索引名称
@Data
public class Blog {

@Id // 文档 ID
private String id;

@Field(type = FieldType.Text, analyzer = "ik_max_word") // 文本类型,支持分词
private String title;

@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String content;

@Field(type = FieldType.Keyword) // 关键字类型,不分词
private String author;

@Field(type = FieldType.Keyword)
private List<String> tags;

@Field(type = FieldType.Long)
private Long views;

@Field(type = FieldType.Double)
private Double price;

@Field(type = FieldType.Boolean)
private Boolean isPublished;

@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
private LocalDateTime createdAt;

@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
private LocalDateTime updatedAt;
}

8.4 Repository 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Blog Repository 接口
* 继承 ElasticsearchRepository,自动具备 CRUD 功能
*/
public interface BlogRepository extends ElasticsearchRepository<Blog, String> {

// 🎯 根据标题查询
List<Blog> findByTitle(String title);

// 🎯 根据作者查询
List<Blog> findByAuthor(String author);

// 📊 按作者查询并排序
List<Blog> findByAuthorOrderByCreatedAtDesc(String author);

// 📈 查询浏览量大于指定值的文章
List<Blog> findByViewsGreaterThan(Long views);

// 🔍 模糊查询标题
List<Blog> findByTitleContaining(String keyword);

// 🏷️ 按标签查询
List<Blog> findByTagsContaining(String tag);
}

8.5 自定义查询方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 自定义复杂查询
*/
@Service
public class BlogService {

@Autowired
private ElasticsearchOperations elasticsearchOperations;

@Autowired
private BlogRepository blogRepository;

/**
* 复杂条件查询
*/
public SearchHits<Blog> searchBlogs(String keyword, String author, Long minViews) {

// 构建查询条件
Criteria criteria = new Criteria("title").matches(keyword)
.and(new Criteria("author").is(author));

if (minViews != null) {
criteria = criteria.and(new Criteria("views").greaterThanEqual(minViews));
}

Query query = new CriteriaQuery(criteria);
return elasticsearchOperations.search(query, Blog.class);
}

/**
* 分页查询
*/
public Page<Blog> searchByPage(String keyword, int page, int size) {
Query query = new StringQuery("{\"match\":{\"title\":\"" + keyword + "\"}}");

Pageable pageable = PageRequest.of(page, size);
query.setPageable(pageable);

SearchHits<Blog> hits = elasticsearchOperations.search(query, Blog.class);
return new PageImpl<>(hits.getSearchHits(), pageable, hits.getTotalHits());
}

/**
* 聚合查询
*/
public Map<String, Long> getAuthorArticleCounts() {
Criteria criteria = new Criteria();
Query query = new CriteriaQuery(criteria);

SearchHits<Blog> hits = elasticsearchOperations.search(query, Blog.class);

// 简单聚合:按作者分组统计
Map<String, Long> result = new HashMap<>();
hits.getSearchHits().forEach(hit -> {
String author = hit.getContent().getAuthor();
result.merge(author, 1L, Long::sum);
});

return result;
}
}

九、ELK 日志分析实战

9.1 ELK 架构概述

9.2 Filebeat 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/myapp/*.log
fields:
app: myapp
env: production

output.elasticsearch:
hosts: ["localhost:9200"]
index: "app-logs-%{+yyyy.MM.dd}"

9.3 Logstash 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# pipeline.conf
input {
beats {
port => 5044
}
}

filter {
json {
source => "message"
}

date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
}

output {
elasticsearch {
hosts => ["localhost:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}

十、常见问题与最佳实践

10.1 常见问题

10.2 最佳实践

实践 说明 推荐程度
分片大小控制 每个分片建议 20-50GB ✅✅✅
副本数量 生产环境至少 1 副本 ✅✅✅
冷热分离 热数据 SSD,冷数据 HDD ✅✅
使用别名 通过别名切换索引 ✅✅
路由优化 合理使用 routing 参数 ✅✅

十一、总结

11.1 核心知识点回顾

11.2 学习路线


💡 写给读者的话:Elasticsearch 是现代搜索和日志分析的核心组件,掌握其使用对后端开发者来说至关重要。希望本文能帮助你建立完整的 ES 知识体系,在项目中游刃有余地使用 Elasticsearch!🔍


📅 本文首次发布于 2026 年 5 月 24 日