在搜索场景中,用户使用不同词语表达同一概念(例如“手机”与“智能手机”),可能导致搜索结果不全。同义词功能将这些词语视为等同,以扩展搜索范围,提升搜索召回率和用户体验。
操作前检查清单
在执行同义词文件变更前,务必确认以下事项:
确认关键索引至少拥有一个副本分片,以保障服务在单节点重启期间的可用性。(删除词典时将引起集群重启)
监控并确认集群负载处于健康水平(建议:CPU使用率 < 60%,堆内存使用率 < 50%)。
连接集群,通过
GET /_nodes/stats/jvm?filter_path=nodes.*.jvm.mem.heap_*查看所有节点的CPU和堆内存使用率。
工作原理与决策指南
理解同义词的两种配置方式及其利弊,有助于做出正确的技术选型。
同义词语法规则
同义词文件必须为 UTF-8 编码的 .txt 文件。文件中的每一行定义一组同义词规则,支持以下两种格式:
等价同义词(Solr格式)
用英文逗号分隔的词语将被视为完全等价。搜索其中任意一个词,都会匹配包含这组词中任何一个的文档。# 示例:搜索“手机”、“智能手机”或“移动电话”时,效果相同。 手机,智能手机,移动电话 ipod,i-pod,i pod定向映射(WordNet格式)
使用=>将一组词语映射到一个标准词,通常用于归一化,即将不规范的用词指向规范用词。# 示例:将"usa"和"us"都映射到“美国”。 usa,us => 美国
两种配置方式对比与决策
支持通过上传文件或在索引配置中内联定义同义词两种方式,两种方式的对比如下表所示。
对比项 | 方式一:上传文件 | 方式二:内联定义 |
操作方式 | 上传TXT文件到ES集群,然后在索引 | 直接在索引 |
优点 |
|
|
缺点 | 已有索引无法动态加载新词典。 |
|
适用场景 | 词典内容稳定、不常变更,且需要在多个索引间共享的场景。 | 对可用性要求极高,或需要频繁、快速更新同义词的场景。 |
操作步骤
方式一:通过上传文件配置(可复用)
此方式适合词典相对固定的场景。
步骤一:上传同义词文件
以下示例通过filter过滤器配置同义词,使用测试文件aliyun_synonyms.txt,其内容为:begin, start。
登录阿里云Elasticsearch控制台,选择目标地域和资源组,然后单击目标实例ID。
在左侧导航栏,选择配置与管理 > ES集群配置,在基础配置区域找到同义词配置,单击上传。
在弹出的面板中,单击配置,然后选择上传方式:
文件后缀必须是.txt,文件名包含大小写字母、数字和下划线,且长度不超过30个字符
上传文件:从本地选择同义词TXT文件。
添加OSS文件:输入Bucket名称和同义词文件名称后,单击添加。
限制:OSS Bucket必须与ES实例在同一地域。
单击保存,确认后执行。
步骤二:创建索引并引用同义词文件
等待实例状态恢复为正常,连接集群后创建索引,并配置其使用已上传的同义词文件。
PUT /aliyun-index-test
{
"settings": {
"index":{
"analysis": {
"analyzer": {
"by_smart": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": ["by_tfr","by_sfr"],
"char_filter": ["by_cfr"]
},
"by_max_word": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": ["by_tfr","by_sfr"],
"char_filter": ["by_cfr"]
}
},
"filter": {
"by_tfr": {
"type": "stop",
"stopwords": [" "]
},
"by_sfr": {
"type": "synonym",
"synonyms_path": "analysis/aliyun_synonyms.txt"
}
},
"char_filter": {
"by_cfr": {
"type": "mapping",
"mappings": ["| => |"]
}
}
}
}
}
}不同版本的集群,其索引创建语法存在一定差异,请参见ES常见版本操作索引示例。
步骤三:配置同义词字段title
ES 7.0以下版本
PUT /aliyun-index-test/_mapping/doc { "properties": { "title": { "type": "text", "analyzer": "by_max_word", "search_analyzer": "by_smart" } } }ES 7.0及以上版本
PUT /aliyun-index-test/_mapping/ { "properties": { "title": { "type": "text", "analyzer": "by_max_word", "search_analyzer": "by_smart" } } }
步骤四:验证同义词效果
使用_analyze API验证分词器是否已正确加载同义词,假设同义词文件包含 begin,start。
GET /aliyun-index-test/_analyze
{
"analyzer": "by_smart",
"text":"begin"
}成功的返回结果应同时包含 begin 和 start 两个词元(token)。
{
"tokens" : [
{
"token" : "begin",
"start_offset" : 0,
"end_offset" : 5,
"type" : "ENGLISH",
"position" : 0
},
{
"token" : "start",
"start_offset" : 0,
"end_offset" : 5,
"type" : "SYNONYM",
"position" : 0
}
]
}步骤五:测试搜索效果
写入两份包含同义词的文档
PUT /aliyun-index-test/doc/1 { "title": "Shall I begin?" }PUT /aliyun-index-test/doc/2 { "title": "I start work at nine." }搜索其中一个词(例如
begin),可同时召回包含begin和start的文档。GET /aliyun-index-test/_search { "query" : { "match" : { "title" : "begin" }}, "highlight" : { "pre_tags" : ["<red>", "<bule>"], "post_tags" : ["</red>", "</bule>"], "fields" : { "title" : {} } } }返回结果:
{ "took" : 70, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 0.28247005, "hits" : [ { "_index" : "aliyun-index-test", "_type" : "_doc", "_id" : "1", "_score" : 0.28247005, "_source" : { "title" : "Shall I begin?" }, "highlight" : { "title" : [ "Shall I <red>begin</red>?" ] } }, { "_index" : "aliyun-index-test", "_type" : "_doc", "_id" : "2", "_score" : 0.25069216, "_source" : { "title" : "I start work at nine." }, "highlight" : { "title" : [ "I <red>start</red> work at nine." ] } } ] } }
方式二:在索引设置中内联配置(不便复用)
此方式将同义词规则直接写入索引配置,适合词典小且需要快速迭代的场景。
步骤一:创建索引并定义同义词
连接集群,在创建索引时直接将同义词规则定义在synonyms数组中。
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_synonyms": {
"filter": [
"lowercase",
"my_synonym_filter"
],
"tokenizer": "ik_smart"
}
},
"filter": {
"my_synonym_filter": {
"synonyms": [
"begin,start"
],
"type": "synonym"
}
}
}
}
}上述命令创建了一个名为 my_index 的索引,并配置了自定义文本分析,处理流程为:
当文本字段使用 my_synonyms 分析器时,ik_smart 分词器将输入文本切分成词元;lowercase 过滤器将所有词元转换为小写;my_synonym_filter 过滤器将小写后的词元(如 begin 或 start)映射到其同义词组(即两者都被视为同一个规范词)。
步骤二:配置同义词字段title
ES 7.0以下版本
PUT /my_index/_mapping/doc { "properties": { "title": { "type": "text", "analyzer": "my_synonyms" } } }ES 7.0及以上版本
PUT /my_index/_mapping/ { "properties": { "title": { "type": "text", "analyzer": "my_synonyms" } } }
步骤三:验证同义词效果
GET /my_index/_analyze
{
"analyzer":"my_synonyms",
"text":"Shall I begin?"
}返回结果:
{
"tokens" : [
{
"token" : "shall",
"start_offset" : 0,
"end_offset" : 5,
"type" : "ENGLISH",
"position" : 0
},
{
"token" : "i",
"start_offset" : 6,
"end_offset" : 7,
"type" : "ENGLISH",
"position" : 1
},
{
"token" : "begin",
"start_offset" : 8,
"end_offset" : 13,
"type" : "ENGLISH",
"position" : 2
},
{
"token" : "start",
"start_offset" : 8,
"end_offset" : 13,
"type" : "SYNONYM",
"position" : 2
}
]
}删除同义词将触发集群重启
通过控制台或API删除同义词文件,将触发整个集群的滚动重启,期间集群性能可能出现短暂波动。
服务抖动:滚动重启意味着集群节点将逐一重启,即使索引配置了副本,也可能导致查询延迟短暂增加或服务抖动。
服务中断风险:在集群高负载或索引无副本的极端情况下,集群重启可能导致部分请求失败或服务短暂中断。
生效耗时:重启和词典下发的总耗时与集群规模、数据量及负载有关,可能持续数分钟甚至更长时间。