根据您在问题中提供的信息,听起来包含电子邮件地址的字段已被索引标准分析仪 https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-analyzer.html,如果未指定其他分析器或该字段未标记为,则应用于字符串字段的默认分析器not_analyzed
.
标准分析器对给定字符串输入的影响可以通过使用分析API https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html弹性搜索:
curl -XPOST "http://localhost:9200/_analyze?analyzer=standard&text=ter%40gmail.com
文本输入需要进行 url 编码,如此处使用 @ 符号所示。运行该查询的结果是
{
"tokens": [
{
"token": "ter",
"start_offset": 0,
"end_offset": 3,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "gmail.com",
"start_offset": 4,
"end_offset": 13,
"type": "<ALPHANUM>",
"position": 2
}
]
}
我们可以看到标准分析器为输入生成两个标记,ter
and gmail.com
,这就是该字段的倒排索引中将存储的内容。
现在,运行一个Match query https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html将导致分析匹配查询的输入,默认情况下使用与应用匹配查询的字段的映射定义中找到的分析器相同的分析器。
然后,默认情况下,将来自此匹配查询分析的结果组合成一个布尔值或查询使得包含该字段的倒排索引中的任何一个标记的任何文档都将是匹配的。举个例子
text [email protected] /cdn-cgi/l/email-protection
,这意味着任何匹配的文档ter
or gmail.com
因为这个领域会很受欢迎
// Indexing
input: [email protected] /cdn-cgi/l/email-protection -> standard analyzer -> ter,gmail.com in inverted index
// Querying
input: [email protected] /cdn-cgi/l/email-protection -> match query -> docs with ter or gmail.com are a hit!
显然,对于精确匹配来说,这根本不是我们想要的!
运行一个Term query https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html将导致术语查询的输入not被分析,即它是一个与术语输入完全匹配的查询,但在索引时已分析过的字段上运行它可能会出现问题;由于字段的值已经过分析,但术语查询的输入尚未经过分析,因此您将得到与索引时发生的分析结果与术语输入完全匹配的结果。例如
// Indexing
input: [email protected] /cdn-cgi/l/email-protection -> standard analyzer -> ter,gmail.com in inverted index
// Querying
input: [email protected] /cdn-cgi/l/email-protection -> term query -> No exact matches for [email protected] /cdn-cgi/l/email-protection
input: ter -> term query -> docs with ter in inverted index are a hit!
这也不是我们想要的!
我们可能想要对该字段执行的操作是将其设置为not_analyzed
在映射定义中
putMappingDescriptor
.MapFromAttributes()
.Properties(p => p
.String(s => s.Name(n => n.FieldName).Index(FieldIndexOption.NotAnalyzed)
);
有了这个,我们就可以搜索精确匹配 with a Term filter https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html用一个Filtered query https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html
// change dynamic to your type
var docs = client.Search<dynamic>(b => b
.Query(q => q
.Filtered(fq => fq
.Filter(f => f
.Term("fieldName", "[email protected] /cdn-cgi/l/email-protection")
)
)
)
);
这将产生以下查询 DSL
{
"query": {
"filtered": {
"filter": {
"term": {
"fieldName": "[email protected] /cdn-cgi/l/email-protection"
}
}
}
}
}