Elasticsearch 6.2 中没有规范化的完全匹配、不区分大小写的匹配

Hid*_*Hid 5 case-insensitive exact-match elasticsearch

我已经查看了我能找到的关于执行完全匹配、不区分大小写查询的每篇文章和帖子,但是在实施时,它们并没有执行我正在寻找的内容。

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

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

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

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

我想要的是以下行为:


插入用户

POST {elastic}/users/_doc

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}
Run Code Online (Sandbox Code Playgroud)

该文档将存储在一个索引中,users完全按照它的方式命名。

通过用户名获取用户

GET {frontend}/user/UsErNaMe
Run Code Online (Sandbox Code Playgroud)

应该回来

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}
Run Code Online (Sandbox Code Playgroud)

GET {frontend}/user/username
Run Code Online (Sandbox Code Playgroud)

应该回来

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}
Run Code Online (Sandbox Code Playgroud)

GET {frontend}/user/USERNAME
Run Code Online (Sandbox Code Playgroud)

应该回来

{
    "email": "random@email.com",
    "username": "UsErNaMe",
    "password": "1234567"
}
Run Code Online (Sandbox Code Playgroud)

GET {frontend}/user/UsErNaMe $RaNdoM LeTteRs
Run Code Online (Sandbox Code Playgroud)

应该返回任何东西。

谢谢你。

Nis*_*ini 6

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

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

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

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

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

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

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"
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

上面case_insensitive_analyzer是所需的分析器,如您所见,它已应用于username现场。

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

PUT test/_doc/1
{
  "email": "random@email.com",
  "username": "UsErNaMe",
  "password": "1234567"
}
Run Code Online (Sandbox Code Playgroud)

对于该字段username,输入是UsErNaMe。分析器首先lowercaseUsErNaMe产生值的输入应用过滤器username。现在在这个值上username它应用分keyword词器,它只输出应用过滤器后获得的值,作为单个标记 ie username

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

GET test/_doc/_search
{
  "query": {
    "match": {
      "username": "USERNAME"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用上面会给你想要的输出。USERNAME在上面的查询中替换为usernameorUsErNaMeUSERnameall 将匹配文档。这样做的原因是,如果没有明确指定分析器,则在搜索时,elasticsearch 使用在索引时应用于字段的分析器。在上述情况下,当搜索 field 时usernamecase_insensitive_analyzer将应用于输入值,即USERNAME这将导致令牌username并因此匹配。