文章三十三:Elasticsearch 文本分词器深入实战

文本分词的概念:

文本信息通过一定的规则进行拆解,分成独立的词项,便于搜索,基于分词之后的字符去检索。

es内置分词器:

|--------------------|--------|--------|---------------------------------|------------------|---------|
| 分词器名称 | 是否ES内置 | 是否需装插件 | 核心特点 | 适用场景 | 默认分词器标记 |
| standard(标准分词器) | 是 | 否 | ES默认分词器,按单词边界切分,英文自动转小写,中文单字拆分 | 默认英文场景,不适合中文业务 | ✅ 默认分词器 |
| simple(简单分词器) | 是 | 否 | 按非字母字符切割,仅保留字母,全部转小写 | 简单英文文本过滤场景 | ❌ |
| whitespace(空格分词器) | 是 | 否 | 仅按空格字符切分,不处理标点、不转大小写 | 空格分隔的纯文本场景 | ❌ |
| stop(停用词分词器) | 是 | 否 | 在simple基础上,自动过滤英文停用词(a/an/the等) | 英文全文检索,去除无意义停用词 | ❌ |
| keyword(关键词分词器) | 是 | 否 | 完全不分词,将整段文本作为一个词条 | 精准匹配、枚举值、标签类字段 | ❌ |
| pattern(正则分词器) | 是 | 否 | 基于正则表达式自定义分词规则,灵活度高 | 有特殊分隔规则的文本场景 | ❌ |
| language(多语言分词器) | 是 | 否 | 针对英语、法语等多语言优化,无好用的中文内置分词 | 英文等拼音语言文本检索 | ❌ |
| fingerprint(指纹分词器) | 是 | 否 | 生成文本指纹,用于去重、相似度检索、内容排重 | 文本去重、版权校验、相似内容匹配 | ❌ |
| classic(经典分词器) | 是 | 否 | 老式英文分词器,兼容ES旧版本,功能与standard类似 | 兼容旧版本ES的英文场景 | ❌ |

在上面的内置分词器中可以发现,内置的分词器中没有合适的中文分词器。

深入分词器组成

分词器(Analyzer) 是全文检索的核心基石,直接决定了检索的准确率、召回率与性能。你提到的「字符过滤器、此项分析器、此项转换器」是对分词器核心组成的初步认知,存在少量笔误,本文将以官方标准定义为基础,完整解析 ES 分词器的三大核心组件字符过滤器(Character Filter)分词器(Tokenizer)词项过滤器(Token Filter),拆解各组件的职责、执行逻辑、内置实现与实战用法,帮你彻底吃透 ES 分词器的底层原理。

字符过滤器(Character Filter)

字符过滤器是分词器的前置预处理组件 ,作用于原始文本流,在文本被切分成词项之前,对单个字符进行清洗、转换、过滤、替换操作,从源头优化文本质量,为后续的分词切分做准备。

ES 内置常用字符过滤器

过滤器名称 核心功能 适用场景
html_strip 剥离 HTML 标签,保留标签内的纯文本 网页内容、富文本日志、带 HTML 标签的业务文本
mapping 自定义字符映射替换,支持批量字符替换 特殊符号清洗、全角 / 半角转换、敏感词替换
pattern_replace 基于正则表达式的字符替换 复杂规则的文本清洗、固定格式的内容过滤
lowercase 全量字符转小写(部分分词器内置,可单独配置) 英文文本统一大小写,避免大小写导致的检索差异

示例:字符过滤器的实际效果

原始文本:<p>Hello World! 我是ES用户,123456</p> 经过 html_strip 字符过滤器处理后,输出:Hello World! 我是ES用户,123456 再经过 pattern_replace 过滤器(正则过滤数字)处理后,输出:Hello World! 我是ES用户,

代码展示:

复制代码
GET _analyze
{
  "char_filter": [
    "html_strip"
  ],
  "text": [
    "<p>Hello World! 我是ES用户,123456</p>"
  ]
}

上文中为大家介绍了html的字符过滤器,下面为大家展示一下mapping的使用方式:

复制代码
GET _analyze
{
  "char_filter": [
    {
      "type": "mapping",
      "mappings": [
        "a=>1",
        "b=> 2"
      ]
    }
  ],
  "text": [
    "Ab shijian shijian"
  ]
}

分词器/切词器(Tokenizer)

整个文本分析的核心环节 :接收经过字符过滤后的文本,按照规则切割成一个个独立的词条(Token),同时记录每个词条的起始偏移、位置、类型等信息。

ES 自带多款开箱即用的 Tokenizer

ES 自带多款开箱即用的 Tokenizer,分为结构化分词、文本分词、语义分词三大类,下面逐个介绍用途、适用场景。

1. standard 标准分词器
  • 规则 :基于Unicode 文本分割算法,按单词边界切分,以空格、标点作为分割依据;
  • 特点 :默认忽略标点,适合英文、拉丁文;对中文不友好,会把每个汉字单独切成一个词;
  • 适用场景:英文文档、国际化文本、普通外文检索。
2. whitespace 空格分词器
  • 规则只按空格切割 ,遇到空格就拆分,不处理标点、不特殊过滤
  • 特点:标点会跟着单词一起保留,不做大小写转换;
  • 适用场景:固定格式标签、编码、账号、带符号的英文短句。
3. keyword 关键词分词器
  • 规则不做任何切分 ,把整个输入文本当作一个完整词条
  • 特点:原样保留内容,无拆分;
  • 适用场景:精确匹配字段,如手机号、身份证、订单号、枚举状态、分类标签、主键 ID。
