更新时间:2026-07-07 GMT+08:00
分享

配置简繁体转换搜索

在跨地区业务场景中,用户可能会遇到使用简体中文搜索繁体中文数据,或以繁体中文搜索简体中文数据的情况,例如,输入“国际”希望召回包含“國際”的文档。然而,由于简体和繁体之间的字形差异,直接搜索会无法准确召回目标文档,导致用户体验不佳。为此,CSS服务为Elasticsearch集群预置了简繁分析插件(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 架构图

关键流程说明:

  • 索引阶段:原始数据先经char_filter(tsconvert)将繁体统一为简体,再经IK分词器(ik_smart)分词,分词结果写入倒排索引。例如原文“國際電視臺”被转换为“国际电视台”后再分词存储。
  • 查询阶段:搜索关键词同样先统一为简体再分词,与倒排索引匹配,实现简繁互搜。
  • 自定义分析器:由ik_smart粗粒度分析器与tsconvert字符过滤器组合而成,写入与查询均使用该分析器。

前提条件

  • 目标集群处于“可用”状态,无正在进行中的任务。
  • 如果自定义的简繁转换分析器依赖自定义词库,则需提前完成自定义词库配置,操作步骤请参见配置自定义词库

本文的示例代码基于Elasticsearch 7.x版本的集群,版本低于7.x的操作命令请参见示例代码(Elasticsearch版本<7.x)

登录Kibana

登录Kibana进入命令执行页面。Elasticsearch集群支持多种客户端访问,本文仅以CSS服务集成的Kibana为例介绍配置指导。

  1. 登录云搜索服务管理控制台
  2. 在左侧导航栏,选择“集群管理 > Elasticsearch”
  3. 在集群列表,选择目标集群,单击操作列的“Kibana”,登录Kibana。
  4. 在Kibana左侧导航栏选择“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

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

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

  1. 执行以下命令,创建索引test并指定自定义分析器。
    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": {
        "type1": {
          "properties": {
            "desc": {
              "type": "text",
              "analyzer": "ts_ik"
            }
          }
        }
      }
    }
  2. 执行以下命令,将测试数据写入索引test。
    POST /_bulk
    { "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
    { "desc" : "國際電視臺" }
    { "index" : { "_index" : "test", "_type" : "type1", "_id" : "2" } }
    { "desc" : "国际大城市" }
    { "index" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
    { "desc" : "联合国" }
  3. 执行以下命令,通过关键词搜索验证配置结果。
    GET /test/type1/_search
    {
      "query": {
        "match": {
          "desc": "國際"
        }
      }
    }

相关文档