Elasticsearch停用词列表变更后的数据重索引问题
问题背景与疑问
我有一个使用自定义分析器myAnalyzer的carName字段,相关定义如下:
@Field(type = FieldType.Text, searchAnalyzer = "myAnalyzer", analyzer = "myAnalyzer") private String carName;
myAnalyzer的配置为:
{ "index": { "analysis": { "filter": { "myStopwords": { "ignore_case": "true", "type": "stop", "stopwords": [ "word1", "word2" ] } }, "char_filter": { "myTrimmer": { "flags": "CASE_INSENSITIVE", "pattern": "somepatter", "replacement": "somrereplacement", "type": "pattern_replace" } }, "analyzer": { "myAnalyzer": { "filter": [ "lowercase", "unique", "myStopwords" ], "char_filter": [ "myTrimmer" ], "type": "custom", "tokenizer": "whitespace" } } } } }
现在myStopwords停用词列表会新增或删除词汇。我的数据库中有CAR实体,新增车辆时会同步索引到Elasticsearch。请问:
- 当停用词列表变更时,我需要做什么?能否仅在Elasticsearch端刷新数据,无需从数据库重新读取?
- 若停用词变更导致
carName字段的索引数据丢失,是否必须从数据库重新索引所有车辆? - 分析器在索引阶段生效,停用词列表变更属于分析器变更,似乎需要重索引车辆数据,但不确定是否正确。例如,若车辆名称为
Ford King Taurus:- 原本King不在停用词列表,后来添加进去;
- 原本King在停用词列表,后来移除;
这两种情况对搜索有何影响?变更后搜索能否正常工作?
- 了解到
UpdateByQuery方法可用于更新部分文档,能否用它来让Elasticsearch重新处理所有carName字段以适配停用词列表变更?
解答
核心结论:停用词列表变更后,必须重新处理所有已索引的文档才能让变更生效,无需从数据库重新拉取数据,用UpdateByQuery就能实现。
停用词变更后的操作要求
停用词属于分析器的索引阶段配置,已索引的文档是用旧停用词规则生成的倒排索引,所以必须重新处理这些文档才能应用新规则。不需要从数据库重新读取数据,Elasticsearch本身存储了文档的原始字段值,可直接用这些值重新生成索引。是否必须从数据库重索引?
不需要。Elasticsearch的文档中默认保存了carName的原始值(除非你手动配置了store: false),所以直接在ES内部重新处理这些原始值即可,无需回源数据库。两种停用词变更场景的影响
- 新增停用词(比如把King加入停用词):
旧索引中King是被索引的,搜索King时还能匹配到旧文档;但新索引的文档不会包含King的词条。此时搜索结果会混杂新旧规则的匹配,直到所有文档都重新处理完成。 - 移除停用词(比如把King从停用词中删掉):
旧索引中没有King的词条,搜索King时找不到旧文档;新索引的文档会包含King词条。同样,搜索结果会不一致,直到重处理完成。
这两种情况如果不重处理文档,搜索都无法完全按新规则正常工作,会出现匹配结果不符合预期的情况。
- 新增停用词(比如把King加入停用词):
UpdateByQuery的可行性
完全可以用UpdateByQuery来实现。这个API会遍历索引中的所有文档,把每个文档的原始字段值重新用新的分析器处理,生成新的倒排索引。执行命令示例:POST /your_car_index/_update_by_query { "query": { "match_all": {} } }执行时ES会自动重新解析
carName字段,应用更新后的停用词规则,不需要额外指定字段(前提是字段映射没变化,且分析器配置已经更新完成)。
注意:执行UpdateByQuery前,要先确保已经更新了索引的分析器配置(即把新的停用词列表更新到myStopwords过滤器中),否则重新处理时还是会用旧规则。
内容的提问来源于stack exchange,提问作者SereneAtk
相关产品推荐
相关产品推荐

