ElasticSearch 按完全匹配搜索电子邮件

Hro*_*oft 2 elasticsearch

我需要通过电子邮件搜索联系人。根据ES 文档,实现这一目标的最佳方法是使用分uax_url_email词器。这是我的索引设置:

settings: {
  index: {
    creation_date: "1467895098804",
    analysis: {
      analyzer: {
        email: {
          type: "custom",
          tokenizer: "uax_url_email"
        }
      }
    },
    number_of_shards: "5",
    number_of_replicas: "1",
    uuid: "wL0P6OIaQqqYpFDvIHArTw",
    version: {
      created: "2030399"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

和映射:

contact: {
  dynamic: "false",
  properties: {
    contact_status: {
      type: "string"
    },
    created_at: {
      type: "date",
      format: "strict_date_optional_time||epoch_millis"
    },
    email: {
      type: "string"
    },
    id: {
      type: "long"
    },
    mailing_ids: {
      type: "long"
    },
    subscription_status: {
      type: "string"
    },
    type_ids: {
      type: "long"
    },
    updated_at: {
      type: "date",
      format: "strict_date_optional_time||epoch_millis"
    },
    user_id: {
      type: "long"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

创建索引后,我插入了两个文档:

curl -X PUT 'localhost:9200/contacts/contact/1' -d '{"contact_status": "confirmed", "email": "example@gmail.com", "id": "1", "user_id": "1", "subscription_status": "on"}'
Run Code Online (Sandbox Code Playgroud)

curl -X PUT 'localhost:9200/contacts/contact/2' -d '{"contact_status": "confirmed", "email": "example@yahoo.com", "id": "2", "user_id": "2", "subscription_status": "on"}'
Run Code Online (Sandbox Code Playgroud)

然后我尝试以不同的方式通过电子邮件搜索联系人:

curl -X POST 'localhost:9200/contacts/_search?pretty' -d '{"query": {"bool": {"must": [ {"match": {"_all": { "query": "example@google.com", "analyzer": "email" } } } ] } } }'
Run Code Online (Sandbox Code Playgroud)

我希望在 id=1 时得到 1 个结果,但得到了空命中:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}
Run Code Online (Sandbox Code Playgroud)

我测试过的下一个搜索查询是:

curl -X POST 'localhost:9200/contacts/_search?pretty' -d '{"query": {"bool": {"must": [ {"match": {"_all": { "query": "example@google", "analyzer": "email" } } } ] } } }'
Run Code Online (Sandbox Code Playgroud)

返回 2 个结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.016878016,
    "hits" : [ {
      "_index" : "contacts",
      "_type" : "contact",
      "_id" : "2",
      "_score" : 0.016878016,
      "_source" : {
        "contact_status" : "confirmed",
        "email" : "example@yahoo.com",
        "id" : "2",
        "user_id" : "2",
        "subscription_status" : "on"
      }
    }, {
      "_index" : "contacts",
      "_type" : "contact",
      "_id" : "1",
      "_score" : 0.016878016,
      "_source" : {
        "contact_status" : "confirmed",
        "email" : "example@gmail.com",
        "id" : "1",
        "user_id" : "1",
        "subscription_status" : "on"
      }
    } ]
  }
}
Run Code Online (Sandbox Code Playgroud)

但如您所知,我希望在搜索结果中获得 1 个文档。我究竟做错了什么?

Bos*_*nne 11

用它来提出你的要求它对我有用

GET my_index/_search
{
    "query": {
        "match_phrase_prefix" : {
            "email": "valery@gmail.com"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你会有期待的结果


isr*_*lst 6

这是发生的事情:

" uax_url_email" 分词器等于“标准”分词器(意思是它删掉了“@”),除非它得到一种模式,"<text>@<text>.<text>"在这种情况下它不删掉“@”而是将整个电子邮件地址作为一个标记。

现在,在索引时,您将“电子邮件”字段定义为“字符串”,默认为“标准”标记器,这意味着 - 您的地址被标记为2 个标记:“ example”和“ gmail.com”!在搜索时您定义了“电子邮件”标记器,这意味着您的(第一个)查询“example@google.com”根本没有被标记(因为它属于电子邮件模式),因此它既不匹配“example”也不匹配“gmail.com”(雅虎也是如此)。在您的第二个查询中,您搜索了“example@google” - 这不属于整个电子邮件模式,因此电子邮件标记器作为“标准”标记器工作,这意味着它会剪切“@”并将“example”和“google”标记化 在您的索引中寻找任何一个。由于示例已在您的 2 个文档中编入索引 - 它适合两者!

如果您只想匹配地址的“示例”部分 - 您不能在搜索时使用“电子邮件”分析器!在任何情况下,大多数情况下,您不应该从索引分析器更改搜索分析器

请注意,“标准”分析器不会将“gmail.com”切成 2 个标记!