ES 学习(九)从文本到词元:分词器如何“拆解“你的数据

目录

    • 一、分词器工作原理
      • [1.1 Analyzer的组成结构](#1.1 Analyzer的组成结构)
      • [1.2 分词流程解析](#1.2 分词流程解析)
      • [1.3 同义词处理机制](#1.3 同义词处理机制)
      • [1.4 停用词处理机制](#1.4 停用词处理机制)
    • 二、核心分词器介绍
      • [2.1 Standard Analyzer(标准分词器)【ES内置,自0.90版本开始】](#2.1 Standard Analyzer(标准分词器)【ES内置,自0.90版本开始】)
      • [2.2 Simple Analyzer(简单分词器)【ES内置,自0.90版本开始】](#2.2 Simple Analyzer(简单分词器)【ES内置,自0.90版本开始】)
      • [2.3 Whitespace Analyzer(空白分词器)【ES内置,自0.90版本开始】](#2.3 Whitespace Analyzer(空白分词器)【ES内置,自0.90版本开始】)
      • [2.4 Keyword Analyzer(关键词分词器)【ES内置,自0.90版本开始】](#2.4 Keyword Analyzer(关键词分词器)【ES内置,自0.90版本开始】)
    • 三、中文分词器详解
      • [3.1 IK Analyzer(IK分词器)【需单独安装】](#3.1 IK Analyzer(IK分词器)【需单独安装】)
      • [3.2 SmartCN Analyzer(智能中文分词器)【ES内置,从2.0版本开始】](#3.2 SmartCN Analyzer(智能中文分词器)【ES内置,从2.0版本开始】)
      • [3.3 Jieba Analyzer(结巴分词器)【需单独安装】](#3.3 Jieba Analyzer(结巴分词器)【需单独安装】)
    • 四、高级分词技术
      • [4.1 N-gram分词](#4.1 N-gram分词)
      • [4.2 Edge N-gram分词](#4.2 Edge N-gram分词)
    • 五、分词器选择与配置
      • [5.1 选择原则](#5.1 选择原则)
      • [5.2 自定义分词器](#5.2 自定义分词器)
      • [5.3 性能优化建议](#5.3 性能优化建议)
    • 六、总结

Elasticsearch(ES)作为一款强大的分布式搜索和分析引擎,其核心功能之一是全文搜索。而分词器(Analyzer)在全文搜索中扮演着至关重要的角色。

分词器负责将原始文本分解为独立的词条(Token),以便进行索引和搜索。本文将详细介绍 ES 中 分词器的工作原理 以及 常用的分词器,帮助开发者更好地理解和应用。


一、分词器工作原理

1.1 Analyzer的组成结构

ES分词器(Analyzer)是一个文本处理流水线,由四个有序步骤组成,每个步骤都有特定的职责:

第1步:输入读取器

  • 功能:接收原始文本输入,作为整个处理流程的起点

  • 输入源:文档字段内容、查询关键词、高亮文本等

  • 编码处理:自动识别和处理不同字符编码(UTF-8、GBK等)

  • 示例:接收用户输入的"Apple iPhone 14 Pro (New)"

    第2步:字符过滤器(Character Filters)

  • 功能:在分词前对原始文本进行字符级预处理

  • 处理特点:基于规则进行字符替换、删除或转换

  • 常见类型

    • HTML Strip Filter :移除HTML/XML标签,如将"

      Hello
      "处理为"Hello"

    • Mapping Filter:字符映射替换,如全角转半角、"&"转"and"

    • Pattern Replace Filter:正则表达式替换,如统一日期格式

  • 示例:将"Apple iPhone & Samsung"处理为"Apple iPhone and Samsung"

    第3步:分词(Tokenizer)

  • 功能:将字符流分解为词条流(Token Stream),是整个分词过程的核心

  • 分词策略

    • 基于空格:按空格、标点符号切分(Standard Tokenizer)
    • 基于语言规则:考虑特定语言的词汇边界(如中文按词语切分)
    • 基于正则:使用正则表达式定义切分规则(Pattern Tokenizer)
  • 输出信息:每个词条包含文本内容、位置、偏移量、类型等元数据

  • 示例:将"Apple iPhone 14 Pro"分词为["Apple", "iPhone", "14", "Pro"]

    第4步:词元过滤器(Token Filters)

  • 功能:对分词后的词条流进行后处理,优化和标准化词条

  • 处理类型

    • 规范化:转小写(LowerCase)、移除变音符号
    • 过滤:停用词过滤(Stop)、长度过滤(Length)
    • 扩展:同义词扩展(Synonym)、词干提取(Stemmer)
    • 保护:关键字保护(Keyword Marker)
  • 执行顺序:按配置顺序依次应用多个过滤器

  • 示例:将["Apple", "iPhone", "14", "Pro"]处理为["apple", "iphone", "14", "pro"]

    完整处理流水线示例

json 复制代码
原始文本: "<p>The Quick Brown Foxes!</p>"
    ↓ [HTML Strip Filter]
"The Quick Brown Foxes!"  (移除HTML标签)
    ↓ [Standard Tokenizer]
["The", "Quick", "Brown", "Foxes"]  (按空格和标点分词)
    ↓ [LowerCase Filter]
["the", "quick", "brown", "foxes"]  (转小写)
    ↓ [StopWord Filter]
["quick", "brown", "foxes"]  (移除停用词"the")
    ↓ [Stemmer Filter]
["quick", "brown", "fox"]  (词干提取:foxes → fox)

1.2 分词流程解析

ES分词流程是双向的,确保索引和查询使用相同的处理规则:

索引阶段流程

1) 输入接收 :获取文档字段的原始文本内容

2) 字符预处理 :应用配置的Character Filters

3) 词汇切分 :Tokenizer根据规则将文本切分为词汇单元

4) 词条标准化 :应用Token Filters进行后处理

5) 索引构建:将处理后的词条写入倒排索引

查询阶段流程

1) 查询解析 :解析用户输入的查询语句

2) 查询分词 :使用与索引阶段相同的Analyzer处理查询文本

3) 词条匹配 :在倒排索引中查找匹配的词条

4) 相关性计算 :基于词条匹配度计算文档相关性

5) 结果返回:按相关性排序返回匹配的文档

一致性保证机制

  • Analyzer复用:索引和查询阶段使用相同的Analyzer配置
  • 配置同步:通过索引映射(Mapping)统一管理Analyzer配置
  • 版本控制:Analyzer配置变更时,需要重建索引以保证一致性

1.3 同义词处理机制

同义词处理是提升搜索召回率的重要功能,ES提供了多种实现方式:

Synonym Token Filter原理

  • 词典加载:启动时加载同义词词典到内存

  • 查询时扩展:将输入词条扩展为其同义词集合

  • 索引时扩展:在索引阶段就将同义词展开,提高查询性能

    同义词格式支持

  • Solr格式中国, 中华人民共和国, PR China

  • WordNet格式:基于词义关系的同义词定义

  • 显式映射i-pod, i pod => ipod(单向映射)

    性能优化策略

  • 索引时扩展:查询性能更好,但索引体积增大

  • 查询时扩展:索引体积小,但查询性能略低

  • 缓存机制:热点同义词查询结果缓存

    配置示例

json 复制代码
{
  "filter": {
    "my_synonym_filter": {
      "type": "synonym",
      "synonyms": [
        "中国, 中华人民共和国, PRC",
        "电脑, 计算机, 电子计算机"
      ],
      "expand": true,  // 是否展开所有同义词
      "lenient": false // 是否忽略同义词格式错误
    }
  }
}

1.4 停用词处理机制

停用词处理是平衡搜索精度和性能的重要机制:

停用词选择策略

  • 基于词频:高频但低信息量的词汇

  • 基于词性:介词、冠词、连词等功能词

  • 基于领域:特定领域的无意义词汇

    停用词列表管理

  • 内置列表:ES提供多种语言的默认停用词

  • 自定义列表:根据业务需求定制停用词

  • 动态更新:通过API实时更新停用词配置

    性能影响分析

  • 索引体积:移除停用词可减少30-50%的索引大小

  • 查询性能:减少词条数量,提高查询速度

  • 召回率影响:可能降低某些查询的召回率

    多语言停用词处理

json 复制代码
{
  "filter": {
    "english_stop": {
      "type": "stop",
      "stopwords": "_english_"  // 使用内置英文停用词
    },
    "chinese_stop": {
      "type": "stop",
      "stopwords": ["的", "了", "在", "是", "我", "有", "和", "就", "不", "人", "都", "一", "一个", "上", "也", "很", "到", "说", "要", "去", "你", "会", "着", "没有", "看", "好", "自己", "这"]
    }
  }
}

二、核心分词器介绍

2.1 Standard Analyzer(标准分词器)【ES内置,自0.90版本开始】

Standard Analyzer 是 ES 的默认分词器,适用于大多数语言场景。它基于Unicode文本分割算法,能够智能地识别单词边界。

核心原理

  • Unicode分词算法:基于Unicode标准附录#29(Unicode Text Segmentation)定义的词边界规则

  • 正则表达式匹配 :使用正则表达式[^\\p{L}\\p{N}]+识别非字母数字字符作为分隔符

  • 双向最大匹配:在歧义情况下,优先选择更长的匹配结果

    工作流程

    1) 字符过滤 :可选的字符过滤器预处理(如HTML标签移除)

    2) 分词 :Tokenizer根据Unicode规则将文本按词边界切分

    3) 小写转换 :Lowercase Token Filter将所有词条转换为小写形式

    4) 停用词过滤:可选的停用词过滤器移除常见无意义词汇

    使用示例

    创建索引DSL

json 复制代码
PUT /standard_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "standard"
      },
      "title": {
        "type": "text",
        "analyzer": "standard"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /standard_test/_doc/1
{
  "title": "The Quick Brown Foxes!",
  "content": "Elasticsearch 7.15.0 is a distributed search engine."
}

POST /standard_test/_doc/2
{
  "title": "Java Programming Guide",
  "content": "This guide covers Java 8 features and best practices."
}

测试查询结果

json 复制代码
GET /standard_test/_search
{
  "query": {
    "match": {
      "content": "search engine"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "standard",
  "text": "The Quick Brown Foxes!"
}
// 结果:["the", "quick", "brown", "foxes"]

适用场景

  • 通用英文文本处理
  • 多语言混合内容处理
  • 作为自定义分词器的基础模板

2.2 Simple Analyzer(简单分词器)【ES内置,自0.90版本开始】

Simple Analyzer是一个基础的分词器,其工作原理相对简单。

核心原理

  • 字母字符识别 :使用Character.isLetter()方法识别字母字符

  • 非字母分隔:所有非字母字符都被视为分隔符

  • 贪婪匹配:尽可能长地匹配连续字母序列

    工作流程

    1) 字符过滤 :移除所有非字母字符(数字、标点、符号等)

    2) 分词 :在任意非字母字符处进行切分

    3) 小写转换:统一转换为小写形式

    使用示例

    创建索引DSL

json 复制代码
PUT /simple_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "simple"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /simple_test/_doc/1
{
  "content": "Hello World! This is a test123 with numbers."
}

POST /simple_test/_doc/2
{
  "content": "Email: user@example.com, Phone: 123-456-7890"
}

测试查询结果

json 复制代码
GET /simple_test/_search
{
  "query": {
    "match": {
      "content": "hello world"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "simple",
  "text": "Hello World! This is a test123 with numbers."
}
// 结果:["hello", "world", "this", "is", "a", "test", "with", "numbers"]

适用场景

  • 纯文本内容处理
  • 需要高性能的简单分词需求
  • 预处理过的标准化文本

2.3 Whitespace Analyzer(空白分词器)【ES内置,自0.90版本开始】

Whitespace Analyzer是最简单的分词器之一,仅根据空白字符进行分词。

核心原理

  • 空白字符定义:空格、制表符(\t)、换行符(\n)、回车符(\r)等

  • 字符保留:保留所有非空白字符,包括标点符号

  • 位置敏感:严格按字符位置进行切分

    工作流程

    1) 空白分割 :仅在定义的空白字符处进行切分

    2) 无转换 :不进行大小写转换或字符过滤

    3) 原始保留:保持文本的原始格式和内容

    使用示例

    创建索引DSL

