ElasticsearchNotes

第 07 章:分词与文本分析

zjc 于 2026-01-07 发布

这是《Elasticsearch 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 中文搜索效果往往取决于分词。同一个查询“轻薄高性能笔记本”,不同的 Analyzer 可能产生完全不同的词项,进而影响召回和排序。

本章讲解 Analyzer 组成、内置分词器、自定义分词、中文分词、多字段分词、搜索与写入分词差异,以及分词排查方法。

7.1 什么是 Analyzer

Analyzer 是文本分析流程,负责把原始字符串转换为倒排索引用的词项。

Character Filters -> Tokenizer -> Token Filters
组件 作用 示例
Character Filter 处理原始字符 去 HTML 标签
Tokenizer 切分词元 按空格、英文单词、中文词
Token Filter 处理词元 小写、停用词、同义词、词干

输入:

Elasticsearch 搜索引擎实战

可能输出:

elasticsearch
搜索
搜索引擎
实战

7.2 _analyze API

这是排查分词最重要的工具。

POST /_analyze
{
  "analyzer": "standard",
  "text": "Elasticsearch 搜索引擎实战"
}

返回:

{
  "tokens": [
    {
      "token": "elasticsearch",
      "start_offset": 0,
      "end_offset": 13,
      "type": "<ALPHANUM>",
      "position": 0
    }
  ]
}

指定字段 Analyzer:

POST /products/_analyze
{
  "field": "title",
  "text": "轻薄高性能笔记本电脑"
}

自定义测试:

POST /_analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase"],
  "text": "Elasticsearch SEARCH Engine"
}

7.3 内置 Analyzer

Analyzer 特点
standard 默认,英文效果好,中文常按单字切
simple 按非字母切分并转小写
whitespace 按空白切分,不转小写
stop 类似 simple,并移除停用词
keyword 不分词
pattern 按正则切分
fingerprint 排序并拼接词项,适合去重

standard 测试:

POST /_analyze
{
  "analyzer": "standard",
  "text": "高性能笔记本电脑"
}

常见输出:

高
性
能
笔
记
本
电
脑

它对英文处理较好,但中文搜索会产生大量单字词项,通常需要中文分词器。

7.4 Tokenizer

Tokenizer 说明
standard Unicode 文本分词
whitespace 按空白切分
letter 按字母切分
lowercase 等价 letter + lowercase
keyword 不分词
pattern 正则切分
path_hierarchy 路径分词
edge_ngram 前缀切分

路径分词:

POST /_analyze
{
  "tokenizer": "path_hierarchy",
  "text": "/usr/local/elasticsearch"
}

输出:

/usr
/usr/local
/usr/local/elasticsearch

适合类目路径、部门路径、文件路径。

7.5 Token Filter

Filter 作用
lowercase 小写
uppercase 大写
stop 停用词
stemmer 英文词干
asciifolding 音符字符转换
trim 去首尾空白
synonym 同义词
ngram N-gram
edge_ngram 前缀 N-gram
word_delimiter 拆分复合词
unique 词项去重

示例:

POST /_analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase", "stop"],
  "text": "The Quick Brown Fox"
}

输出:

quick
brown
fox

7.6 自定义 Analyzer

在索引设置中定义:

PUT /articles
{
  "settings": {
    "analysis": {
      "filter": {
        "my_stopwords": {
          "type": "stop",
          "stopwords": ["的", "了", "和"]
        }
      },
      "analyzer": {
        "custom_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "my_stopwords"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "custom_analyzer"
      }
    }
  }
}

也可以加入 Character Filter,例如移除 HTML 标签:

"analyzer": {
  "html_analyzer": {
    "type": "custom",
    "char_filter": ["html_strip"],
    "tokenizer": "standard",
    "filter": ["lowercase"]
  }
}

注意:Analyzer 属于索引设置,修改已索引字段的 Analyzer 通常需要 Reindex。

7.7 中文分词:IK

常用模式:

Analyzer 特点
ik_max_word 尽可能多切分,召回更全
ik_smart 尽量少切分,词项更粗

写入测试:

POST /_analyze
{
  "analyzer": "ik_max_word",
  "text": "轻薄高性能笔记本电脑"
}

可能输出:

轻薄
高性能
笔记本
电脑

搜索测试:

POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "轻薄笔记本电脑"
}

常见组合:

{
  "title": {
    "type": "text",
    "analyzer": "ik_max_word",
    "search_analyzer": "ik_smart"
  }
}

思路是索引时多切分提升召回,搜索时少切分减少无关组合。具体效果必须按业务查询评估。

7.8 IK 自定义词典

安装目录下通常有配置文件:

config/analysis-ik/
 +-- IKAnalyzer.cfg.xml
 +-- main.dic
 +-- stopword.dic
 +-- custom/

