词库管理

更新时间:
复制为 MD 格式

阿里云Elasticsearch Serverless(简称ES Serverless)内置IK分词、同义词、关键词过滤、词干提取等插件,支持用户上传自定义词库,实现词库的分级管理与作用域隔离,助力企业构建更精准、灵活的中文检索能力。本文介绍如何添加、使用及管理词库。

背景信息

IK分词插件用于将连续的中文句子切分为有意义的词语,其主要组成如下:

插件组成

描述

分词规则及词库类型

分词器

负责将中文文本拆分为有意义的词语(Token),决定分词粒度。

支持的分词规则如下:

  • ik_max_word:将文本按照最细粒度进行拆分,适合术语查询。例如,会将输入文本计算机汉字输入方法拆分为计算机,计算,算机,汉字输入,汉字,输入,方法

    IK分词器MAX WORD新增单字成词功能,使系统在进行中文分词时,不仅识别词语,还将组成词语的单个汉字也纳入索引。该功能显著提升短查询和模糊查询的搜索召回率,为用户提供更智能、更容错的搜索体验。通过在分词器中新增enable_single_word:true配置来开启单字成词功能,使用示例请参见下文使用ik_max_word分词器

  • ik_smart:将文本按照粗粒度进行拆分,适合短语查询。例如,会将计算机汉字输入方法拆分为计算机,汉字输入,方法

词库文件

提供词汇基础,分词器需基于词库文件进行分词。

说明

词库文件为UTF-8编码的DIC文件。要求每行一个词,换行符为\n,并且每行除首尾空格外,不允许再包含空格。

IK分词插件内置默认的主词库(main.dic)、停用词词库(stopword.dic),可直接使用。

您也可根据业务需要添加自定义词库,优化分词效果。支持添加的词库类型如下:

  • IK分词词库:提供给分词器的基础词汇知识库,分词器将基于该词库进行分词。

    若创建索引时指定了该词库,则向索引中写入数据时,应用会将该数据与词库中的词进行匹配,并将匹配到的词建立索引,该索引可通过相应的关键词被检索到。

  • IK停用词词库:通常会将一些无意义的词添加至停用词词库。例如,也、了、仍、从、以。

    说明

    可参考ES官网IK分词配置文件Config目录下的extra_stopword.dic文件。

    若创建索引时指定了该词库,则向索引中写入数据时,应用会将该数据与词库中的词进行匹配,并将匹配到的词过滤,被过滤的词不会出现在倒排索引中。

ES Serverless默认内置增强型IK分词插件,可实现词库的配置体系分级与作用域隔离。您可为不同索引或分析器配置独立的分词词库,实现精细化管理。

说明

高优先级词库配置会完全覆盖低优先级词库配置,即当多个词库对同一个词或分词规则定义不同时,以高优先级的词库配置为准。

词库级别

核心优势

作用域

优先级

分词器 (Analyzer) 级别

提供精细化控制,实现同一索引的不同字段可使用不同词库。

目标自定义分词器

最高

索引 (Index) 级别

实现业务隔离,不同索引(例如,产品库、文章库)可拥有独立的词库。

目标索引

中等

应用 (Application) 级别

提供基础词库,方便快速使用。

说明

内置词库默认为应用级别。

应用全局

最低

使用限制

  • 词库数量及大小限制:最大支持上传10个词库文件,并且所有词库文件的大小总和不超过20MB。

  • 词库格式限制:仅支持将DIC格式的文件添加为词库。

进入词库管理

  1. 进入应用详情页。

    1. 登录Elasticsearch Serverless控制台,在顶部菜单栏切换至目标地域。

    2. 在左侧导航栏单击应用管理,单击已创建的应用名称,进入应用详情页。

  2. 在左侧导航栏的搜索调优中心 > 词库管理页签,您可按需添加词库使用词库,并执行相关管理操作。

添加词库