json 复制代码
PUT /whitespace_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "log_message": {
        "type": "text",
        "analyzer": "whitespace"
      },
      "tags": {
        "type": "text",
        "analyzer": "whitespace"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /whitespace_test/_doc/1
{
  "log_message": "ERROR 2023-10-01 10:00:00 Service failed",
  "tags": "error production api"
}

POST /whitespace_test/_doc/2
{
  "log_message": "INFO 2023-10-01 10:05:00 Service recovered",
  "tags": "info production api"
}

测试查询结果

json 复制代码
GET /whitespace_test/_search
{
  "query": {
    "match": {
      "tags": "production"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "whitespace",
  "text": "ERROR 2023-10-01 10:00:00 Service failed"
}
// 结果:["ERROR", "2023-10-01", "10:00:00", "Service", "failed"]

适用场景

  • 结构化日志分析
  • 已预处理的标准格式文本
  • 需要保持原始格式的标识符处理

2.4 Keyword Analyzer(关键词分词器)【ES内置,自0.90版本开始】

Keyword Analyzer是一种特殊的分词器,它将整个输入文本作为一个单独的词条处理。

核心原理

  • 整体封装:将整个输入视为不可分割的单一实体

  • 零变换:除非显式配置,否则不进行任何转换

  • 精确匹配:确保索引和查询时的一致性

    工作流程

    1) 整体保留 :将整个输入字符串作为一个词条

    2) 可选处理 :可配置字符过滤和小写转换等

    3) 边界保护:维护文本的完整性和精确性

    使用示例

    创建索引DSL

