Elasticsearch中text类型邮箱字段为何无法搜索域名部分
问题原因
出现这个问题是Elasticsearch默认text类型的分词规则和搜索预期不匹配导致的:
默认分词器处理test@gmail.com这类邮箱字符串时,会将@作为分割点拆分,但会把@后面的完整域名(比如gmail.com)识别为独立的主机名整体,不会按.继续拆分,最终写入倒排索引的分词term只有两个:test、gmail.com。
这和实际遇到的现象完全对应:
- 搜索
test时,搜索词分词后得到termtest,和索引中存储的term完全匹配,因此可以返回结果 - 搜索完整邮箱
test@gmail.com时,搜索词会被拆分为test、gmail.com两个term,都能和索引中的term匹配,因此可以返回结果 - 搜索
gmail时,搜索词分词后得到termgmail,但索引中只有gmail.com这个完整term,不存在单独的gmailterm,因此无法匹配到任何结果。
解决方案
如果需要支持搜索域名的任意片段(比如gmail、com都能命中对应邮箱),可以通过调整字段的分词规则实现,以下是两种常用方案:
- 方案1:自定义分词器,将
@、.都作为分词分隔符
通过自定义分析器,用字符过滤器把邮箱里的@、.替换为空格,再交给standard分词器处理,test@gmail.com会被拆分为test、gmail、com三个独立term,任意部分搜索都能命中。索引配置示例如下:
注意:分词器配置修改后需要重建索引,重新导入全量历史数据才能生效。PUT transaction-green { "settings": { "analysis": { "analyzer": { "email_analyzer": { "type": "custom", "char_filter": ["email_char_filter"], "tokenizer": "standard", "filter": ["lowercase"] } }, "char_filter": { "email_char_filter": { "type": "pattern_replace", "pattern": "[@.]", "replacement": " " } } } }, "mappings": { "properties": { "email": { "type": "text", "analyzer": "email_analyzer", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } } - 方案2:使用N-gram分词器实现任意子串匹配
如果需要支持输入邮箱任意连续字符都能匹配(比如输入gmai也能命中带gmail.com的邮箱),可以配置N-gram分词器对邮箱内容按指定长度窗口切分。该方案的缺点是会增大索引体积,搜索性能略低于普通分词方案,按需选择即可。
内容的提问来源于stack exchange,提问作者Joey Yi Zhao
相关产品推荐
相关产品推荐