词库管理页面单击添加自定义词库,输入词库名称,按照界面指引添加IK分词词库IK停用词词库、同义词词库。您可通过如下方式上传词库文件。

  • 通用规则:

    • 词库名称必须在当前应用内唯一,并且词库添加成功后名称不可更改。

    • 新词库添加后,仅支持对新创建的索引进行分词,存量索引不会基于该词库进行重新分词。因此,建议您对存量索引使用旧词库,而对新创建的索引使用新词库进行分词。

  • IK分词词库、IK停用词词库内容要求:

    • 要求每行一个词,换行符为\n,并且每行除首尾空格外,不允许再包含空格。若词条中间包含空格,则该词条不会生效。例如," 单词 "" 单词""单词 "为合规词条,而"单 词"为不合规词条。

    • #开头的行,视为注释处理。

  • 同义词语法规则:

    • 同义词文件必须为 UTF-8 编码的 .dic 文件。文件中的每一行定义一组同义词规则,支持以下两种格式:

      • 等价同义词(Solr格式)
        用英文逗号分隔的词语将被视为完全等价。搜索其中任意一个词,都会匹配包含这组词中任何一个的文档。

        # 示例:搜索“手机”、“智能手机”或“移动电话”时,效果相同。
        手机,智能手机,移动电话
        ipod,i-pod,i pod

        或者使用 => 将一组词语映射到一个标准词,通常用于归一化,即将不规范的用词指向规范用词。

        # 示例:将"usa"和"us"都映射到“美国”。
        usa,us => 美国
      • WordNet格式,详细信息请参见WordNet

    • 词干提取器(stemmer)

      • 作用:词干提取器是文本分析中的重要组件,其核心作用是将单词的不同形态还原为统一的词根形式。例如,"running"、"runs"和"ran"都会被提取为共同的词干"run"。这一过程显著提高了搜索系统的语义理解能力,使用户在搜索"run"时能够匹配到包含"running"或"runs"的内容。在搜索引擎和自然语言处理应用中,词干提取器有效提升了召回率,确保不同词形变体的内容能被统一检索,特别适用于英文等有丰富词形变化的语言处理场景。

      • 格式:

        running => run // 表示词干提取,在识别到前面的词后,会转义为后面的词
        jumping => jump
    • 关键词过滤器(keyword)

      • 作用:关键词过滤器是一种特殊的分析组件,其核心作用是将输入文本视为不可分割的单一关键词,避免对其进行分词处理。与常规分词器不同,它会保持原始文本的完整性,确保"New York"不会被拆分为"New"和"York",而是作为一个整体处理。这种机制在需要精确匹配的场景中至关重要,如产品ID、品牌名称、专有名词等字段的索引和搜索。在搜索引擎中,关键词过滤器确保了某些特定字段能保持其原始语义完整性,为精确查询和聚合分析提供了可靠基础。

      • 格式:

        running // 配置在词典中的词不会被过滤掉,会一直保留
        jump
    • 停用词(stopwords)

      • 作用:停用词是指在文本处理中被过滤掉的常见无意义词汇(如"the"、"a"、"and"等),这些高频词对内容区分度贡献有限。移除停用词能显著减小索引体积、提高查询效率,并使搜索结果更加精准,因为系统能更专注于具有实际语义价值的关键词。

      • 格式:

        the // 配置在词典中的词会被识别为同义词
        of
        and
        to
        a
    • 字符映射过滤器(mapping char filter)

      • 作用:字符映射过滤器在文本被分词器处理前执行字符级替换操作,通过预定义的映射规则将特定字符序列转换为目标形式。它主要用于标准化文本表示、处理特殊符号和解决语言特定字符问题,从而提升搜索质量和查询准确性。

      • 格式:

        . => 0 // 词组中 => 前面的词会被 => 后面的词替换
        > => 1
        < => 2

image

  • 从本地上传:单击image图标或通过拖拽方式上传本地文件。

  • OSS文件上传:选择目标OSS Bucket中的指定文件进行上传。

    • BucketES Serverless应用需在同一地域。

    • Bucket中的目录名称需包含es-serverless,或需为Bucket添加es-serverless: es-serverless标签,否则将导致上传失败。

      说明

      ES Serverless需根据es-serverless关键字对OSS Bucket进行服务授权,获取该OSS Bucket数据。

    • ES Serverless应用不支持自动同步更新OSS中的词库文件。若源端OSS中的词库文件内容发生变化,需通过IK词库更新操作使之生效。

