文档首页/ 云搜索服务 CSS/ 最佳实践/ 数据搜索与分析/ 通过IK分词器与自定义词库实现精准关键词搜索
更新时间:2026-07-07 GMT+08:00
分享

通过IK分词器与自定义词库实现精准关键词搜索

通过配置自定义主词词库和停词词库,并结合IK分词器的ik_max_word和ik_smart组合策略,使专有词语在索引与检索阶段均能被完整识别,最终实现关键词搜索精准命中率显著提升。

应用场景

在电商、医疗、企业知识库等场景中,默认分词器和IK预置词库往往无法精准识别行业专有名词(如品牌名被拆散、医学术语被误切),导致搜索召回率低、精准度差。通过IK分词器结合自定义主词词库和停词词库,可让专有词语被完整保留、无意义干扰词被过滤,实现精准的关键词搜索。

典型应用:

  • 电商商品搜索:避免品牌名、产品型号等专有名词被错误切分,防止搜索结果混乱。
  • 医疗健康检索:确保医学术语、药品名称、疾病名称被完整识别,提升检索准确性。
  • 法律文书检索:防止法律专用词语、机构名称被拆散,保障文书精准定位。
  • 企业内部知识库:解决内部项目名、技术术语、人名等被默认分词器错误切分的问题。
  • 内容社区运营:避免因网络流行词、热点词汇未被收录而影响内容召回效果。

方案架构

图1 架构图
  • 索引阶段:原始数据经过IK分词器分词。主词词库确保专有词语被完整保留,停词词库过滤无意义词语,分词结果写入倒排索引进行存储。
  • 查询阶段:搜索关键词经过IK分词器分词。分词结果与倒排索引进行匹配,召回相关文档。
  • 词库加载层:自定义词库(主词词库和停词词库)通过OBS动态加载,无需重启集群即可生效;预置词库(静态主词词库、静态停词词库、Extra主词词库和Extra停词词库)由CSS内置维护,提供常用词语的基础覆盖。
  • 组合策略:写入用细粒度分析器ik_max_word,穷举所有词组组合写入索引,确保搜索时不遗漏,提升召回率;查询用粗粒度分析器ik_smart,只取最合理的分词结果进行匹配,避免噪音干扰,提升准确性。

方案优势

  • 零中断动态更新:自定义词库通过OBS动态加载,更新词库后无需重启集群,业务完全无感知。
  • 双粒度组合策略:写入(ik_max_word)+ 查询(ik_smart)的组合模式,在召回率与精准度之间取得最佳平衡。
  • 按需裁剪:停词词库可将无意义的高频词(如“的”“是”“了”)从索引中剔除,降低索引存储体积,提升查询性能。
  • 灵活扩展:词库文件独立维护于OBS,支持随业务发展持续追加新词,运营人员即可操作,无需开发介入。

约束限制

  • 集群版本要求:2018年3月10日之前创建的集群,不支持自定义词库功能。本文的示例代码基于OpenSearch集群和Elasticsearch 7.x版本的集群,Elasticsearch集群版本低于7.x的操作命令请参见示例代码(Elasticsearch版本<7.x)
  • IK分词器主要用于中文分词,如果用于英文,仅#、&、+、-、.、@、_视为普通字符保留,其余特殊字符均作为切分点将文本切分为独立词组。

前提条件

  • 目标集群处于“可用”状态,无正在进行中的任务。
  • 确认操作账号已具备以下权限(可以在IAM服务的“权限管理 > 权限”中查看和配置):
    • 配置自定义词库的权限:
      "css:IKThesaurus:*"
    • OBS桶及对象的读取权限:
      obs:bucket:getBucketLocation
      obs:bucket:getBucketStoragePolicy
      obs:bucket:listAllMyBuckets
      obs:object:getObject
    • 如果OBS桶使用SSE-KMS加密模式时,还需KMS权限:
      "kms:cmk:create",
      "kms:dek:create",
      "kms:cmk:get",
      "kms:dek:decrypt",
      "kms:cmk:list"

步骤一:准备词库文件

准备主词词库和停词词库,并上传至OBS桶中。

  1. 准备以下两个词库文件。要求编码均为UTF-8无BOM格式,每行一词,英文小写,且文件大小不超过100MB。
    • 主词词库文件示例“main_custom.txt”
      容灾备份
      高可用
    • 停词词库文件示例“stop_custom.txt”
      以及
      可以
  2. 将准备好的词库文件上传至OBS桶。

    OBS桶必须与CSS集群位于同一区域,且“存储类别”“标准存储”

步骤二:配置自定义词库

为集群配置自定义的主词词库和停词词库,使IK分词器能识别业务专有词语并过滤干扰词。

  1. 登录云搜索服务管理控制台
  2. 在左侧导航栏,根据集群类型选择“集群管理 > Elasticsearch”“集群管理 > OpenSearch”
  3. 在集群列表,单击目标集群名称,进入集群详情页。
  4. 选择“集群配置 > 自定义词库”,进入自定义词库配置页面。
  5. 根据业务需求配置自定义词库。
    表1 配置自定义词库

    参数名称

    操作说明

    OBS桶

    选择词库文件所在的OBS桶。

    主词词库

    选择“更新 > 选择”,选择OBS桶中已上传的主词词库文件“main_custom.txt”,单击“确定”

    停词词库

    选择“更新 > 选择”,选择OBS桶中已上传的停词词库文件“stop_custom.txt”,单击“确定”

    同义词词库

    保持默认值“不更新”,表示不配置该词库。

  6. 配置完成后,单击“保存”,在弹窗中单击“确定”,启动词库更新。

    下方呈现词库配置信息。等待约1分钟,词库状态从“更新中”变更为“成功”,表示词库更新完成。

    图2 词库状态

