Chewy(Elasticsearch)多邮箱字段模糊搜索失效问题求助
邮箱字段通配符搜索失效的解决办法
问题场景
我定义了针对邮箱的分析器:
analyzer: { email: { tokenizer: 'uax_url_email', filter: ['lowercase'] } }
并配置了存储多个邮箱值的字段:
field :emails, type: :text, analyzer: 'email', search_analyzer: 'email', value: -> (user) { [user.email, user.lead_requests.pluck(:email)].flatten.compact.uniq }
索引完成后测试搜索出现以下情况:
- 通配符搜索
*example.com能正常返回结果:
UsersIndex.query(wildcard: { emails: "*example.com" }).count => 1
- 但带@的通配符搜索
*@example.com返回0:
UsersIndex.query(wildcard: { emails: "*@example.com" }).count => 0
- 通配符搜索完整邮箱
volk@example.com也返回0(注:此处字段名写错为email,修正为emails后仍无结果):
UsersIndex.query(wildcard: { email: "volk@example.com" }).count => 0
- 只有使用match查询完整邮箱才能得到结果:
UsersIndex.query(match: { emails: "volk@example.com" }).count => 1
问题原因
uax_url_email分词器会将完整邮箱作为单个token存入倒排索引,但通配符查询不会经过分析器处理,而是直接匹配索引中的原始token。text类型字段的倒排索引里是经过分词后的token(比如volk@example.com),但前缀通配符开头的查询(*xxx)在text字段上匹配效率低且容易出现匹配异常;字段名写错是个别查询无结果的原因,但核心问题还是通配符查询与text字段分词逻辑不匹配。
解决方案
方案1:添加keyword子字段
给emails字段新增一个keyword类型的子字段,用于存储完整邮箱的原始值,支持精确匹配和通配符查询:
field :emails, type: :text, analyzer: 'email', search_analyzer: 'email', value: -> (user) { [user.email, user.lead_requests.pluck(:email)].flatten.compact.uniq }, fields: { keyword: { type: 'keyword', ignore_above: 256 } }
之后使用该子字段进行查询:
# 带@的通配符查询 UsersIndex.query(wildcard: { "emails.keyword": "*@example.com" }).count # 完整邮箱通配符查询 UsersIndex.query(wildcard: { "emails.keyword": "volk@example.com" }).count
方案2:使用match_phrase_prefix查询
如果仅需要前缀类的包含搜索,可以用match_phrase_prefix,它会经过分析器处理,能匹配邮箱的后半段:
UsersIndex.query(match_phrase_prefix: { emails: "@example.com" }).count
方案3:改用ngram分词器(支持任意位置包含搜索)
如果需要支持任意位置的包含搜索(比如搜volk、example都能找到对应邮箱),可以配置ngram分词器:
analyzer: { email_ngram: { tokenizer: { type: 'ngram', min_gram: 2, max_gram: 10 }, filter: ['lowercase'] } }
然后将字段的分析器替换为email_ngram:
field :emails, type: :text, analyzer: 'email_ngram', search_analyzer: 'email_ngram', value: -> (user) { [user.email, user.lead_requests.pluck(:email)].flatten.compact.uniq }
这种方式会生成更多的token,索引体积会增大,需要根据业务场景权衡使用。
内容的提问来源于stack exchange,提问作者zolter
相关产品推荐
相关产品推荐