添加自定义词:

程序员
云原生
高刷新率
轻薄本

添加停用词:

请问
一下
怎么样

修改后需要重启或调用插件提供的 reload API,具体能力取决于插件版本。

词表治理示例:

类型 示例 目的
业务词 轻薄本、高刷新率 避免拆错
品牌词 Elasticsearch、云原生 保持专有名词
停用词 请问、一下、怎么样 降低噪声
同义词 笔记本=笔记本电脑 扩展召回
屏蔽词 违规词 合规控制

7.9 同义词

搜索时同义词:

PUT /products
{
  "settings": {
    "analysis": {
      "filter": {
        "search_synonym": {
          "type": "synonym_graph",
          "synonyms": [
            "笔记本,笔记本电脑",
            "手机,智能手机"
          ]
        }
      },
      "analyzer": {
        "search_synonym_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": ["search_synonym"]
        }
      }
    }
  }
}

Mapping:

{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "search_synonym_analyzer"
      }
    }
  }
}

写入时同义词会增加索引体积;搜索时同义词灵活但增加查询成本。业务词表频繁变化时,通常优先使用搜索时同义词。

7.10 搜索补全

edge_ngram

适合输入前缀补全:

PUT /suggests
{
  "settings": {
    "analysis": {
      "filter": {
        "edge_ngram_filter": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 20
        }
      },
      "analyzer": {
        "edge_ngram_analyzer": {
          "tokenizer": "standard",
          "filter": ["lowercase", "edge_ngram_filter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "keyword": {
        "type": "text",
        "analyzer": "edge_ngram_analyzer",
        "search_analyzer": "standard"
      }
    }
  }
}

写入 elasticsearch 后索引:

e
el
ela
elas
...

completion suggester

PUT /suggests-completion
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion"
      }
    }
  }
}

写入:

PUT /suggests-completion/_doc/1
{
  "suggest": {
    "input": ["Elasticsearch 教程", "ES 入门"],
    "weight": 10
  }
}

查询:

GET /suggests-completion/_search
{
  "suggest": {
    "product-suggest": {
      "prefix": "elastic",
      "completion": {
        "field": "suggest"
      }
    }
  }
}

7.11 多字段分词策略

同一文本可以用不同 Analyzer 建多个子字段:

{
  "title": {
    "type": "text",
    "analyzer": "ik_max_word",
    "fields": {
      "smart": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "english": {
        "type": "text",
        "analyzer": "english"
      },
      "keyword": {
        "type": "keyword",
        "ignore_above": 128
      }
    }
  }
}

查询:

{
  "multi_match": {
    "query": "elasticsearch search",
    "fields": ["title", "title.smart", "title.english"],
    "type": "most_fields"
  }
}

适合中英混合、品牌词、缩写、拼音等场景。

7.12 拼音搜索

可使用拼音分词插件。常见三层召回:

中文原词 -> 拼音全拼 -> 拼音缩写

示例:

用户输入:bjb
候选结果:笔记本

拼音搜索要重点治理:

  1. 多音字;
  2. 拼音切分歧义;
  3. 英文品牌词;
  4. 缩写误召回;
  5. 词表更新流程。

7.13 写入分词与搜索分词

搜索前,查询文本也会被分析。

GET /products/_search
{
  "query": {
    "match": {
      "title": {
        "query": "高性能笔记本",
        "analyzer": "ik_smart"
      }
    }
  }
}

常见问题:

问题 原因
文档搜不到 写入与搜索词项不同
召回太多 分词过细
召回太少 分词过粗或词表缺失
大小写不匹配 未 lowercase
同义词无效 Analyzer 未生效或未重建
前缀搜不到 未使用 edge_ngram/completion

排查步骤:

1. _analyze 写入 Analyzer
2. _analyze 搜索 Analyzer
3. 对比词项
4. 查看 Mapping
5. 用 term query 验证词项
6. 检查词库和同义词

7.14 分词与相关性

分词结果直接影响 BM25:

  1. 词项越多,单字段匹配概率越高;
  2. 罕见词通常权重更高;
  3. 字段长度影响归一化;
  4. 多字段重复内容会提高匹配度;
  5. 停用词和同义词会改变召回。

不要只追求“能搜到”,还要观察无关结果是否变多、长标题是否被过度惩罚、品牌词是否被拆错、缩写是否有专门字段、热门词是否需要业务加权。

7.15 本章小结

7.16 思考题

  1. ik_max_wordik_smart 应如何组合使用?
  2. 为什么修改索引 Analyzer 通常需要重建索引?
  3. 写入时同义词和搜索时同义词各有什么优缺点?
  4. 用户输入“ysb”想搜“笔记本”,如何设计拼音搜索?
  5. 如果某个查询无结果,你会按什么顺序排查分词?