配置并使用词库

词库文件上传完成后,大约需要2min生效。您可在词库生效后,进入Kibana配置并使用词库进行分词。

验证词库的有效性

您可使用POST /_analyze接口,测试添加的词库是否生效。示例代码如下。

POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "租户专用词汇测试"
}

索引级别词库配置

示例创建一个名为 products 的索引,并且该索引使用business-termsproduct-names分词词库,及stop-words停用词词库进行分词。

说明

执行该操作前,需先将相关词库添加至应用中。

PUT /products
{
  "settings": {
    "index": {
      "ik": {
        "extra_dict_ids": ["business-terms", "product-names"],
        "extra_stop_dict_ids": ["stop-words"]
      }
    }
  },
  "mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "ik_max_word" },
      "content": { "type": "text", "analyzer": "ik_smart" }
    }
  }
}
  • extra_dict_ids:表示添加的自定义IK分词词库。

  • extra_stop_dict_ids:表示添加的自定义IK停用词词库。

分析器级别词库配置

  • 方式一:通过自定义分析器(analyzer)+自定义分词器(tokenizer)方式,在分词器中配置自定义词库,扩展性强,适用于复杂业务。

    示例创建一个名为 custom_analyzer_index 的索引,并配置对my_ik_analyzer分析器使用analyzer-specific-dictspecial-terms分词词库,及analyzer-stop-words停用词词库,实现对 content 字段使用独立词库进行分词。

    说明

    执行该操作前,需先将相关词库添加至应用中。

    PUT /custom_analyzer_index
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "my_ik_analyzer": {
              "type": "custom",
              "tokenizer": "ik_tokenizer",
              "filter": ["lowercase"]
            }
          },
          "tokenizer": {
            "ik_tokenizer": {
              "type": "ik_max_word",
              "use_smart": false,
              "enable_lowercase": true,
              "extra_dict_ids": ["analyzer-specific-dict", "special-terms"],
              "extra_stop_dict_ids": ["analyzer-stop-words"]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "my_ik_analyzer"
          }
        }
      }
    }
    • extra_dict_ids:表示添加的自定义IK分词词库。

    • extra_stop_dict_ids:表示添加的自定义IK停用词词库。

  • 方式二:直接在分析器定义中配置自定义词库,简洁高效,适用于标准场景。

    创建一个名为 analyzer_level_index 的索引,并定义两个分析器,实现同一个索引中,不同字段使用独立的词库进行分词。

    说明

    执行该操作前,需先将相关词库添加至应用中。

    • product_analyzer分析器:使用product-dictbrand-names分词词库,及product-stop-words停用词词库,对product_name字段进行分词。

    • content_analyzer分析器:使用content-dicttechnical-terms分词词库,及content-stop-words停用词词库,对description字段进行分词。

    PUT /analyzer_level_index
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "product_analyzer": {
              "type": "ik_smart",
              "extra_dict_ids": ["product-dict", "brand-names"],
              "extra_stop_dict_ids": ["product-stop-words"]
            },
            "content_analyzer": {
              "type": "ik_max_word",
              "extra_dict_ids": ["content-dict", "technical-terms"],
              "extra_stop_dict_ids": ["content-stop-words"]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "product_name": {
            "type": "text",
            "analyzer": "product_analyzer"
          },
          "description": {
            "type": "text",
            "analyzer": "content_analyzer"
          }
        }
      }
    }
    • extra_dict_ids:表示添加的自定义IK分词词库。

    • extra_stop_dict_ids:表示添加的自定义IK停用词词库。