json 复制代码
PUT /keyword_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "user_id": {
        "type": "text",
        "analyzer": "keyword"
      },
      "status": {
        "type": "text",
        "analyzer": "keyword"
      },
      "category_code": {
        "type": "text",
        "analyzer": "keyword"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /keyword_test/_doc/1
{
  "user_id": "USER_001234",
  "status": "ACTIVE",
  "category_code": "CAT_ELECTRONICS"
}

POST /keyword_test/_doc/2
{
  "user_id": "USER_005678",
  "status": "INACTIVE",
  "category_code": "CAT_BOOKS"
}

测试查询结果

json 复制代码
GET /keyword_test/_search
{
  "query": {
    "term": {
      "user_id": "USER_001234"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "keyword",
  "text": "USER_001234"
}
// 结果:["USER_001234"] - 整个文本作为一个词条

适用场景

  • ID、编码等精确匹配字段
  • 聚合分析中的分组字段
  • 不需要分词的短文本字段

三、中文分词器详解

3.1 IK Analyzer(IK分词器)【需单独安装】

IK Analyzer是ES中最流行的中文分词器,由林良益开发,支持细粒度和智能分词两种模式。

核心算法

  • 双向最大匹配算法:结合正向最大匹配(FMM)和逆向最大匹配(BMM)

  • 歧义消除:通过概率模型和词典权重解决分词歧义

  • 动态词典加载:支持运行时词典更新和扩展

    词典结构

  • 核心词典:包含约27万常用中文词汇

  • 扩展词典:用户自定义词汇,支持热更新

  • 停用词典:过滤无意义词汇,提高搜索精度

    工作模式

    ik_smart模式(智能分词):

  • 算法:基于N-最短路径算法,选择最优分词路径

  • 特点:分词粒度较粗,适合搜索场景

  • 示例:"中华人民共和国" → ["中华人民共和国"]

    ik_max_word模式(细粒度分词):

  • 算法:穷尽所有可能的词汇组合

  • 特点:分词粒度最细,适合索引场景

  • 示例:"中华人民共和国" → ["中华人民共和国", "中华人民", "中华", "华人", "人民共和国", "人民", "共和国", "共和", "国"]

    使用示例

    创建索引DSL

json 复制代码
PUT /ik_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "ik_smart_analyzer": {
          "type": "ik_smart"
        },
        "ik_max_analyzer": {
          "type": "ik_max_word"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /ik_test/_doc/1
{
  "title": "中华人民共和国成立了",
  "content": "1949年10月1日,中华人民共和国在北京天安门广场正式成立。"
}

POST /ik_test/_doc/2
{
  "title": "Elasticsearch中文分词",
  "content": "IK分词器是Elasticsearch中最流行的中文分词插件。"
}

测试查询结果

json 复制代码
GET /ik_test/_search
{
  "query": {
    "match": {
      "title": "中国"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "ik_smart",
  "text": "中华人民共和国成立了"
}
// 结果:["中华人民共和国", "成立了"]

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "中华人民共和国成立了"
}
// 结果:["中华人民共和国", "中华人民", "中华", "华人", "人民共和国", "人民", "共和国", "共和", "国", "成立", "了"]

3.2 SmartCN Analyzer(智能中文分词器)【ES内置,从2.0版本开始】

SmartCN是ES官方提供的中文分词器,基于Apache Lucene的中文分词模块。

核心算法

  • 隐马尔可夫模型(HMM):基于统计模型的词性标注和分词

  • 维特比算法:动态规划求解最优分词路径

  • 最大熵模型:用于处理未登录词识别

    训练数据

  • 语料库:基于人民日报等权威语料训练

  • 标注体系:采用PKU词性标注集

  • 模型更新:定期更新以适应新词汇

    分词流程

    1) 字符预处理 :全角半角转换、数字归一化

    2) 原子切分 :基于词典的最大匹配切分

    3) HMM标注 :为每个字符分配词性标签

    4) 路径优化 :使用维特比算法求解最优路径

    5) 后处理:合并连续单字、处理特殊模式

    使用示例

    创建索引DSL

