如何在Elasticsearch中查找translated_body_text重复但raw_body_text不重复的文档?
如何在Elasticsearch中查找translated_body_text重复但raw_body_text不重复的文档?
嗨,这个脏数据排查的需求我之前处理过类似的,刚好可以给你一步步说怎么在Elasticsearch里实现~
首先得先解决一个核心问题:你的translated_body_text和raw_body_text是text类型,直接做聚合或者精确匹配会被分词,结果肯定不对,所以首先得用精确匹配的字段来操作——最好的方式是用text字段对应的keyword子字段(很多Elasticsearch默认mapping会自动给text字段生成.keyword的keyword子字段),如果没有的话我们再想办法。
第一步:找出所有有问题的翻译文本
先运行这个聚合查询,把your_index_name换成你的实际索引名,它会帮你找出所有「同一个翻译对应了多个不同源文本」的翻译值:
GET /your_index_name/_search { "size": 0, // 不需要返回具体文档,只看聚合结果就行 "aggs": { "group_by_translation": { "terms": { "field": "translated_body_text.keyword", // 用keyword子字段做精确分组 "min_doc_count": 2 // 只筛选出现至少两次的翻译,过滤掉唯一的正常翻译 }, "aggs": { "unique_source_count": { "cardinality": { "field": "raw_body_text.keyword" // 统计每个翻译对应的不同源文本数量 } }, "filter_bad_translations": { "bucket_selector": { "buckets_path": { "sourceCount": "unique_source_count.value" }, "script": "params.sourceCount > 1" // 只留下源文本数量大于1的桶,这些就是有问题的翻译 } } } } } }
比如你例子里的Hello, how are you?就会出现在结果里,因为它对应了两个不同的源文本。
第二步:查询对应问题文档
拿到第一步聚合出来的有问题的翻译值后,用这个查询把所有相关文档拉出来,方便你后续修复:
GET /your_index_name/_search { "query": { "terms": { "translated_body_text.keyword": [ "Hello, how are you?", // 替换成第一步拿到的有问题的翻译值 // 可以同时加多个,比如还有其他重复的翻译也放这里 ] } }, "_source": ["raw_body_text", "translated_body_text"] // 只返回需要的两个字段,减少数据传输 }
如果你的text字段没有.keyword子字段怎么办?
方案1:更新mapping添加keyword子字段(推荐,性能最优)
运行这个请求来更新索引的mapping,给两个text字段添加上对应的keyword子字段:
PUT /your_index_name/_mapping { "properties": { "translated_body_text": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 1024 // 根据你的文本长度调整,比如如果源文本很长就设大一点 } } }, "raw_body_text": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 1024 } } } } }
更新完mapping后,需要重新索引所有文档,这样新的keyword子字段才会有数据,之后就可以用上面的聚合和查询了。
方案2:用脚本聚合(应急用,性能较差)
如果暂时不能更新mapping,可以用脚本直接获取text字段的原始值来聚合,但数据量大的话性能会很糟糕,只适合小数据量临时排查:
GET /your_index_name/_search { "size": 0, "aggs": { "group_by_translation": { "terms": { "script": "doc['translated_body_text'].value", // 用脚本获取原始文本内容 "min_doc_count": 2 }, "aggs": { "unique_source_count": { "cardinality": { "script": "doc['raw_body_text'].value" } }, "filter_bad_translations": { "bucket_selector": { "buckets_path": { "sourceCount": "unique_source_count.value" }, "script": "params.sourceCount > 1" } } } } } }
一些额外注意点
- 绝对不要直接用text字段做聚合或精确匹配:text类型会自动分词,比如“Hello, how are you?”会被拆成多个独立的词,聚合出来的结果完全不是你要的「整个翻译文本重复」的情况。
- 如果你用keyword子字段,
ignore_above参数要设置得比你最长的源文本/翻译文本长,不然超过长度的文本会被忽略,聚合结果会不准。 - 数据量大的话,聚合查询可能会慢,可以考虑给keyword子字段优化索引(不过默认keyword字段是有索引的),或者调整聚合的分片参数来提速。
内容来源于stack exchange
相关产品推荐
相关产品推荐

