
# 配置简繁体转换搜索
在跨地区业务场景中，用户可能会遇到使用简体中文搜索繁体中文数据，或以繁体中文搜索简体中文数据的情况，例如，输入"国际"希望召回包含"國際"的文档。然而，由于简体和繁体之间的字形差异，直接搜索会无法准确召回目标文档，导致用户体验不佳。为此，CSS服务为OpenSearch集群预置了简繁分析插件（analysis-stconvert），通过在分词分析阶段自动完成简繁体的转换，用户无需修改业务数据或编写转换逻辑，只需在创建索引时配置对应的分析器，即可实现"输入简体命中繁体"或"输入繁体命中简体"的跨字形语义搜索。
#### 功能介绍
简繁分析插件（analysis-stconvert）是一款支持中文简体与繁体相互转换的插件，CSS服务默认已安装，开箱即用。其核心能力是在文本分析阶段对字符进行转换，使简体与繁体在索引层面统一，从而实现跨字形的搜索匹配。
表1支持的转换类型 
| 转换类型 | 说明                                         | 示例           |
|:---|:---|:---|
| s2t  | 简体转繁体。                                     | "手机" \> "手機" |
| t2s  | 繁体转简体。常用类型，IK分词器的词库以简体中文为主，对简体文本的分词效果优于繁体。 | "國際" \> "国际" |
   
简繁分析插件可灵活嵌入分词器的不同处理阶段，支持以下四种使用方式：
表2简繁分析插件的使用方式 
| 使用方式                | 说明                                                                                                                                                                                                                                                                                                                                                              | 适用场景                             |
|:---|:---|:---|
| char_filter（字符过滤器）  | 在分词之前对原始字符串进行转换。 - tsconvert：繁转简（t2s）  - stconvert：简转繁（s2t）   | 需要先统一字形、再分词（依赖分词器）。推荐方式，本文采用此方案。 |
| tokenizer（分词器）      | 将转换与分词合并在同一步骤完成。                                                                                                                                                                                                                                                                                                                                                | 轻量场景，不需要叠加其他分词器。                 |
| token_filter（词元过滤器） | 在分词之后对token进行转换。                                                                                                                                                                                                                                                                                                                                                | 需要先分词（依赖分词器）、再对词语进行字形统一。         |
| analyzer（分析器）       | 将插件直接作为完整的分析器使用。                                                                                                                                                                                                                                                                                                                                                | 仅需简繁转换，无需IK等中文分词能力。              |
   
#### 简繁转换的工作原理
本文采用char_filter（tsconvert）方式，将简繁转换嵌入IK分词器之前，实现字形统一。
图1架构图   
![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002629899338.png "点击放大")
关键流程说明：
- 索引阶段：原始数据先经char_filter（tsconvert）将繁体统一为简体，再经IK分词器（ik_smart）分词，分词结果写入倒排索引。例如原文"國際電視臺"被转换为"国际电视台"后再分词存储。
- 查询阶段：搜索关键词同样先统一为简体再分词，与倒排索引匹配，实现简繁互搜。
- 自定义分析器：由ik_smart粗粒度分析器与tsconvert字符过滤器组合而成，写入与查询均使用该分析器。
 