json 复制代码
PUT /smartcn_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "smartcn"
      },
      "content": {
        "type": "text",
        "analyzer": "smartcn"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /smartcn_test/_doc/1
{
  "title": "北京天气预报",
  "content": "今天北京天气晴朗,气温在20到25度之间,适合外出活动。"
}

POST /smartcn_test/_doc/2
{
  "title": "上海旅游攻略",
  "content": "上海是一座现代化大都市,有许多著名的旅游景点,如外滩、东方明珠等。"
}

测试查询结果

json 复制代码
GET /smartcn_test/_search
{
  "query": {
    "match": {
      "title": "北京"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "smartcn",
  "text": "北京天气预报"
}
// 结果:["北京", "天气", "预报"]

3.3 Jieba Analyzer(结巴分词器)【需单独安装】

Jieba分词器是基于著名的jieba分词库开发的ES插件。

核心算法

  • 基于前缀词典:使用Trie树结构存储词典,支持快速查询

  • 动态规划:基于DAG(有向无环图)寻找最优分词路径

  • HMM新词发现:使用HMM模型识别未登录词

    三种分词模式

    精确模式

  • 算法:基于词典的最大概率分词

  • 特点:精度高,适合文本分析

  • 示例:"我来到北京清华大学" → ["我", "来到", "北京", "清华大学"]

    全模式

  • 算法:扫描所有可能的词汇组合

  • 特点:速度快,可能包含冗余词汇

  • 示例:"我来到北京清华大学" → ["我", "来到", "北京", "清华", "清华大学", "华大", "大学"]

    搜索引擎模式

  • 算法:在精确模式基础上,对长词进行二次切分

  • 特点:兼顾召回率和精度,适合搜索场景

  • 示例:"我来到北京清华大学" → ["我", "来到", "北京", "清华", "华大", "大学", "清华大学"]

    使用示例

    创建索引DSL

json 复制代码
PUT /jieba_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "jieba_search_analyzer": {
          "type": "jieba_search"
        },
        "jieba_index_analyzer": {
          "type": "jieba_index"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "jieba_index",
        "search_analyzer": "jieba_search"
      },
      "content": {
        "type": "text",
        "analyzer": "jieba_index"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /jieba_test/_doc/1
{
  "title": "我来到北京清华大学",
  "content": "清华大学是中国著名的高等学府,位于北京市海淀区。"
}

POST /jieba_test/_doc/2
{
  "title": "京东商城购物指南",
  "content": "京东商城是中国领先的电商平台,提供丰富的商品选择。"
}

测试查询结果

json 复制代码
GET /jieba_test/_search
{
  "query": {
    "match": {
      "title": "清华大学"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "analyzer": "jieba_search",
  "text": "我来到北京清华大学"
}
// 结果:["我", "来到", "北京", "清华大学"]

GET /_analyze
{
  "analyzer": "jieba_index",
  "text": "我来到北京清华大学"
}
// 结果:["我", "来到", "北京", "清华", "清华大学", "华大", "大学"]

四、高级分词技术

4.1 N-gram分词

N-gram是一种基于滑动窗口的分词技术,特别适合处理部分匹配和模糊搜索。

使用示例

创建索引DSL

json 复制代码
PUT /ngram_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "ngram_analyzer": {
          "tokenizer": "ngram_tokenizer"
        }
      },
      "tokenizer": {
        "ngram_tokenizer": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 3,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "analyzer": "ngram_analyzer"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /ngram_test/_doc/1
{
  "product_name": "iPhone 13 Pro Max"
}

POST /ngram_test/_doc/2
{
  "product_name": "Samsung Galaxy S21"
}

测试查询结果

json 复制代码
GET /ngram_test/_search
{
  "query": {
    "match": {
      "product_name": "pho"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "tokenizer": "ngram_tokenizer",
  "text": "hello"
}
// 结果:["he", "el", "ll", "lo", "hel", "ell", "llo"]

4.2 Edge N-gram分词

Edge N-gram是N-gram的变种,仅从词的开头生成n-gram,适合实现自动补全功能。

使用示例

创建索引DSL

json 复制代码
PUT /autocomplete_test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "autocomplete_tokenizer",
          "filter": ["lowercase"]
        }
      },
      "tokenizer": {
        "autocomplete_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 10,
          "token_chars": ["letter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "autocomplete"
      }
    }
  }
}

插入测试数据

json 复制代码
POST /autocomplete_test/_doc/1
{
  "name": "Elasticsearch"
}

POST /autocomplete_test/_doc/2
{
  "name": "Elastic Stack"
}

POST /autocomplete_test/_doc/3
{
  "name": "Elastic Cloud"
}

测试查询结果

json 复制代码
GET /autocomplete_test/_search
{
  "query": {
    "match": {
      "name": "Ela"
    }
  }
}

// 使用_analyze API查看分词效果
GET /_analyze
{
  "tokenizer": "autocomplete_tokenizer",
  "text": "hello"
}
// 结果:["h", "he", "hel", "hell", "hello"]

性能对比

分词器类型 索引体积 查询性能 适用场景
Standard 精确搜索
N-gram 模糊搜索
Edge N-gram 自动补全

五、分词器选择与配置

5.1 选择原则

根据应用场景选择合适的分词器:

  • 通用英文文本:使用Standard Analyzer,平衡精度与性能

  • 中文内容:使用IK Analyzer,支持细粒度和智能分词模式

  • 精确匹配:使用Keyword Analyzer,保持原始文本完整性

  • 日志分析:使用Whitespace Analyzer,按空白字符简单切分

  • 自动补全:使用Edge N-gram,支持前缀匹配

  • 模糊搜索:使用N-gram,支持部分匹配和纠错

    分词器对比表

分词器 类型 适用语言 索引体积 查询性能 最佳场景 特点
Standard Analyzer ES内置 多语言 通用文本处理 Unicode分词,默认选择
Simple Analyzer ES内置 英文 纯字母文本 移除非字母字符
Whitespace Analyzer ES内置 多语言 极高 结构化数据 按空白字符切分
Keyword Analyzer ES内置 多语言 极高 精确匹配 不分词,整体处理
IK Analyzer 需单独安装 中文 中文搜索 支持细粒度和智能模式
SmartCN Analyzer ES内置 中文 中文分析 基于HMM模型
Jieba Analyzer 需单独安装 中文 中文处理 三种分词模式可选
N-gram 可配置 多语言 模糊搜索 字符级滑动窗口
Edge N-gram 可配置 多语言 自动补全 前缀匹配

5.2 自定义分词器

自定义分词器允许组合多个组件创建满足特定需求的分词器。以下是一个商品名称分词器的完整示例。

重要说明:Elasticsearch中的分词器必须属于某个索引,不能脱离索引单独存在。以下操作是先创建索引并定义分词器,但暂时不定义字段映射。

1. 单独创建自定义分词器

bash 复制代码
# 创建products索引,仅定义自定义分词器,不定义映射
PUT /products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "product_analyzer": {
          "type": "custom",
          "char_filter": ["html_strip", "brand_mapping"],
          "tokenizer": "standard",
          "filter": ["lowercase", "synonym_filter", "stop_filter"]
        }
      },
      "char_filter": {
        "brand_mapping": {
          "type": "mapping",
          "mappings": [
            "& => and",
            "i-phone => iphone",
            "mac book => macbook"
          ]
        }
      },
      "filter": {
        "synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "iphone, apple phone, 苹果手机",
            "macbook, apple laptop, 苹果笔记本",
            "galaxy, samsung phone, 三星手机"
          ]
        },
        "stop_filter": {
          "type": "stop",
          "stopwords": ["the", "a", "an", "and", "or", "in", "on", "at"]
        }
      }
    }
  }
}

