【问题标题】:Exact-match, case-insensitive match without normalization in Elasticsearch 6.2在 Elasticsearch 6.2 中没有规范化的完全匹配、不区分大小写的匹配
【发布时间】:2019-04-18 08:53:38
【问题描述】:

我查看了所有我能找到的关于执行完全匹配、不区分大小写的查询的文章和帖子,但在实施时,它们并没有执行我想要的。

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

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

我尝试为我的username 属性指定lowercase 分析器并使用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

应该返回任何东西。

谢谢。

【问题讨论】:

    标签: elasticsearch case-insensitive exact-match


    【解决方案1】:

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

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

    以上两个可以通过:

    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。分析器首先对输入UsErNaMe 应用lowercase 过滤器,从而得到值username。现在在这个值username 上应用keyword 标记器,它只输出应用过滤器后获得的值,作为单个标记,即username

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

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

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

    【讨论】:

    • 感谢您的帮助。我确实已经尝试过了,但我认为它不起作用,但事实证明我忘记为我的服务中的一条路线切换到匹配查询。完成所有必要的更改后,一切都运行良好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    相关资源
    最近更新 更多