# 通过IK分词器与自定义词库实现精准关键词搜索
通过配置自定义主词词库和停词词库，并结合IK分词器的ik_max_word和ik_smart组合策略，使专有词语在索引与检索阶段均能被完整识别，最终实现关键词搜索精准命中率显著提升。
#### 应用场景
在电商、医疗、企业知识库等场景中，默认分词器和IK预置词库往往无法精准识别行业专有名词（如品牌名被拆散、医学术语被误切），导致搜索召回率低、精准度差。通过IK分词器结合自定义主词词库和停词词库，可让专有词语被完整保留、无意义干扰词被过滤，实现精准的关键词搜索。
典型应用：
- 电商商品搜索：避免品牌名、产品型号等专有名词被错误切分，防止搜索结果混乱。
- 医疗健康检索：确保医学术语、药品名称、疾病名称被完整识别，提升检索准确性。
- 法律文书检索：防止法律专用词语、机构名称被拆散，保障文书精准定位。
- 企业内部知识库：解决内部项目名、技术术语、人名等被默认分词器错误切分的问题。
- 内容社区运营：避免因网络流行词、热点词汇未被收录而影响内容召回效果。
 
#### 方案架构
图1架构图   
![](https://support.huaweicloud.com/bestpractice-css/figure/zh-cn_image_0000002660118979.png "点击放大")
- 索引阶段：原始数据经过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. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
2. 在左侧导航栏，根据集群类型选择"集群管理 \> Elasticsearch"或"集群管理 \> OpenSearch"。
3. 在集群列表，单击目标集群名称，进入集群详情页。
4. 选择"集群配置 \> 自定义词库"，进入自定义词库配置页面。
5. 根据业务需求配置自定义词库。
   表1配置自定义词库 
   | 参数名称    | 操作说明                                                       |
   |:---|:---|
   | OBS桶    | 选择词库文件所在的OBS桶。                                          |
   | 主词词库    | 选择"更新 \> 选择"，选择OBS桶中已上传的主词词库文件"main_custom.txt"，单击"确定"。   |
   | 停词词库 | 选择"更新 \> 选择"，选择OBS桶中已上传的停词词库文件"stop_custom.txt"，单击"确定"。 |
   | 同义词词库 | 保持默认值"不更新"，表示不配置该词库。                                     |
      
   
6. 配置完成后，单击"保存"，在弹窗中单击"确定"，启动词库更新。 下方呈现词库配置信息。等待约1分钟，词库状态从"更新中"变更为"成功"，表示词库更新完成。
   图2词库状态   
   ![](https://support.huaweicloud.com/bestpractice-css/figure/zh-cn_image_0000002629839644.png) 
 
#### 步骤三：验证分词效果
词库更新后，先验证词库分词效果再创建索引，确保词库配置正确。
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": "容灾备份"
       }
     }
   }
   ```
   
 