2. 为索引添加字段映射(使用已定义的分词器)

bash 复制代码
# 为products索引添加字段映射,使用已定义的product_analyzer分词器
PUT /products/_mapping
{
  "properties": {
    "name": {
      "type": "text",
      "analyzer": "product_analyzer"
    },
    "brand": {
      "type": "keyword"
    },
    "price": {
      "type": "float"
    }
  }
}

2. 测试自定义分词器效果

bash 复制代码
# 测试商品名称分词效果
GET /products/_analyze
{
  "analyzer": "product_analyzer",
  "text": "Apple i-phone & Mac Book Pro 2023"
}

预期分词结果

  • 原始文本:Apple i-phone & Mac Book Pro 2023

  • 处理后:apple, iphone, and, macbook, pro, 2023

  • 同义词扩展:apple, iphone, 苹果手机, and, macbook, 苹果笔记本, pro, 2023

    3. 插入测试数据

bash 复制代码
# 插入商品数据
POST /products/_bulk
{ "index": { "_id": 1 } }
{ "name": "Apple iPhone 14 Pro Max", "brand": "Apple", "price": 999.99 }
{ "index": { "_id": 2 } }
{ "name": "Samsung Galaxy S23 Ultra", "brand": "Samsung", "price": 899.99 }
{ "index": { "_id": 3 } }
{ "name": "Apple MacBook Pro M2", "brand": "Apple", "price": 1299.99 }
{ "index": { "_id": 4 } }
{ "name": "Google Pixel 7 Pro", "brand": "Google", "price": 599.99 }
{ "index": { "_id": 5 } }
{ "name": "i-phone 13 & Accessories", "brand": "Apple", "price": 699.99 }

