完全匹配,不区分大小写的匹配,无需在Elasticsearch 6.2中进行标准化

时间:2019-04-18 08:53:38

标签: elasticsearch case-insensitive exact-match

我看过每一篇文章,发现我可以找到有关执行完全匹配,不区分大小写的查询的信息,但是在实现时,它们并不能满足我的需求。

在将此问题标记为重复之前,请阅读整篇文章。

给出用户名,我想查询我的Elasticsearch数据库以仅返回与用户名完全匹配但不区分大小写的文档。

我尝试为我的lowercase属性指定一个username分析器,并使用match查询来实现此行为。虽然这解决了区分大小写的匹配问题,但在完全匹配时失败。

我研究过使用lowercase规范化器,但这会使索引中的所有用户名都变为小写,因此当我聚合用户名时,它们将以小写形式返回,这不是我想要的。我需要在用户名中保留每个字母的原始大小写。

我想要的是以下行为:


插入用户

POST {elastic}/users/_doc

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}

此文档将按照原样存储在名为users的索引中。

通过用户名获取用户

GET {frontend}/user/UsErNaMe

应该返回

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}

GET {frontend}/user/username

应该返回

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}

GET {frontend}/user/USERNAME

应该返回

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}

GET {frontend}/user/UsErNaMe $RaNdoM LeTteRs

应该返回任何内容。

谢谢。

1 个答案:

答案 0 :(得分:3)

要实现不区分大小写的精确匹配,您需要定义自己的分析器。分析器需要执行两个操作:

  1. 小写输入值。 (不区分大小写)
  2. 小写操作后对输入的任何修改为
  3. 否。 (用于精确搜索)

以上两个可以通过以下方式实现:

  1. 在定义自定义分析器时使用lowercase过滤器。
  2. tokenizer设置为keyword,这将确保在应用小写过滤器后生成输入值的单个标记。

现在,可以将此自定义分析器应用于需要区分大小写的精确搜索的文本字段。

因此,您可以在下面使用索引来创建索引:

PUT test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "case_insensitive_analyzer": {
          "type": "custom",
          "filter": [
            "lowercase"
          ],
          "tokenizer": "keyword"
        }
      }
    }
  },
  "mappings": {
    "_doc": {
      "properties": {
        "email": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "username": {
          "type": "text",
          "analyzer": "case_insensitive_analyzer"
        },
        "password": {
          "type": "keyword"
        }
      }
    }
  }
}

在上面的case_insensitive_analyzer中是必需的分析器,如您所见,它已应用在username字段中。

因此,当您索引文档如下时:

PUT test/_doc/1
{
  "email": "random@email.com",
  "username": "UsErNaMe",
  "password": "1234567"
}

对于字段username,输入为UsErNaMe。分析器首先在输入lowercase上应用UsErNaMe过滤器,得到值username。现在,在此值username上应用keyword令牌生成器,该令牌生成器什么也不做,只输出应用了过滤器后获得的值作为单个令牌,即username

现在您可以使用以下匹配查询来搜索用户名字段:

GET test/_doc/_search
{
  "query": {
    "match": {
      "username": "USERNAME"
    }
  }
}

使用上面的命令将为您提供所需的输出。将上述查询中的USERNAME替换为usernameUsErNaMeUSERname,所有文件都会匹配。原因是,在搜索中是否未明确指定分析器时,elasticsearch在建立索引时会使用应用于该字段的分析器。在上述情况下,当对字段username进行搜索时,case_insensitive_analyzer将应用于输入值,即USERNAME,这将导致标记username并因此导致匹配。