使用ik_max_word分词器

  1. Kibana中可直接执行的索引创建请求,实现IK分词器的MAX WORD模式并启用单字成词功能。

    PUT /product_index
    {
      "settings": {
        "index": {
          "number_of_shards": 1,
          "number_of_replicas": 0,
          "analysis": {
            "analyzer": {
              "my_index_analyzer": {
                "type": "ik_max_word",
                "filter": ["lowercase"],
                "enable_single_word": "true"
              },
              "my_search_analyzer": {
                "type": "ik_max_word",
                "filter": ["lowercase"],
                "enable_single_word": "true"
              }
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "my_index_analyzer",
            "search_analyzer": "my_search_analyzer",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "title": {
            "type": "text",
            "analyzer": "my_index_analyzer",
            "search_analyzer": "my_search_analyzer"
          },
          "description": {
            "type": "text",
            "analyzer": "my_index_analyzer",
            "search_analyzer": "my_search_analyzer"
          },
          "created_at": {
            "type": "date"
          }
        }
      }
    }
  2. 创建索引后,可在Kibana中执行以下命令验证单字成词功能.

    POST /product_index/_analyze
    {
      "analyzer": "my_index_analyzer",
      "text": "华为手机旗舰店"
    }

    预期分词结果将包含单字:"华"、"为"、"手"、"机"、"旗"、"舰"、"店"等,同时保留原有词语"华为"、"手机"、"旗舰店"。

    重要
    如果您的IK分词器版本较旧,enable_single_word参数可能需要替换为IK官方支持的参数。对于较新版本的IK分词器,单字成词功能已默认包含,但此配置确保了明确启用该功能。

使用同义词

以下示例通过filter过滤器配置同义词,使用测试文件aliyun-synonyms.dic,其内容为:begin, start,开始之前请先添加词库

  1. 连接集群后创建索引,并配置其使用已上传的同义词文件。

    PUT /aliyun-index-test01
    {
      "settings": {
        "analysis": {
          "filter": {
            "my_inline_synonym_filter": {
              "type": "synonym_graph",
              "synonyms_path": "aliyun-synonyms",
              "updateable": true
            }
          },
          "analyzer": {
            "my_ik_search_analyzer": {
              "type": "custom",
              "tokenizer": "ik_smart",
              "filter": ["lowercase", "my_inline_synonym_filter"]
            },
            "my_ik_index_analyzer": {
              "type": "custom",
              "tokenizer": "ik_max_word",
              "filter": ["lowercase"]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "title": {
            "type": "text",
            "analyzer": "my_ik_index_analyzer",
            "search_analyzer": "my_ik_search_analyzer",
            "term_vector": "with_positions_offsets"
          }
        }
      }
    }
  2. 验证同义词效果。

    使用_analyze API验证分词器是否已正确加载同义词,假设同义词文件包含 begin,start

    GET /aliyun-index-test01/_analyze
    {
      "analyzer": "my_ik_search_analyzer",
      "text": "start"
    }

    成功的返回结果应同时包含 begin 和 start 两个词元(token)。

    {
      "tokens": [
        {
          "token": "begin",
          "start_offset": 0,
          "end_offset": 5,
          "type": "SYNONYM",
          "position": 0
        },
        {
          "token": "start",
          "start_offset": 0,
          "end_offset": 5,
          "type": "ENGLISH",
          "position": 0
        }
      ]
    }

使用词干提取器和关键词提取器

以下示例通过filter过滤器配置词干提取器和关键词过滤器,使用测试文件my-strem.dicmy-keyword.dic,其内容如下所示,开始之前请先添加词库

my-strem.dic

running =>run
runs =>run
ran =>run

my-keyword.dic

asd_123
  1. 连接集群后创建索引,并配置其使用已上传的词干提取词库和关键词过滤词库。

    词干提取

    PUT /analysis-demo
    {
                   "settings": {
                     "analysis": {
                       "analyzer": {
                         "my_stemmer_analyzer": {
                           "tokenizer": "standard",
                           "filter": [
                             "lowercase",
                             "stemmer_filter"
                           ]
                         }
                       },
                       "filter": {
                         "stemmer_filter": {
                           "type": "stemmer_override",
                           "rules_path": "my-stemmer", // 此处配置stemmer的路径,名称同控制台上传的词典名称
                           "language": "english"
                         }
                       }
                     }
                   },
                   "mappings": {
                     "properties": {
                       "content": {
                         "type": "text",
                         "analyzer": "my_stemmer_analyzer"
                       }
                     }
                   }
                 }

    在索引中验证词干提取效果。

    POST /analysis-demo/_analyze
    {
      "analyzer": "my_stemmer_analyzer",
      "text": "I am running. He runs every day. They ran yesterday."
    }

    成功的返回结果中running、runs、ran均被替换为run:

    {
      "tokens": [
        {
          "token": "i",
          "start_offset": 0,
          "end_offset": 1,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "am",
          "start_offset": 2,
          "end_offset": 4,
          "type": "<ALPHANUM>",
          "position": 1
        },
        {
          "token": "run",
          "start_offset": 5,
          "end_offset": 12,
          "type": "<ALPHANUM>",
          "position": 2
        },
        {
          "token": "he",
          "start_offset": 14,
          "end_offset": 16,
          "type": "<ALPHANUM>",
          "position": 3
        },
        {
          "token": "run",
          "start_offset": 17,
          "end_offset": 21,
          "type": "<ALPHANUM>",
          "position": 4
        },
        {
          "token": "every",
          "start_offset": 22,
          "end_offset": 27,
          "type": "<ALPHANUM>",
          "position": 5
        },
        {
          "token": "day",
          "start_offset": 28,
          "end_offset": 31,
          "type": "<ALPHANUM>",
          "position": 6
        },
        {
          "token": "they",
          "start_offset": 33,
          "end_offset": 37,
          "type": "<ALPHANUM>",
          "position": 7
        },
        {
          "token": "run",
          "start_offset": 38,
          "end_offset": 41,
          "type": "<ALPHANUM>",
          "position": 8
        },
        {
          "token": "yesterday",
          "start_offset": 42,
          "end_offset": 51,
          "type": "<ALPHANUM>",
          "position": 9
        }
      ]
    }

    关键词过滤

    PUT /stemmer01
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "stemmer_keyword_analyzer": {
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "keyword_filter"
              ]
            }
          },
          "filter": {
            "keyword_filter": {
              "type": "keyword_marker",
              "keywords_path": "my-keyword",
              "ignore_case": true
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "stemmer_keyword_analyzer"
          }
        }
      }
    }

    在索引中验证关键词过滤效果。

    POST /stemmer01/_analyze
    {
      "text": "asd_123-and another product",
      "analyzer": "stemmer_keyword_analyzer"
    }

    成功的返回结果中asd_123作为关键词整体输出:

    {
      "tokens": [
        {
          "token": "asd_123",
          "start_offset": 0,
          "end_offset": 7,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "and",
          "start_offset": 8,
          "end_offset": 11,
          "type": "<ALPHANUM>",
          "position": 1
        },
        {
          "token": "another",
          "start_offset": 12,
          "end_offset": 19,
          "type": "<ALPHANUM>",
          "position": 2
        },
        {
          "token": "product",
          "start_offset": 20,
          "end_offset": 27,
          "type": "<ALPHANUM>",
          "position": 3
        }
      ]
    }

