ElasticSearch 全文检索入门:倒排索引 + IK 分词器 + BM25 相关性算法

前言

业务搜索场景下,MySQL 的 like '%关键词%' 只适合极小体量数据,无法分词、无法相关性排序、性能低下。 Elasticsearch (简称 ES) 是目前主流开源全文搜索引擎,底层基于 Lucene。 全文检索三大核心基石:倒排索引(存储结构) + IK 分词器(中文文本切割) + BM25(相关性打分排序)。 本文从原理 → REST‑API 详解 → 实操完整案例,带你从零入门中文全文检索。

一、三大核心原理

1. 倒排索引:搜索引擎的底层基石

正向索引(传统数据库存储)

文档 ID → 文档原文内容

doc1: 春天来了,春暖花开
doc2: 春天适合踏青

查询关键词时,需要逐条扫描全部文档,数据量大查询速度极慢。

倒排索引(ES 存储结构)

词条 (Term) → 对应文档 ID 列表

春天: [doc1,doc2]
来了: [doc1]
春暖花开: [doc1]
适合: [doc2]
踏青: [doc2]

优势:搜索关键词直接根据词条定位文档,不需要全库扫描,查询速度极快。 构建倒排索引的前置条件:文本分词;中文必须借助中文分词器切割词条。

2. IK 分词器:中文搜索必备插件

ES 自带standard标准分词器,中文会被拆成单个汉字,完全无法用于词语搜索。 示例原文:春暖花开 standard 分词结果:

IK‑Analyzer 国内最流行的开源中文分词插件,提供两种分词模式:

  1. ik_max_word(索引写入阶段推荐):最细粒度拆分,穷尽所有可匹配词语
春暖花开 → 春天、春暖、春暖花开、花开
  1. ik_smart(查询搜索阶段推荐):粗粒度最少切分,无冗余词条
春暖花开 → 春暖花开

最佳实践:写入索引用 ik_max_word;查询搜索用 ik_smart IK 支持自定义扩展词典,可以添加行业新词、网络热词、专业术语。

3. BM25 相关性打分算法(ES8.x 默认评分算法)

BM25(Best‑Matching‑25)是 ES 默认相关性排序算法,用来替代老旧的 TF‑IDF,解决词频越高得分无限上涨、长文档打分不公平问题。

image

参数说明

  • (f(q_i,D)):词条在当前文档出现次数 (词频 TF)
  • IDF:逆文档频率;稀有词汇权重更高
  • (|D|):当前文档长度
  • avgdl:索引内所有文档平均长度
  • (k_1=1.2):词频饱和系数,词频达到一定程度分数不再暴涨
  • (b=0.75):文档长度惩罚系数,过长文档自动降权

BM25 核心特性:词频收益有上限,文档堆砌关键词不会拿到超高分数,搜索结果更加公平。 TF‑IDF VS BM25:TF‑IDF 词频越高得分无上限;BM25 做了饱和截断,现代搜索优先使用 BM25。

二、ES REST‑API 接口全面讲解

ES 所有操作都是基于 HTTP RESTful API,默认端口 9200,请求方式:GET/POST/PUT/DELETE

1. 分词调试接口 /_analyze

接口地址:POST http://127.0.0.1:9200/_analyze 作用:分词预览调试工具。不会创建索引,不会保存任何数据。用来测试一段文本会被分词器切成哪些词条。

开发必用!排查分词错误的第一手段。分词结果错误,生成的倒排索引就错误,后续搜索必然搜不到内容。

① 全局测试分词,不绑定索引

POST 127.0.0.1:9200/_analyze
{
  "analyzer": "ik_smart",
  "text": "春暖花开去踏青"
}
  • analyzer:指定分词器,ik_smart / ik_max_word / standard
  • text:待切割原文

返回结果重点查看tokens数组,就是切割完成的词条。

② 复用索引字段已经配置好的分词器测试

POST 127.0.0.1:9200/article/_analyze
{
  "field": "title",
  "text": "春暖花开去踏青"
}

article:索引名称;field:复用 mapping 里面 title 字段配置好的分词器。

2. 创建索引 PUT /索引名

接口地址:PUT /article 作用:新建索引,等价于 MySQL 新建数据库 + 建表。索引 = 数据库 / 数据表;文档 = 数据表的一行数据。

完整版,配置分片、映射、分词器:

PUT /article
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "title":{
        "type":"text",
        "analyzer":"ik_max_word",
        "search_analyzer":"ik_smart"
      },
      "content":{
        "type":"text",
        "analyzer":"ik_max_word",
        "search_analyzer":"ik_smart"
      }
    }
  }
}
  • analyzer:写入文档构建倒排索引时,使用 ik_max_word 细粒度分词
  • search_analyzer:用户搜索查询时,使用 ik_smart 粗粒度分词

⚠️注意:PUT 仅支持新建索引;索引一旦创建成功,不能直接修改 mapping,需要重建索引。

3. 查询索引配置 GET /索引名

GET /article 查看索引 settings、mappings 全部配置;排查字段分词器配置是否生效。

4. 删除索引 DELETE /索引名

DELETE /article 删除整个索引,文档数据、倒排索引全部清空,谨慎操作。

5. 新增单条文档 POST /索引名/_doc/[id]

