Elasticsearch 入门教程:核心原理、Docker 部署与中文搜索实战

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 适合想快速上手 Elasticsearch 的后端开发者和搜索服务初学者。读完你会理解 ES 为什么搜得快、怎么在本地搭一套完整环境、怎么写查询、以及怎么把 MySQL 数据同步到 ES。

最近在给项目接全文搜索功能,折腾了一圈 Elasticsearch,从装环境到调分词再到上线同步方案,踩了不少坑。这份 Elasticsearch 入门教程整理了从零到跑通的全部经历,希望能帮你少走弯路。点个收藏,我们开始。

一、Elasticsearch 是什么:不只是"搜索引擎"

Elasticsearch(简称 ES) 是一个开源的分布式搜索与分析引擎,基于 Apache Lucene 构建。它存数据,但真正擅长的是对海量文本做近实时的全文检索——你可以把它理解为"给数据库装上了百度搜索"。

如果把 ES 和 MySQL 做一层概念映射,对应关系大致如下:

MySQL Elasticsearch 说明
Database Cluster 一个 ES 集群对应一个数据库实例
Table Index(索引) 数据存储的逻辑单元
Row Document(文档) 最小数据单位,JSON 格式
Column Field(字段) 文档中的属性
Schema Mapping(映射) 定义字段类型和索引方式

ES 7.x 之后,Type 的概念被废弃,一个 Index 下默认只保留 _doc 类型,架构比 6.x 清爽了不少。

ES 有几个让我觉得"真香"的特性:分布式架构天生支持横向扩展、数据写入后近实时可搜(默认 1 秒 refresh)、RESTful API 让任何语言都能调用、插件化设计可以按需扩展。这几个特性叠加在一起,让 ES 成了全文搜索领域的事实标准。

Elasticsearch 与 MySQL 概念对比示意图,Elasticsearch 入门教程核心概念:左侧 MySQL 术语,右侧对应 ES 术语

二、倒排索引:为什么 ES 搜得这么快

讲 ES 绕不开倒排索引——它是全文搜索能力的根基,不理解它,后面的分词器和查询优化都只能死记硬背。

2.1 什么是倒排索引

传统的"正排索引"是文档 → 关键词的映射,就像翻到一本书的某页去看这页写了什么。而倒排索引(Inverted Index) 反其道而行之,是关键词 → 文档的映射——就像书末的索引页,查"分布式"三个字,直接告诉你出现在哪几页。

举个例子,假设有 3 篇文档:

  • 文档 1:Elasticsearch 是分布式引擎
  • 文档 2:分布式系统的核心是搜索
  • 文档 3:搜索引擎的未来是智能化

经过分词和归一化处理后,倒排索引长这样:

关键词 文档 ID
elasticsearch 1
分布式 1, 2
系统 2
搜索 2, 3
引擎 1, 3

当用户搜索"引擎"时,ES 直接查表定位到文档 1 和 3,不需要扫描全部文档——时间复杂度从 O(n) 降到了 O(1)。

2.2 倒排索引的构建过程

倒排索引构建三步流程,Elasticsearch 入门教程必知:分词 → 归一化 → 创建倒排列表

第一步:分词(Tokenization)。把原始文本拆成独立的词条。比如"Elasticsearch支持全文检索"拆成 [elasticsearch, 支持, 全文, 检索]

第二步:归一化(Normalization)。对分词结果做标准化——转小写(Elasticsearch → elasticsearch)、去掉"的""是"这类停用词、做词干提取(running → run)。这一步直接决定了后续搜索的召回质量。

第三步:创建倒排列表。为每个词项建立到文档 ID 的映射关系,持久化存储。最终结构类似 {"elasticsearch": [1], "分布式": [1, 2], ...}

2.3 用户搜索时发生了什么

搜索执行流程:用户输入 → 解析查询词并分词 → 查倒排索引 → 合并结果集 → 相关性排序 → 返回

当用户输入"分布式搜索"时,ES 的执行链路是这样的:查询词同样被分词(分布式 + 搜索)→ 分别查倒排索引(分布式 → [1,2],搜索 → [2,3])→ 按 AND/OR 逻辑合并结果 → 用 TF-IDF 或 BM25 算法算相关性评分并排序。整个链路在毫秒级完成,这就是倒排索引的威力。

三、分词器:搜索质量的命门

