【问题标题】:ElasticSearch search email by full matchElasticSearch 通过完全匹配搜索电子邮件
【发布时间】:2016-07-07 13:13:08
【问题描述】:

我需要通过电子邮件搜索联系人。根据ES documentation,实现这一目标的最佳方法是使用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"
    }
  }
}

和映射:

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"
    }
  }
}

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

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

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

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

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

我希望得到 1 个 id=1 的结果,但结果为空:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}

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

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

返回 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"
      }
    } ]
  }
}

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

【问题讨论】:

  • 如果email 只包含电子邮件地址,为什么不将该字段设为"index":"not_analyzed",然后使用term 过滤器来搜索电子邮件地址?
  • 因为我还需要按user_id、id等字段进行搜索。此外,我想按电子邮件的一部分进行搜索,如下所示:在输入中输入 example 并获取包含“示例”的电子邮件列表,在我的情况下 - 两个文档。或者,如果我输入 gmail.com => 获取 id 为 1 的文档
  • 我建议采用这种方法:stackoverflow.com/questions/30115867/… 如果您有任何困难或与此不同的用例,请告诉我。

标签: elasticsearch


【解决方案1】:

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

GET my_index/_search
{
    "query": {
        "match_phrase_prefix" : {
            "email": "valery@gmail.com"
        }
    }
}

你会得到预期的结果

【讨论】:

    【解决方案2】:

    事情是这样的:

    uax_url_email”分词器等同于“标准”分词器(意味着它会删除“@”),除非它获得"<text>@<text>.<text>" 的模式,在这种情况下它不会删除“@”但将整个电子邮件地址作为一个令牌。

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

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

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

    【讨论】:

    • 感谢您的解释。我认为在搜索查询中指定分析器会分析属性,而不是搜索查询。 :(所以据我所知,我应该在“创建索引”阶段为电子邮件指定分析器。问题是我已经在生产中有这样的索引方案,其中包含 600k+ 文档,解决这个搜索问题的唯一方法是重新创建这个索引?
    • 您应该在映射中指定您的“电子邮件”分析器。这样,每个新文档都将被分析。为此,您只需要使用新映射创建一个新索引,并将旧索引重新索引到新索引。这很容易。再说一次,您只能将电子邮件作为一个整体进行匹配!
    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 2020-04-18
    • 2016-07-12
    • 1970-01-01
    • 2011-08-24
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多