#### 前提条件
- 目标集群处于"可用"状态，无正在进行中的任务。
- 如果自定义的简繁转换分析器依赖自定义词库，则需提前完成自定义词库配置，操作步骤请参见[配置自定义词库](https://support.huaweicloud.com/usermanual-css/css_01_0313.html)。
 
#### 登录OpenSearch Dashboards
登录OpenSearch Dashboards进入命令执行页面。OpenSearch集群支持多种客户端访问，本文仅以CSS服务集成的OpenSearch Dashboards为例介绍配置指导。
1. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
2. 在左侧导航栏，选择"集群管理 \> OpenSearch"。
3. 在集群列表，选择目标集群，单击操作列的"Dashboards"，登录OpenSearch Dashboards。
4. 在OpenSearch Dashboards左侧导航栏选择"Dev Tools"，进入操作页面。 控制台左侧是命令输入框，其右侧的三角形图标为执行按钮，右侧区域则显示执行结果。
   
 
#### 创建索引
创建索引并定义包含简繁转换逻辑的自定义分析器，使索引在写入和查询时都先统一字形再分词。
执行以下命令，创建索引test并自定义分析器ts_ik（组合ik_smart和tsconvert）。
```
PUT /test
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "ts_ik": {
          "tokenizer": "ik_smart",
          "char_filter": [
            "tsconvert"
          ]
        }
      },
      "char_filter": {
        "tsconvert": {
          "type": "stconvert",
          "convert_type": "t2s"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "desc": {
        "type": "text",
        "analyzer": "ts_ik"
      }
    }
  }
}
```
表3关键参数说明 
| 参数                    | 说明                                                      |
|:---|:---|
| ts_ik                 | 自定义分析器，先经tsconvert字符过滤器将繁体统一为简体，再由ik_smart完成分词。         |
| char_filter.tsconvert | 自定义字符过滤器，类型为stconvert（简繁转换插件），convert_type: t2s表示繁体转简体。 |
| convert_type: t2s     | 繁体转简体，用于将繁体原文统一为简体，便于后续分词。IK分词器对简体中文分词更准确，因此推荐统一转为简体。   |
| analyzer: ts_ik       | 将desc字段绑定到自定义分析器，写入与查询均使用该分析器处理。                        |
   
预期结果：
```
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "test"
}
```
#### 验证分词效果
索引创建成功后，先验证自定义分析器效果再导入数据，确保简繁转换与分词配置正确。
执行以下命令，查看自定义分析器ts_ik对繁体文本的转换与分词结果。
```
POST /test/_analyze
{
  "analyzer": "ts_ik",
  "text": "國際電視臺"
}
```
预期结果：
```
{
  "tokens" : [
    { "token" : "国际", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 },
    { "token" : "电视台", "start_offset" : 2, "end_offset" : 5, "type" : "CN_WORD", "position" : 1 }
  ]
}
```
结果解读：繁体"國際電視臺"被转换为简体"国际电视台"后，ik_smart将其切分为"国际"和"电视台"，转换与分词均正常。
#### 导入数据
向索引中写入繁体或简体内容，验证简繁混合数据的搜索效果。
执行以下命令，将测试数据写入索引test。
```
POST /test/_bulk
{"index":{"_id":"1"}}
{"desc":"國際電視臺"}
{"index":{"_id":"2"}}
{"desc":"国际大城市"}
{"index":{"_id":"3"}}
{"desc":"联合国"}
```
预期结果：
```
{
  "took" : 6,
  "errors" : false,
  "items" : [
    { "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1", "_version" : 1, "result" : "created", "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 1, "status" : 201 } },
    { "index" : { "_index" : "test", "_type" : "_doc", "_id" : "2", "_version" : 1, "result" : "created", "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1, "status" : 201 } },
    { "index" : { "_index" : "test", "_type" : "_doc", "_id" : "3", "_version" : 1, "result" : "created", "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "_seq_no" : 2, "_primary_term" : 1, "status" : 201 } }
  ]
}
```
#### 验证简繁转换搜索
通过简体和繁体关键词分别搜索，验证跨字形搜索的效果。
执行以下命令，用简体关键词"国际"搜索。
```
GET /test/_search
{
  "query": {
    "match": {
      "desc": "国际"
    }
  }
}
```
执行以下命令，用繁体关键词"國際"搜索。
```
GET /test/_search
{
  "query": {
    "match": {
      "desc": "國際"
    }
  }
}
```
两次搜索的预期结果一致：
```
{
...
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.43445712,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.43445712,
        "_source" : {
          "desc" : "國際電視臺"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.43445712,
        "_source" : {
          "desc" : "国际大城市"
        }
      }
    ]
  }
}
```
结果解读：无论用简体"国际"还是繁体"國際"搜索，均能同时召回繁体文档（文档1）和简体文档（文档2），且得分一致，说明简繁转换双向生效。文档3"联合国"不包含"国际"，未被召回。
#### 常见问题
- **问题1：如何配置"简体搜索命中繁体文档"？**
  创建索引时，将tsconvert（t2s）这个char_filter替换为stconvert（s2t）即可。索引文档时简体被转为繁体存储，搜索时同样转为繁体匹配。配置如下：
  ```
  PUT /test1
  {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 0,
      "analysis": {
        "analyzer": {
          "ts_ik": {
            "tokenizer": "ik_smart",
            "char_filter": [
              "stconvert"
            ]
          }
        },
        "char_filter": {
          "stconvert": {
            "type": "stconvert",
            "convert_type": "s2t"
          }
        }
      }
    },
    "mappings": {
      "properties": {
        "desc": {
          "type": "text",
          "analyzer": "ts_ik"
        }
      }
    }
  }
  ```
  
- **问题2：已有索引的文档想补充简繁转换支持，需要重建索引吗？**
  分析器配置只能在索引创建时设定，已存在的索引无法修改分析器。是否需要重建索引取决于现有数据的情况：
  - 现有数据全部为简体，新增繁转简分析器后，不需要重建索引，因为数据本身已是简体，新增分析器后新写入的繁体数据会自动转换，历史数据无需处理。
  
  - 现有数据包含繁体数据，新增繁转简分析器后，需要重建索引，因为历史繁体数据未经转换，无法被简体关键词命中。
  
  
  重建索引的两种方式：
  - 方式一：原地更新（适用于数据量较小的场景） 执行以下命令：
    ```
    POST /{my_index}/_update_by_query
    ```
    该命令会对已有文档重新执行分析器处理，但不会改变索引的分析器配置。如果索引创建时未配置简繁转换分析器，此方式无法生效。
    
  
  - 方式二：通过索引别名（Alias）无缝切换
    1. 新建配置了简繁转换分析器的索引。
    
    2. 通过_reindex将旧索引数据迁移至新索引。
       ```
       POST /_reindex
       {
         "source": { "index": "old_index" },
         "dest": { "index": "new_index" }
       }
       ```
       
    
    3. 将别名指向新索引。
       ```
       POST /_aliases
       {
         "actions": [
           {
             "remove": {
               "index": "old_index",
               "alias": "my_alias"
             }
           },
           {
             "add": {
               "index": "new_index",
               "alias": "my_alias"
             }
           }
         ]
       }
       ```
       
    
    4. （可选）删除旧索引，释放存储空间。
       ```
       DELETE /old_index
       ```
       
     
    
 