倒排索引的质量,很大程度上取决于分词器(Analyzer)。分词器决定了文本怎么拆、怎么存、怎么搜——它是在字符写入索引之前必须要经过的"安检通道"。

ES 的 Analyzer 由三个组件串联而成:

分词器三大组件处理流程:字符过滤器预处理 → 分词器切分文本 → 词项过滤器后处理

  1. 字符过滤器(Character Filters):预处理,比如去掉 HTML 标签、替换特殊字符(如把 & 转成 and
  2. 分词器(Tokenizer):将文本按规则切分成一个个词项,这是整个流程中唯一必须的组件
  3. 词项过滤器(Token Filters):对词项做后处理——转小写、去停用词、词干提取等

ES 内置了多种分词器,我整理了一张场景对照表:

分词器 分词方式 中文效果 适用场景
standard 按词边界切分,转小写 逐字拆分(差) 英文通用场景
simple 按非字母字符切分 逐字拆分 简单英文文本
whitespace 仅按空格切分 不分词 大小写敏感场景
keyword 不分词,整个输入作为单个词项 不分词 精确匹配(ID、状态码)
stop standard + 过滤停用词 逐字拆分 英文长文搜索

注意到没? 上面所有内置分词器对中文的处理都是"逐字拆分"——standard 会把"秋季穿搭指南"切成"秋、季、穿、搭、指、南"六个单字。这意味着搜"秋季"时,term 查询可能颗粒无收(后面第六章会详细演示这个坑)。这就是为什么必须装 IK 分词器。

四、Docker 部署 ES + Kibana:十分钟跑起本地环境

开发环境用 Docker 跑 ES 最省心——一行命令启动,不想要了直接 docker rm -f 清掉。以下基于 ES 7.3.0(2026 年 7 月实测可用)。

4.1 拉取镜像并单节点启动

# 拉取镜像
docker pull elasticsearch:7.3.0

# 单节点启动
docker run -d --name es7 \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e ES_JAVA_OPTS="-Xms1024m -Xmx1024m" \
  elasticsearch:7.3.0
  • 9200:REST API 端口,外部调用走这个
  • 9300:集群内部节点间通信端口,单节点用不到但建议暴露
  • discovery.type=single-node:跳过主节点选举,单机开发必备
  • ES_JAVA_OPTS:设 JVM 堆内存为 1GB,建议不超过宿主机物理内存的一半

浏览器访问 http://localhost:9200,返回 JSON 格式的集群信息就说明跑起来了。

4.2 挂载配置与数据,防止容器删除数据丢失

容器一删数据就没了,必须把关键目录挂载出来:

docker cp es7:/usr/share/elasticsearch/config E:\docker\elasticsearch
docker cp es7:/usr/share/elasticsearch/data E:\docker\elasticsearch
docker cp es7:/usr/share/elasticsearch/plugins E:\docker\elasticsearch

编辑 config/elasticsearch.yml,加上跨域配置:

cluster.name: "my-es-cluster"
network.host: 0.0.0.0
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type

删掉旧容器,重新用带 -v 挂载的参数启动:

docker rm -f es7

docker run -d --name es7 \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e ES_JAVA_OPTS="-Xms1024m -Xmx1024m" \
  -v E:\docker\elasticsearch\config:/usr/share/elasticsearch/config \
  -v E:\docker\elasticsearch\data:/usr/share/elasticsearch/data \
  -v E:\docker\elasticsearch\plugins:/usr/share/elasticsearch/plugins \
  elasticsearch:7.3.0

4.3 搭上 Kibana

Kibana 是 ES 官方的可视化和分析工具,它自带的 Dev Tools 是最好的 ES 查询练习环境。版本号必须和 ES 保持一致,否则有兼容性问题:

docker pull kibana:7.3.0
docker run -d --name kibana -p 5601:5601 kibana:7.3.0

同样把配置文件复制出来,编辑 kibana.yml

server.name: kibana
server.host: "0"
elasticsearch.hosts: ["http://172.17.0.1:9200"]  # 宿主机 IP,不是 localhost
i18n.locale: "zh-CN"

注意:Kibana 在容器内访问 ES 时,localhost 指向的是容器自身,必须用宿主机的实际 IP。Windows 下通常为 172.17.0.1(用 docker inspect es7 可以确认)。

docker rm -f kibana
docker run -d --name kibana \
  -p 5601:5601 \
  -v E:\docker\kibana\config:/usr/share/kibana/config \
  kibana:7.3.0

访问 localhost:5601,看到中文界面的 Kibana 控制台就成功了。左侧导航栏找到 Dev Tools 入口,后面所有查询都在这里写。

五、IK 中文分词器:让 ES 真正认识中文

我最早用默认分词器建索引,上线后发现中文搜索效果很差——搜"美食"出来一堆不相关的结果。排查后才发现,"美食"被 standard 分词器拆成了"美"和"食"两个单字,匹配逻辑全乱了。

IK 分词器(IK Analyzer) 是专为中文设计的 Lucene 分词插件,通过内置词典识别中文词组。你可以理解为"给 ES 装了一本现代汉语词典"——它知道"美食"是一个完整的词,而不是"美"+"食"。

5.1 安装与持久化

# 进入 ES 容器
docker exec -it es7 /bin/sh

# 安装 IK(版本号与 ES 一致)
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/7.3.0

安装时提示确认,输入 y 回车。看到 -> Installed analysis-ik 就装好了。

我踩过的坑:插件安装在容器内部,容器一删就没了。安装完一定要把插件文件复制到宿主机挂载目录:

docker cp es7:/usr/share/elasticsearch/plugins/analysis-ik E:\docker\elasticsearch\plugins
docker cp es7:/usr/share/elasticsearch/config/analysis-ik E:\docker\elasticsearch\config

这样配合第四章的 -v 挂载,插件就能持久化保留了。重启后查日志确认:

docker restart es7
docker logs -f es7 2>&1 | grep analysis-ik

看到 loaded plugin [analysis-ik] 就说明插件已生效。

5.2 ik_smart vs ik_max_word

IK 提供两种模式,选择困难症友好——记住一句话:建索引用 ik_max_word(细粒度),搜索时用 ik_smart(智能分词)

模式 策略 输入"深度学习框架使用指南"的产出 适用场景
ik_smart 智能粗粒度 [深度学习, 框架, 使用指南] 搜索查询时使用
ik_max_word 最细粒度穷举 [深度学习, 深度, 学习, 框架, 使用, 指南] 建索引时使用

_analyze API 实际验证一下,左边 IK、右边 standard,差距一目了然:

# IK 智能分词
POST /_analyze
{
   
  "analyzer": "ik_smart",
  "text": "这个技术博客写得怎么样?"
}
# 结果:这 / 个 / 技术 / 博客 / 写 / 得 / 怎么样

# 默认 standard 分词
POST /_analyze
{
   
  "analyzer": "standard",
  "text": "这个技术博客写得怎么样?"
}
# 结果:这 / 个 / 技 / 术 / 博 / 客 / 写 / 得 / 怎 / 么 / 样

IK 能识别"技术""博客"等中文词组,而 standard 只会逐字拆分——这在生产环境中意味着完全不同的搜索体验。

六、ES 基础查询语法:从增删改查到聚合搜索

理论都讲完了,下面该写查询了。

6.1 结构化建索引

先建一个笔记索引,指定每个字段的分词器:

PUT /note
{
   
  "settings": {
   
    "number_of_shards": 1,
    "number_of_replicas": 1
  },
  "mappings": {
   
    "properties": {
   
      "title": {
    "type": "text", "analyzer": "ik_max_word" },
      "content": {
    "type": "text", "analyzer": "ik_max_word" },
      "create_time": {
   
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      }
    }
  }
}

Mapping(映射) 相当于 MySQL 的建表语句——定义每个字段的类型和索引方式。这里 titlecontent 都用 ik_max_word,意味着写入时会按最细粒度分词,提高搜索召回率。

插入几条测试数据:

PUT /note/_doc/1
{
    "title": "夏日旅游攻略", "content": "去海边玩耍的必备攻略,推荐三亚和青岛。", "create_time": "2024-08-16 16:49:35" }

PUT /note/_doc/2
{
    "title": "美食笔记", "content": "推荐几家成都的火锅店,真的很辣很过瘾!", "create_time": "2024-11-02 17:00:36" }

PUT /note/_doc/3
{
    "title": "秋季穿搭指南", "content": "分享适合秋天的服装搭配技巧,风衣必不可少。", "create_time": "2024-11-03 16:59:58" }

6.2 增删改查速览

几个常用操作,一张代码块看完:

# 全量更新(文档存在则覆盖,不存在则插入)
PUT /note/_doc/1
{
    "title": "更新后的标题", "content": "新内容" }

# 只更新指定字段(推荐)
POST /note/_update/1
{
    "doc": {
    "title": "只更新标题" } }

# 仅创建,已存在则报错
PUT /note/_create/4
{
    "title": "新文档", "content": "测试" }

# 删除
DELETE /note/_doc/1

# 查看单条
GET /note/_doc/2

# 搜索全部
GET /note/_search

6.3 搜索:match vs term,一个常踩的坑

全文搜索用 match——搜索词会先被分词再匹配:

GET /note/_search
{
   
  "query": {
    "match": {
    "title": "穿搭" } }
}
# "穿搭"分词后匹配 → 命中文档 3

精确匹配用 term——搜索词不经过分词,直接去索引里比对:

GET /note/_search
{
   
  "query": {
   
    "bool": {
   
      "filter": {
    "term": {
    "title": "秋季" } }
    }
  }
}

可能有人会问:用 term 搜"秋季",文档 3 标题明明包含"秋季穿搭指南",为什么一条结果都没有?

这是我在项目中真遇到过的问题。原因出在分词环节:文档入库时 title 用了 ik_max_word 分词,"秋季穿搭指南"被拆成了多个词项。但 term 查询不做分词,直接用"秋季"这个完整字符串去索引里找——索引里存的是被 IK 拆散后的词项,很可能不包含完整的"秋季"。

换成 match 就能搜到,因为 match 会先把"秋季"分词后再分别匹配索引。一句话概括:match 分词后搜索(覆盖面广),term 原样匹配(精准但可能漏)。

6.4 分页、排序、聚合

# 分页:from = (page-1) * size
GET /note/_search
{
   
  "query": {
    "match_all": {
   } },
  "from": 0, "size": 2
}

# 按发布时间倒序
GET /note/_search
{
   
  "query": {
    "match_all": {
   } },
  "sort": [{
    "create_time": {
    "order": "desc" } }]
}

# 聚合:按发布时间分组统计文档数(类似 SQL 的 GROUP BY)
GET /note/_search
{
   
  "query": {
    "match_all": {
   } },
  "aggs": {
   
    "group_by_create_time": {
   
      "terms": {
    "field": "create_time" }
    }
  }
}

补充一点:上面 term 查询用 filter 而非 must,是因为 filter 不计算相关性评分 _score,性能更好——适合"状态等于已发布""价格在 100-200 之间"这类纯过滤场景。

七、数据增量同步:怎么把 MySQL 的数据搬到 ES

生产环境中,MySQL 通常作为主存储,ES 作为搜索的从库。如何把 MySQL 的变更实时同步到 ES?业内主要两条路。

7.1 方案一:MQ 通知

MQ 同步方案架构图:业务服务写 MySQL 后发 MQ 消息 → 搜索服务消费消息 → 更新 ES 索引

业务服务在写 MySQL 的事务内,同时发一条 MQ 消息。搜索服务作为消费者监听消息,收到后更新 ES 索引。

这个方案的优势是灵活——消息体可以只携带变更字段,减少数据传输;MQ 自带持久化能力,搜索服务挂了消息不会丢。但代价是侵入性强——每个涉及搜索的业务点都要写 MQ 发送逻辑,团队大、服务多时维护成本不低。另外"数据库写成功但 MQ 发送失败"这种分布式事务问题也需要补偿机制兜底。

7.2 方案二:Canal

Canal 同步方案架构图:MySQL 产生 binlog → Canal 伪装从库订阅 binlog → 解析变更事件 → 推送至 ES

Canal 是阿里巴巴开源的一个 MySQL binlog 增量订阅中间件。它的原理很巧妙——把自己伪装成 MySQL 的从库,监听主库的 binlog,解析出 INSERT/UPDATE/DELETE 事件后推送给下游消费者。你可以理解为"给 MySQL 接了一个监听器,数据一变它就通知你"。

Canal 最大的卖点是零侵入——业务代码一行不用改,直接订阅数据库日志就行。一致性也天然优于 MQ 方案,因为数据来源就是 binlog。但代价是运维成本高(Canal Server 需要独立部署和高可用),而且它只能感知到数据库层面的变更——如果你的同步逻辑涉及 Redis 缓存或外部 API 的数据加工,Canal 就无能为力了。

7.3 选型对比

对比维度 MQ 通知方式 Canal
实时性 较高(受消费速率影响) 近乎实时
数据一致性 需要事务消息或补偿机制 与数据库强一致
业务侵入性 高,需在业务代码中埋点 零侵入
开发成本 需开发生产 + 消费两端逻辑 需开发 binlog 解析与格式转换
运维成本 中等(MQ 需高可用部署) 较高(Canal Server 需独立部署与维护)
适用场景 多数据源、复杂业务逻辑 单一 MySQL 数据源、简单同步逻辑

可能有人会问:两种方案到底怎么选?

我的建议很简单:如果你只有一个 MySQL 数据源,同步逻辑就是"MySQL 多了/改了什么,ES 就跟着改",直接上 Canal,省心。但如果数据源不止 MySQL(比如还有 MongoDB、外部 API),或者同步前需要做字段拼装、多表关联等业务加工,那就选 MQ 方案——灵活性更高。我个人两个方案都在项目里用过:早期团队小、业务简单时用 Canal 确实省了不少事;后来数据源多了、同步逻辑复杂了,才切到 MQ。所以这不是"谁更好"的问题,而是什么阶段适合什么方案。


从倒排索引原理到 Docker 部署,从分词器到查询语法,再到数据同步方案,这篇 Elasticsearch 入门教程帮你把入门的坑都踩了一遍。这些内容在实际项目中够用了——剩下的高级功能(高亮搜索、Suggest 建议器、嵌套聚合等)建议在用到的场景下查官方文档,记忆效率更高。

系列下一篇计划写 Spring Boot 如何集成 Elasticsearch,覆盖 RestHighLevelClient 和 Spring Data Elasticsearch 两种方式,感兴趣的可以关注。

参考链接


如果对你有帮助,欢迎点赞、收藏、转发。

目录
相关文章
|
2天前
|
人工智能 弹性计算 运维
|
23天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)
|
9天前
|
人工智能 缓存 安全
Claude Code 封号真实原因曝光,这次彻底不装了,直接针对国内开发者的账号下手?
Claude Code 封号潮背后:逆向扒出客户端隐写区域标记,Anthropic 政策收紧叠加 DeepSeek 7 月涨价,国产替代更紧迫。
|
14天前
|
人工智能 JSON 自然语言处理
让教学更智慧:用阿里云百炼工作流,自动生成中小学教材内容#小有可为#有温度的AI
通过可视化工作流编排,将大模型推理能力转化为标准化的教学内容生成引擎。教师只需输入教材标题和适用学段,即可自动获得结构完整、符合课程标准的章节内容,大幅降低备课门槛,助力教育资源均衡化。
501 127
|
18天前
|
存储 人工智能 监控
QoderWork完全指南:从入门到精通,把“AI实习生”变成你的全能工作搭档
阿里云2026年推出的桌面端AI工作助手QoderWork,不止聊天,更可动手干活:本地运行、安全可控,支持文件整理、数据分析、PPT生成、网页开发等;内置专家套件、多Agent协作与自定义Skills,让AI真正成为你身边的“AI实习生”。
|
7天前
|
人工智能 编解码 物联网
2026 最新Stable Diffusion 本地部署教程 下载安装使用详细图解(含官网安装包)
Stable Diffusion(SD)是2022年发布的开源文生图模型,由Stability AI等联合开发。支持文生图、图生图、局部重绘等,依托VAE降低算力需求,可在消费级显卡运行。本文提供秋葉aaaki制作的Windows整合包(含图形界面与插件),开箱即用,零配置启动。
|
9天前
|
人工智能 安全 程序员
终于,Claude Code 封号的原因被曝光了!竟然针对中国用户,植入隐形代码?!
通俗易懂地揭秘 Claude Code 封号的手段,分享一些自己对 AI 编程困境的思考,Codex、Cursor、DeepSeek、智谱 GLM、甚至是豆包,都有所行动了
497 1
|
10天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
412 125
|
17天前
|
人工智能 弹性计算 API
什么是 AlibabaCloud Agent Toolkit
Alibaba Cloud Agent Toolkit 是面向AI Agent的阿里云智能工具套件,集成OpenAPI、Terraform、CLI与文档能力,提供MCP插件、场景化Skills及执行审计机制,助AI准确查API、生成代码、规划架构、校验部署,实现安全、可靠、可追溯的云上智能运维。
438 2