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

整理完毕,完结撒花~🌻

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
一隅论数智3 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
爱吃苹果的日记本3 天前
离散数学第六课
学习·离散数学
尧炎科技3 天前
防潮抗变形,就选纯品梅花全桉多层板
大数据
程序员大阳3 天前
副队长大数据教程(5)--集群情况下虚拟机网络配置
大数据·集群·nat·网路
自由能燃气设备3 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
科创致远3 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
嘉立创FPC苗工3 天前
FPC与机器人的双向赋能,解锁智能装备进化新势能
大数据·人工智能·制造·fpc·电路板