使用停用词

以下示例通过filter过滤器配置停用词,使用测试文件my-stop-words.dic,内容如下所示,开始之前请先添加词库

the
of
and
to
a
  1. 连接集群后创建索引,并配置其使用已上传的停用词词库。

    PUT /my-stop-words
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "standard_stop_word_analyzer": {
              "tokenizer": "standard",
              "filter": [
                "stop_word_file"
              ]
            }
          },
          "filter": {
            "stop_word_file": {
              "type": "stop",
              "stopwords_path": "my-stop-words" //名称与在控制台上传词库时输入的词库名称一致
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "standard_stop_word_analyzer"
          }
        }
      }
    }
    
  2. 在索引中验证停用词效果。

    POST /my-stop-words/_analyze
    {
      "analyzer": "standard_stop_word_analyzer",
      "text": "text to analyze"
    }

    成功的返回结果中不含to,to被定义为停用词,因此不会输出:

    {
      "tokens": [
        {
          "token": "text",
          "start_offset": 0,
          "end_offset": 4,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "analyze",
          "start_offset": 8,
          "end_offset": 15,
          "type": "<ALPHANUM>",
          "position": 2
        }
      ]
    }

使用字符映射过滤器

以下示例通过char_filter过滤器配置字符映射过滤器,使用测试文件my-mapping-char-filter.dic,其内容如下所示,开始之前先添加词库