4. letter 字母分词器
  • 规则 :连续字母组成一个词条,遇到非字母就切割
  • 特点:自动剔除数字、标点、特殊符号,只保留字母组合;
  • 适用场景:纯英文词汇、单词检索,不需要数字和符号参与检索的场景。
5. pattern 正则表达式分词器
  • 规则 :通过自定义正则表达式分割文本;
  • 特点:高度灵活,可以自己定义分隔符规则;
  • 适用场景:自定义分隔规则,如按逗号、下划线、横杠分割日志、结构化字符串。
6. simple 简单分词器
  • 规则:遇到非字母字符就分割,只保留连续字母;
  • 和 letter 区别:内部逻辑更轻量化,自动丢弃数字和符号,只切纯字母单词。
7. path_hierarchy 路径层级分词器
  • 规则:针对文件路径、目录层级逐层拆分;
  • 示例/usr/local/elasticsearch 拆分出:/usr/usr/local/usr/local/elasticsearch
  • 适用场景:文件路径、目录结构、分类层级、URL 路径检索。
8. ngram /edge_ngram 边缘分词器
ngram

按指定字符长度范围,滑动截取子串 ; 例:abc 长度 1~2:a、b、c、ab、bc

edge_ngram

字符串开头 固定截取前缀子串; 例:abc 长度 1~2:a、ab

  • 适用场景 :搜索框输入联想、自动补全、拼音模糊检索、短文本模糊匹配
9. uax_url_email 网址邮箱分词器
  • 规则智能识别 URL、邮箱,把完整网址、邮箱当作一个词条,不被标点拆分;
  • 适用场景:内容包含网址、邮箱地址的文章、评论、留言检索。

使用代码展示:

java 复制代码
GET _analyze
{
  "text": [
    "SHijian shi "
    ],
    "tokenizer": "standard",
    "filter": [
      "lowercase"
      ]
}

词项过滤器(Token Filter)

分词之后执行,对切分好的词条做二次加工:转小写、移除停用词、同义词替换、拼音转换、词干还原等。

下面展示了将分词之后的此项进行转化为小写

java 复制代码
GET _analyze
{
  "text": [
    "SHijian shi "
    ],
    "tokenizer": "standard",
    "filter": [
      "lowercase"
      ]
}

自定义分词器实战:

下面的案例中,展示了自定义分词器和查询的DSL:

java 复制代码
PUT /test_analyzer
{
  "settings": {
    "analysis": {
      "analyzer": {
        "study_analyzer": {
          "type": "custom",
          "char_filter": [],
          "tokenizer": "standard",
          "filter": [
            "uppercase"
            ]
        }
      }
    },
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "content":{
        "type": "text",
        "analyzer": "study_analyzer"
      }
    }
  }
}


PUT test_analyzer/_doc/1
{
  "content":"shijie nihao"
}

GET test_analyzer/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": {
              "query": "shijie"
            }
          }
        }
      ]
    }
  }
}
  • 存数据用这个分词器,查数据自动也用这一个,不用额外配置,日常开发够用。

  • 同时写 analyzer + search_analyzer

  • analyzer存索引的时候用这套分词规则

  • search_analyzer搜索查询的时候换另一套分词规则

  • 只有一种场景:入库分词 和 搜索分词 不想用一样的 ,才需要单独配 search_analyzer

在指定的索引下测试自定义的分词器

java 复制代码
POST /你的索引名/_analyze
{
  "analyzer": "你在索引里定义的分词器名称",
  "text": "要测试的文本"
}

安装和使用IK分词器:

  1. 下面展示的是使用物理主机的形式安装的es中的服务器安装Ik分词器。
  2. 在github中下载对应的版本:Index of: analysis-ik/stable/
  3. 下载之后将文件放到:/elasticsearch-8.5.2/plugins 文件中
  4. 之后执行解压缩命令:unzip elasticsearch-analysis-ik-8.5.2.zip -d ./ik
  5. 之后在重启es服务器就行了。
  6. 重启之后,使用下面的命令展示当前集群中的插件:

GET _cat/plugins?v

java 复制代码
//使用的案例
PUT ik_text
{
  "settings": {
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "content":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

PUT ik_text/_doc/1
{
  "content":"今天是周日"
}


POST _analyze
{
  "analyzer": "ik_max_word",
  "text": [
    "今天是周日,但是你为什么没有放假呢"]
}

POST _analyze
{
  "analyzer": "ik_smart",
  "text": [
    "今天是周日,但是你为什么没有放假呢"]
}

两个分词器区别(超级简单)

  • ik_max_word:拆得最细(适合存数据、检索)
  • ik_smart:拆得粗、最少(适合搜索查询)

99% 项目直接用 ik_max_word 就够了!

相关推荐
吴声子夜歌2 小时前
状态机——并行分支聚合
java·状态机·分支聚合
团象科技3 小时前
2026出海趋势观察:OpenAI开放云授权重构跨境企业增长逻辑
大数据·人工智能
optimistic_chen4 小时前
【AI Agent 全栈开发】MCP
java·linux·运维·人工智能·ai编程·mcp
2601_9577875811 小时前
全场景矩阵系统多端统一体验与跨端实时同步技术实践
大数据·人工智能·矩阵·多端统一·跨端同步
2401_8332693011 小时前
Java网络编程入门
java·开发语言
金銀銅鐵12 小时前
[Java] 如何将 Lambda 表达式对应的类保存到 class 文件中?
java·后端
面向Google编程12 小时前
从零学习Kafka:消费者组重平衡
大数据·kafka·负载均衡
それども12 小时前
Gradle 构建疑难杂症 Could not find netty-transport-native-epoll-linux-aarch_64.ja
java·服务器·gradle·maven
正儿八经的少年13 小时前
application.yml 系列配置文件作用与区别
java·配置文件