Skip to content
第 202 / 250 章中间件⏱ 14 分钟阅读

第 202 章:Elasticsearch 入门

学习目标

  • 理解 ES 核心概念
  • 掌握索引与文档操作
  • 学会基础搜索
  • 了解 Spring Data Elasticsearch

一、Elasticsearch 简介

ES 是基于 Lucene分布式搜索与分析引擎,常用于全文搜索、日志分析、APM。

特点:

  • ✅ 全文搜索快(倒排索引)
  • ✅ 近实时(NRT)
  • ✅ 分布式、自动容错
  • ✅ RESTful API
  • ✅ 强大的聚合

二、核心概念

ES关系型数据库
IndexDatabase
Type(7.x 废弃)Table
DocumentRow
FieldColumn
MappingSchema
Query DSLSQL

三、安装

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/1

4.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_afterscroll

六、聚合

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: 5s

7.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.zip

8.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, R0

9.2 文档路由

bash
# 默认 hash(_id) % shards
# 自定义:routing key
PUT /articles/_doc/1?routing=user:123

十、本章小结

概念用途
Index文档集合
DocumentJSON 文档
Mapping字段类型定义
Query DSL搜索语言
Aggregation聚合分析
查询用途
match全文搜索
term精确
bool组合
range范围

动手练习

  1. 创建 articles 索引,定义 mapping
  2. 用 bulk 导入 100 篇文档
  3. 实现标题全文搜索 + 高亮
  4. 按作者分组统计文章数

推荐阅读


下一章:第 203 章:ES 高级搜索与优化

本站基于 VitePress 构建 · 由 Codebook 团队维护