POST /article/_doc/1
{
  "title":"春天踏青攻略",
  "content":"春暖花开,周末适合出门踏青游玩"
}
  • _doc:ES7 + 版本固定文档类型关键字
  • /1:自定义文档唯一 ID;省略 ID 时 ES 自动生成随机 ID

写入成功后 ES 自动执行:文本分词 → 生成词条 → 构建倒排索引。

6. 批量导入文档 POST /索引名/_bulk

POST /article/_bulk
{"index":{"_id":1}}
{"title":"春天踏青攻略","content":"春暖花开,周末适合出门踏青游玩"}
{"index":{"_id":2}}
{"title":"夏季避暑指南","content":"炎炎夏日,寻找清凉避暑胜地"}
{"index":{"_id":3}}
{"title":"春日旅游推荐","content":"春暖花开,各地迎来春游高峰期"}

高性能批量导入接口,大批量数据导入首选 bulk,效率远高于单条循环插入。

7. 根据 ID 精确查询文档 GET /article/_doc/1

GET /article/_doc/1

根据文档 id 查询原始文档内容;不属于全文检索,不走 BM25 打分,不分词搜索

8. 更新文档 POST /索引名/_update/1

POST /article/_update/1
{
  "doc":{
    "title":"新版踏青攻略"
  }
}

ES 文档更新底层逻辑:删除旧文档、新建文档,重新分词,重建倒排索引

9. 删除单条文档 DELETE /article/_doc/1

DELETE /article/_doc/1

ES 最核心搜索接口

GET /article/_search
{
  "query":{
    "match":{
      "content":"春暖花开踏青"
    }
  },
  "highlight": {
    "fields": {
      "content":{}
    }
  }
}

全文检索执行流程:

  1. 用户输入搜索关键词
  2. 使用字段配置的search_analyzer分词
  3. 查询倒排索引筛选候选文档
  4. BM25 算法自动计算相关性得分_score
  5. 按照_score 分数降序返回结果

match查询:分词后全文检索,走 BM25 打分;term查询:精确匹配、不分词,适合标签、状态、id 字段。

11. 集群运维查看接口

#查看集群健康状态
GET /_cat/health?v

#列出所有索引
GET /_cat/indices?v

ES 通用 API 端点对照表

表格

端点 功能说明
_analyze 分词调试工具
_doc 文档单条 CRUD
_bulk 高性能批量操作
_search 全文检索查询
_update 文档局部更新
_cat 集群、索引状态查询

三、完整实操步骤(ES 8.X)

⚠️前置要求:IK 分词器版本号必须和 Elasticsearch 版本完全一致

步骤 1:安装 IK 分词插件

离线安装(推荐)

  1. 下载与 ES 版本一致的 IK‑Analyzer zip 包
  2. 在 ESplugins目录新建ik文件夹,解压所有文件放入
  3. 重启 Elasticsearch 服务

在线安装示例命令

bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.15.0/elasticsearch-analysis-ik-8.15.0.zip

步骤 2:验证 IK 分词是否生效

调用_analyze接口,返回正常中文词语分词结果代表安装成功。

步骤 3:创建索引,配置 IK 分词器(参考上面 PUT /article 示例)

步骤 4:导入测试文档数据(bulk 批量插入)

步骤 5:执行全文检索查询,获取 BM25 打分搜索结果

完整开发调用顺序:

  1. PUT 创建索引 + 配置 mappings 分词器
  2. POST _analyze 调试分词效果(必做!)
  3. POST _bulk 导入文档,生成倒排索引
  4. GET _search 执行全文检索

可选:自定义 BM25 打分参数

PUT /article
{
  "settings": {
    "similarity": {
      "my_bm25": {
        "type": "BM25",
        "k1": 1.5,
        "b": 0.6
      }
    }
  },
  "mappings": {
    "properties": {
      "content":{
        "type":"text",
        "analyzer":"ik_max_word",
        "search_analyzer":"ik_smart",
        "similarity":"my_bm25"
      }
    }
  }
}

四、全文检索完整工作链路

  1. 写入文档:原始文本 → IK 分词器 (ik_max_word) 切割词条 → 构建倒排索引存储
  2. 用户搜索:搜索关键词 → IK 分词器 (ik_smart) 切割查询词条
  3. 检索匹配:词条命中倒排索引筛选候选文档集合
  4. 相关性排序:BM25 算法打分,按照相关性从高到低返回搜索结果

五、高频踩坑清单

  1. ❌坑 1:未安装 IK 分词器,中文只能单字分词,搜索不到结果
  2. ❌坑 2:创建索引忘记指定 IK 分词器;mapping 配置错误,必须重建索引才能生效
  3. ❌坑 3:IK 分词器版本与 ES 版本不一致,ES 启动失败
  4. ❌坑 4:索引写入阶段使用 ik_smart 分词;词条丢失,召回率下降,搜不到相关文档
  5. ✅最佳搭配方案:索引ik_max_word + 查询ik_smart + 默认 BM25 打分

六、进阶拓展方向

  • IK 自定义词典:IKAnalyzer.cfg.xml配置 ext_dict 扩展词库,添加行业新词
  • 混合检索:BM25 关键词召回 + 向量检索语义召回,RAG 知识库系统标配
  • 自定义打分:function_score 在 BM25 分数基础上叠加热度、时间权重
posted @ 2026-08-28 14:53  当下是吾  阅读(19)  评论(0)    收藏  举报