4. 查询测试

bash 复制代码
# 查询包含"iPhone"的商品(同义词匹配)
GET /products/_search
{
  "query": {
    "match": {
      "name": "苹果手机"
    }
  }
}

# 查询包含"MacBook"的商品
GET /products/_search
{
  "query": {
    "match": {
      "name": "苹果笔记本"
    }
  }
}

# 查看分词效果
GET /products/_search
{
  "query": {
    "match": {
      "name": "i-phone"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

5. 验证自定义分词器组件效果

bash 复制代码
# 测试HTML标签过滤
GET /products/_analyze
{
  "analyzer": "product_analyzer",
  "text": "<p>Apple & Samsung phones</p>"
}

# 测试品牌映射
GET /products/_analyze
{
  "analyzer": "product_analyzer",
  "text": "i-phone and mac book"
}

# 测试同义词扩展
GET /products/_analyze
{
  "analyzer": "product_analyzer",
  "text": "galaxy phone"
}

设计要点

  • 字符过滤器:移除HTML标签,标准化品牌名称
  • 分词器:使用标准分词器处理英文文本
  • 词元过滤器:大小写转换、同义词扩展、停用词过滤
  • 场景适配:针对商品名称特点优化分词效果

5.3 性能优化建议

索引层面的优化

分词器选择

  • 精确匹配字段:使用Keyword Analyzer,避免不必要的分词

  • 全文搜索字段:根据语言选择合适的分词器

  • 聚合字段:使用Keyword Analyzer或专门的聚合分词器

    Mapping设计

json 复制代码
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "category": {
        "type": "keyword"  // 精确匹配,无需分词
      },
      "content": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "raw": {
            "type": "keyword"  // 用于聚合和排序
          },
          "suggest": {
            "type": "completion"  // 用于自动补全
          }
        }
      }
    }
  }
}

