Точное совпадение без учета регистра без нормализации в Elasticsearch 6.2 - PullRequest
1 голос
/ 18 апреля 2019

Я просмотрел каждую статью и публикацию о выполнении запросов с точным соответствием без учета регистра, но при реализации они не выполняют то, что я ищу.

Перед вамипометьте этот вопрос как дубликат, пожалуйста, прочитайте весь пост.

Учитывая имя пользователя, я хочу запросить мою базу данных 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 Ответ

3 голосов
/ 18 апреля 2019

Чтобы достичь точного соответствия без учета регистра, вам нужно определить свой собственный анализатор.Анализатору необходимо выполнить два действия:

  1. в нижнем регистре входного значения.(для нечувствительного к регистру)
  2. нет изменений в вводе после действия в нижнем регистре.(для точного поиска)

Приведенные выше два могут быть достигнуты с помощью:

  1. использования фильтра lowercase при определении пользовательского анализатора.
  2. установки *От 1015 * до 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 в приведенном выше запросе на username или UsErNaMe или USERname, все будут соответствовать документу.Причина этого заключается в том, что при поиске, если анализатор не указан явно ,asticsearch использует анализатор, примененный к полю при индексации.В приведенном выше случае при поиске по полю username, case_insensitive_analyzer будет применено к входному значению, т.е. USERNAME, что приведет к токену username и, следовательно, к совпадению.

...