第 202 章:Elasticsearch 入门
学习目标
- 理解 ES 核心概念
- 掌握索引与文档操作
- 学会基础搜索
- 了解 Spring Data Elasticsearch
一、Elasticsearch 简介
ES 是基于 Lucene 的分布式搜索与分析引擎,常用于全文搜索、日志分析、APM。
特点:
- ✅ 全文搜索快(倒排索引)
- ✅ 近实时(NRT)
- ✅ 分布式、自动容错
- ✅ RESTful API
- ✅ 强大的聚合
二、核心概念
| ES | 关系型数据库 |
|---|---|
| Index | Database |
| Type(7.x 废弃) | Table |
| Document | Row |
| Field | Column |
| Mapping | Schema |
| Query DSL | SQL |
三、安装
yaml
# docker-compose.yml
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
environment:
discovery.type: single-node
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
xpack.security.enabled: "false"
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:8.11.0
environment:
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports:
- "5601:5601"bash
# 健康检查
curl http://localhost:9200/_cluster/health四、基础操作
4.1 创建索引
bash
PUT /articles
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word" # 中文分词
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"author": {
"type": "keyword" # 不分词,用于精确匹配
},
"tags": {
"type": "keyword"
},
"viewCount": {
"type": "integer"
},
"createdAt": {
"type": "date"
}
}
}
}4.2 文档 CRUD
bash
# 索引(创建/全量替换)
PUT /articles/_doc/1
{
"title": "NestJS 教程",
"content": "...",
"author": "Tom",
"tags": ["nestjs", "node"],
"viewCount": 100,
"createdAt": "2024-01-01"
}
# 局部更新
POST /articles/_update/1
{
"doc": {
"viewCount": 101
}
}
# 查
GET /articles/_doc/1
# 删
DELETE /articles/_doc/14.3 Bulk 批量
bash
POST /_bulk
{"index":{"_index":"articles","_id":"2"}}
{"title":"Kafka","author":"Jerry"}
{"index":{"_index":"articles","_id":"3"}}
{"title":"Redis","author":"Bob"}五、搜索
5.1 match(全文搜索)
bash
POST /articles/_search
{
"query": {
"match": {
"title": "NestJS 教程"
}
}
}5.2 term(精确)
bash
POST /articles/_search
{
"query": {
"term": {
"author": "Tom"
}
}
}5.3 terms(多值)
bash
POST /articles/_search
{
"query": {
"terms": {
"author": ["Tom", "Jerry"]
}
}
}5.4 bool(组合)
bash
POST /articles/_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Redis" } }
],
"filter": [
{ "term": { "author": "Tom" } },
{ "range": { "viewCount": { "gte": 100 } } }
],
"must_not": [
{ "term": { "tags": "draft" } }
]
}
}
}5.5 highlight(高亮)
bash
POST /articles/_search
{
"query": { "match": { "title": "NestJS" } },
"highlight": {
"fields": {
"title": {
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
}
}
}
}5.6 分页 + 排序
bash
POST /articles/_search
{
"query": { "match_all": {} },
"from": 0,
"size": 10,
"sort": [
{ "viewCount": "desc" },
{ "createdAt": "desc" }
]
}深分页
from + size > 10000 会报错,改用 search_after 或 scroll。
六、聚合
6.1 指标聚合
bash
POST /articles/_search
{
"aggs": {
"total_views": {
"sum": { "field": "viewCount" }
},
"avg_views": {
"avg": { "field": "viewCount" }
},
"max_views": {
"max": { "field": "viewCount" }
}
},
"size": 0
}6.2 桶聚合
bash
POST /articles/_search
{
"aggs": {
"by_author": {
"terms": {
"field": "author",
"size": 10
},
"aggs": {
"avg_views": { "avg": { "field": "viewCount" } }
}
}
},
"size": 0
}6.3 日期直方图
bash
POST /articles/_search
{
"aggs": {
"sales_over_time": {
"date_histogram": {
"field": "createdAt",
"calendar_interval": "day"
}
}
},
"size": 0
}七、Spring Data Elasticsearch
7.1 引入
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>7.2 配置
yaml
spring:
elasticsearch:
uris: http://localhost:9200
connection-timeout: 5s7.3 实体
java
@Document(indexName = "articles")
public class Article {
@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.Integer)
private Integer viewCount;
@Field(type = FieldType.Date)
private LocalDateTime createdAt;
}7.4 Repository
java
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
List<Article> findByAuthor(String author);
List<Article> findByTitleContaining(String keyword);
@Query("{\"match\": {\"title\": \"?0\"}}")
List<Article> searchByTitle(String keyword);
}7.5 复杂查询
java
@Service
public class ArticleService {
@Autowired
private ElasticsearchOperations elasticsearchOperations;
public SearchHits<Article> search(SearchRequest req) {
NativeQuery query = NativeQuery.builder()
.withQuery(q -> q.bool(b -> b
.must(m -> m.match(mq -> mq.field("title").query(req.getKeyword())))
.filter(f -> f.term(t -> t.field("author").value(req.getAuthor())))
))
.withPageable(PageRequest.of(req.getPage(), req.getSize()))
.withSort(Sort.by(Sort.Direction.DESC, "viewCount"))
.build();
return elasticsearchOperations.search(query, Article.class);
}
}八、中文分词
8.1 IK 分词器
bash
# 安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.0/elasticsearch-analysis-ik-8.11.0.zip8.2 使用
json
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word" // 最细粒度
},
"content": {
"type": "text",
"analyzer": "ik_smart" // 粗粒度
}
}
}
}ik_max_word:拆最多词,适合索引 ik_smart:智能拆,适合搜索
九、ES 集群
9.1 分片与副本
Index: articles (3 primary + 1 replica)
Shard 0: [P0, R0]
Shard 1: [P1, R1]
Shard 2: [P2, R2]
分布:
Node 1: P0, R1
Node 2: P1, R2
Node 3: P2, R09.2 文档路由
bash
# 默认 hash(_id) % shards
# 自定义:routing key
PUT /articles/_doc/1?routing=user:123十、本章小结
| 概念 | 用途 |
|---|---|
| Index | 文档集合 |
| Document | JSON 文档 |
| Mapping | 字段类型定义 |
| Query DSL | 搜索语言 |
| Aggregation | 聚合分析 |
| 查询 | 用途 |
|---|---|
| match | 全文搜索 |
| term | 精确 |
| bool | 组合 |
| range | 范围 |
动手练习
- 创建 articles 索引,定义 mapping
- 用 bulk 导入 100 篇文档
- 实现标题全文搜索 + 高亮
- 按作者分组统计文章数
推荐阅读
下一章:第 203 章:ES 高级搜索与优化 →