步骤三:验证分词效果

词库更新后,先验证词库分词效果再创建索引,确保词库配置正确。
  1. 在自定义词库页面,单击页面右上角的“Kibana”“Dashboards”
  2. 在Kibana或Dashboards左侧导航栏选择“Dev Tools”,进入操作页面。
  3. 执行以下命令,查看ik_smart的分词效果。
    GET /_analyze
    {
      "analyzer": "ik_smart",
      "text": "容灾备份以及冗余架构可以保障系统高可用运行"
    }

    预期结果:

    {
      "tokens" : [
        { "token" : "容灾备份", "start_offset" : 0, "end_offset" : 4, "type" : "CN_WORD", "position" : 0 },
        { "token" : "冗余", "start_offset" : 6, "end_offset" : 8, "type" : "CN_WORD", "position" : 1 },
        { "token" : "架构", "start_offset" : 8, "end_offset" : 10, "type" : "CN_WORD", "position" : 2 },
        { "token" : "保障系统", "start_offset" : 12, "end_offset" : 16, "type" : "CN_WORD", "position" : 3 },
        { "token" : "高可用", "start_offset" : 16, "end_offset" : 19, "type" : "CN_WORD", "position" : 4 },
        { "token" : "运行", "start_offset" : 19, "end_offset" : 21, "type" : "CN_WORD", "position" : 5 }
      ]
    }

    结果解读:“容灾备份”“高可用”被识别为独立词,“以及”“可以”作为停词被过滤,说明词库配置生效。

步骤四:创建索引

创建索引并指定写入和查询时使用的IK分词器,实现双粒度组合策略。

执行以下命令,创建索引book,写入时使用ik_max_word分析器,查询时使用ik_smart分析器。

PUT /book
{
    "settings": {
        "number_of_shards": 2,
        "number_of_replicas": 1
    },
    "mappings": {
        "properties": {
            "content": {
                "type": "text",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_smart"
            }
        }
    }
}

预期结果:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "book"
}

步骤五:写入测试数据

写入测试数据,用于验证关键词检索效果。

执行以下命令,将测试文本写入索引book。

POST /book/_bulk
{"index":{"_id":"1"}}
{"content":"容灾备份以及冗余架构可以保障系统高可用运行"}
{"index":{"_id":"2"}}
{"content":"容灾方案成本高"}
{"index":{"_id":"3"}}
{"content":"企业从架构层面推进数据备份的落地改造"}

预期结果:

{
  "took" : 5,
  "errors" : false,
  "items" : [
    { "index" : { "_index" : "book", "_type" : "_doc", "_id" : "1", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 1, "status" : 201 } },
    { "index" : { "_index" : "book", "_type" : "_doc", "_id" : "2", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1, "status" : 201 } },
    { "index" : { "_index" : "book", "_type" : "_doc", "_id" : "3", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 2, "_primary_term" : 1, "status" : 201 } }
  ]
}

步骤六:执行关键词搜索

通过关键词搜索验证自定义词库的配置效果。

  1. 执行以下命令,搜索主词“容灾备份”
    GET /book/_search
    {
      "query": {
        "match": {
          "content": "容灾备份"
        }
      }
    }

    预期结果:

    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 0.89470756,
        "hits" : [
          {
            "_index" : "book",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 0.89470756,
            "_source" : {
              "content" : "容灾备份以及冗余架构可以保障系统高可用运行"
            }
          }
        ]
      }
    }

    结果解读:因为主词词库中包含“容灾备份”,仅文档1被召回。

    • 文档1在写入时ik_max_word将“容灾备份”作为完整词条保留在倒排索引中,搜索时ik_smart也将其识别为独立词,精准匹配。
    • 文档2原文为“容灾方案”,ik_max_word切分出“容灾”但不含完整的“容灾备份”;文档3原文为“数据备份”,切分出“备份”但不含“容灾备份”,因此均无法召回。
  2. 执行以下命令,搜索停词“可以”
    GET /book/_search
    {
      "query": {
        "match": {
          "content": "可以"
        }
      }
    }

    预期结果:

    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 2,
        "successful" : 2,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 0,
          "relation" : "eq"
        },
        "max_score" : null,
        "hits" : [ ]
      }
    }

    结果解读:停词“可以”在数据写入时被IK分词器过滤,未进入倒排索引,因此搜索时无结果返回,说明停词词库生效。

示例代码(Elasticsearch版本<7.x)

当Elasticsearch集群版本低于7.x时,需要自定义type名称,参考以下命令。

  1. 执行以下命令,创建索引book并指定IK分词器。
    PUT /book
    {
        "settings": {
            "number_of_shards": 2,
            "number_of_replicas": 1
        },
        "mappings": {
            "type1": {
                "properties": {
                    "content": {
                        "type": "text",
                        "analyzer": "ik_max_word",
                        "search_analyzer": "ik_smart"
                    }
                }
            }
        }
    }
  2. 执行以下命令,将测试数据写入索引book。
    POST /_bulk
    { "index" : { "_index" : "book", "_type" : "type1", "_id" : "1" } }
    { "content" : "容灾备份以及冗余架构可以保障系统高可用运行" }
    { "index" : { "_index" : "book", "_type" : "type1", "_id" : "2" } }
    { "content" : "容灾方案成本高" }
    { "index" : { "_index" : "book", "_type" : "type1", "_id" : "3" } }
    { "content" : "企业从架构层面推进数据备份的落地改造" }
  3. 执行以下命令,通过关键词搜索验证配置结果。
    GET /book/type1/_search
    {
      "query": {
        "match": {
          "content": "容灾备份"
        }
      }
    }

相关文档