. => 0 // 词组中 => 前面的词会被 => 后面的词替换,即.会被替换为0
> => 1
< => 2
  1. 连接集群后创建索引,并配置其使用已上传的停用词词库。

    PUT /my-mapping-char-filter
    {
                    "settings": {
                      "analysis": {
                        "analyzer": {
                          "mapping_char_word_analyzer": {
                            "tokenizer": "standard",
                            "char_filter": [
                              "mapping_char_word_filter"
                            ]
                          }
                        },
                        "char_filter": {
                          "mapping_char_word_filter": {
                            "type": "mapping",
                            "mappings_path": "my-mapping-char-filter"
                          }
                        }
                      }
                    }
                  }
    
  2. 在索引中验证字符映射过滤器效果。

    POST /my-mapping-char-filter/_analyze
    {
      "analyzer": "mapping_char_word_analyzer",
      "text": "text to analyze.><"
    }

    成功的返回结果中.><分别被替换为012

    {
      "tokens": [
        {
          "token": "text",
          "start_offset": 0,
          "end_offset": 4,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "to",
          "start_offset": 5,
          "end_offset": 7,
          "type": "<ALPHANUM>",
          "position": 1
        },
        {
          "token": "analyze012",
          "start_offset": 8,
          "end_offset": 18,
          "type": "<ALPHANUM>",
          "position": 2
        }
      ]
    }

管理词库

词库添加后,您可在词库管理页面查看词库的基本信息,或按需执行词库的下载、更新、删除等操作。image

  • 查看词库:可查看词库的类型、来源、文件大小及词条数量等信息。

  • 下载词库:可将该词库中的词库文件下载至本地。

  • 更新词库:可将业务所需的最新词库文件更新至当前词库中。

    重要
    • 词库更新过程不会导致业务中断,更新后,仅影响新写入数据的分词,存量索引不会使用新词库进行分词。由于新旧分词逻辑不一致,可能导致历史数据无法查询。

    • 如需对存量索引均采用最新词库进行分词,可执行POST /your_index/_update_by_query操作,将目标索引中的所有文档按照最新分词规则重新分词。为避免对业务产生其他影响,请在业务低峰期执行该操作。

  • 删除词库:若当前词库无需使用,可将其删除。词库删除后无法恢复,请谨慎操作。

    重要
    • 建议您非必要不删除词库,优先通过更新词库内容调整分词策略。

    • 若必须删除词库且需修复历史数据,可通过“先更新词库,再通过POST /your_index/_update_by_query更新索引文档确保数据分词一致性。

更新或删除词库影响

更新或删除词库,可能对搜索准确性及分词行为会产生如下影响:

  • 分词粒度改变

    • 新写入数据:更新或删除词库后,新索引的文档将不再使用原词库规则分词。

    • 历史数据:已索引文档的分词结果不受影响,但搜索时若使用新分词规则,可能导致召回率下降。

  • 搜索效果下降

    • 召回率降低:搜索关键词可能无法匹配到原词库定义的复合词。例如:词库删除“机器学习”后,搜索“机器学习”可能无法召回包含该术语的文档(搜索词将被拆分为“机器”、“学习”)。

    • 准确率波动:停用词库删除后,无意义的词(例如,“的”、“啊”)将重新参与搜索,会增加噪声结果。

  • 相关度评分偏移:词频(TF)、逆文档频率(IDF)等基于分词结果进行计算,词库更新或删除后可能改变评分逻辑,影响排序合理性。