Elasticsearch入门实战:从倒排索引到分布式搜索

举报
yd_248750836 发表于 2026/11/04 08:59:47 2026/11/04
【摘要】 一、Elasticsearch 是什么Elasticsearch(简称 ES)是一个基于 Apache Lucene 构建的分布式搜索与数据分析引擎。它把「倒排索引」技术包装成一套可以横向扩展的服务集群,让海量数据的全文检索从几秒甚至几分钟变成毫秒级返回。在典型业务场景里,ES 主要用来做四件事:场景说明典型用法全文检索关键词模糊匹配、相关性排序商品搜索、文档搜索日志分析海量日志的聚合与筛...

一、Elasticsearch 是什么

Elasticsearch(简称 ES)是一个基于 Apache Lucene 构建的分布式搜索与数据分析引擎。它把「倒排索引」技术包装成一套可以横向扩展的服务集群,让海量数据的全文检索从几秒甚至几分钟变成毫秒级返回。

在典型业务场景里,ES 主要用来做四件事:

场景 说明 典型用法
全文检索 关键词模糊匹配、相关性排序 商品搜索、文档搜索
日志分析 海量日志的聚合与筛选 ELK / EFK 栈
数据分析 聚合统计、分组计数 运营报表、用户画像
检索增强 作为 AI 知识库的文本召回层 RAG 检索

ES 是「以文档为单位的 JSON 存储」。理解下面几个概念,基本就掌握了 ES 的一半。

1.1 索引(Index)与文档(Document)

  • 索引:一组具有相同结构的文档的集合,类似关系型数据库的表
  • 文档:索引里的最小数据单元,就是一条 JSON 数据
{
  "title": "华为云开发者成长中心使用指南",
  "tags": ["云原生", "新手教程"],
  "publish_date": "2026-11-04",
  "views": 1280
}

1.2 分片(Shard)与副本(Replica)

ES 的数据被切分成多个「分片」,每个分片都是一份完整的 Lucene 索引。分片数在索引创建之后不可更改,所以必须在建索引时就规划好。

  • 主分片(primary):负责写入和真实数据
  • 副本分片(replica):主分片的拷贝,用于高可用和读扩展
curl -X PUT "http://localhost:9200/articles" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": { "number_of_shards": 3, "number_of_replicas": 1 },
    "mappings": { "properties": { "title": { "type": "text" } } } }
  '

副本数决定了集群能容忍多少节点故障:1 个副本意味着可以挂掉 1 个节点,业务不中断。

1.3 倒排索引:ES 快的原因

传统数据库是「正向索引」:从文档找它的属性。倒排索引反过来,建立一张「词项 → 文档 ID」的映射表。

词项 出现它的文档 ID
华为云 1, 7, 23
搜索 1, 7, 42
分布式 7, 15, 42

搜索「华为云 搜索」时,ES 只需要在倒排表里查两个词项、求交集,而不用逐篇扫描文档。这就是毫秒级响应的来源。

二、五分钟快速部署

2.1 用 Docker 起一个单节点

docker run -d --name es-dev \
  -e "discovery.type=single-node" \
  -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
  -e "xpack.security.enabled=false" \
  -p 9200:9200 \
  docker.elastic.co/elasticsearch/elasticsearch:8.15.0

2.2 验证是否起来了

curl "http://localhost:9200"

返回类似这样一段 JSON:

{
  "name": "es-dev",
  "cluster_name": "docker-cluster",
  "version": { "number": "8.15.0" },
  "tagline": "You Know, for Search"
}

2.3 日常运维命令

curl "http://localhost:9200/_cat/indices?v"          # 查看所有索引
curl "http://localhost:9200/_cat/nodes?v"            # 查看节点状态
curl "http://localhost:9200/_cluster/health?pretty"  # 查看集群健康度

集群健康状态有三种:green 表示全部分片和副本都正常,yellow 表示主分片正常但副本还没分配,red 表示有主分片不可用,存在数据丢失风险。

三、数据写入与查询

3.1 写入文档

curl -X PUT "http://localhost:9200/articles/_doc/1" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Elasticsearch 入门实战",
    "tags": ["搜索", "大数据"],
    "publish_date": "2026-11-04",
    "views": 1280
  }'

写入默认是异步的,ES 返回 result: created 只代表主分片已经接收。要确保马上能搜到,可以主动刷新:

curl -X POST "http://localhost:9200/articles/_refresh"

3.2 全文检索

curl -X GET "http://localhost:9200/articles/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "multi_match": {
        "query": "搜索",
        "fields": ["title^3", "tags"]
      }
    }
  }'

multi_match 是最常用的跨字段查询写法,title^3 表示标题字段的权重是默认值的 3 倍。

3.3 组合条件:bool 查询

实际业务很少只用一个条件,bool 查询是最核心的组合器:

curl -X GET "http://localhost:9200/articles/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "bool": {
        "must": [{ "match": { "title": "搜索" } }],
        "filter": [{ "range": { "publish_date": { "gte": "2026-01-01" } } }],
        "must_not": [{ "match": { "tags": "广告" } }]
      }
    }
  }'

bool 查询四个子句的含义:

  • must —— 必须匹配,并且参与打分
  • filter —— 必须匹配,但不参与打分,性能更好
  • should —— 满足则加分,不满足不影响结果
  • must_not —— 必须不匹配

关键优化点:能用 filter 就别用 must,因为 filter 可以走缓存且不计入分,在大结果集查询上差距非常明显。

四、三个最常见的坑

坑 1:深分页把集群拖垮

{ "from": 10000, "size": 10 }

ES 需要在每个分片上取回前 10010 条数据再排序归并,from 越大内存消耗越夸张,生产环境极易被打挂。正确做法是改用 search_after 游标翻页:

{
  "size": 10,
  "search_after": [1620000000000, "art_1024"],
  "sort": [{ "publish_date": "desc" }, { "id": "asc" }]
}

坑 2:字段类型建错,ES 直接拒绝写入

动态映射会把 2026-11-04 这样的值识别成 date,把 88 识别成 long,等你想调整时只能重建索引。上线前显式声明 mapping 是最省事的做法:

{
  "mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "ik_max_word" },
      "publish_date": { "type": "date" },
      "views": { "type": "integer" }
    }
  }
}

坑 3:不分词直接做精确匹配

keyword 类型不分词,text 类型会分词。想让「华为云」被完整匹配,用 match_phrase 配合中文分词器,而不是拿 term 去查 text 字段:

{ "query": { "match_phrase": { "title": "华为云" } } }

五、总结与最佳实践

  1. 分片数提前规划:主分片创建后不可更改,按数据量反推,单分片建议控制在 20~50GB
  2. mapping 显式声明:字段类型一旦推断错误只能重建索引,别偷懒
  3. 查询用 filter 不用 must:filter 走缓存不计分,大结果集下性能差距明显
  4. 深分页改用 search_after:from + size 在百万级文档上不可用
  5. 中文检索装 IK 分词器:默认标准分词器对中文支持很弱

ES 的学习曲线不算陡,核心就三件事:倒排索引解决「查得快」,分片副本解决「扛得住」,合理的 mapping 和查询方式解决「用得对」。把这三点吃透,日常的搜索、日志分析、数据聚合需求基本都能覆盖。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。