索引设置优化

  • refresh_interval:批量索引时增大刷新间隔

  • number_of_shards:合理设置分片数,避免过多分词器实例

  • translog:调整事务日志设置,提高写入性能

    查询层面的优化

    查询类型选择

  • match查询:全文搜索,自动应用分词器

  • term查询:精确匹配,绕过分词器

  • match_phrase:短语匹配,保持词条顺序

    查询优化技巧

  • filter上下文:使用filter代替query,利用缓存

  • minimum_should_match:控制匹配精度

  • boost参数:调整字段权重,优化相关性

    监控和调试

    性能监控

  • _stats API:监控分词器性能指标

  • _analyze API:测试分词效果

  • 慢查询日志:识别性能瓶颈

    调试工具

shell 复制代码
# 测试分词效果
GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "中华人民共和国"
}
yaml 复制代码
# 查看索引的分词器配置
GET /my_index/_mapping
bash 复制代码
# 性能分析
GET /my_index/_stats

六、总结

分词器是Elasticsearch全文搜索的核心组件,其选择和配置直接影响搜索质量、系统性能和用户体验。通过深入理解不同分词器的工作原理、适用场景和性能特点,开发者可以设计出最优的分词策略。

整理完毕,完结撒花~🌻

相关推荐
lifallen2 小时前
Flink Agents:Python 执行链路与跨语言 Actor (PyFlink Agent)
java·大数据·人工智能·python·语言模型·flink
江瀚视野2 小时前
京东健康综合门诊望京开业,京东医疗路在何方?
大数据·人工智能
南無忘码至尊2 小时前
Unity学习90天-第1天-认识Unity并书写我们的第一个脚本
学习·unity·游戏引擎
2301_792674862 小时前
java学习day27(算法)
java·学习·算法
财经资讯数据_灵砚智能2 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年4月11日
大数据·人工智能·python·信息可视化·自然语言处理·ai编程
聊点儿技术2 小时前
IPv6来了,IP精准定位服务还能“准”吗?
大数据·网络·人工智能·ip·ipv4·ipv6·ip精准定位
zhangrelay2 小时前
蓝桥云课一分钟-星界战纪-Stellar Combat-make
笔记·学习
wanhengidc2 小时前
云手机搬砖安全吗
大数据·运维·服务器·安全·游戏·智能手机
淬炼之火2 小时前
笔记:对MoE混合专家模型的学习和思考
人工智能·笔记·学习·语言模型·自然语言处理