Точное совпадение без учета регистра без нормализации в Elasticsearch 6.2
Я просмотрел все статьи и посты, которые мог найти о выполнении запросов с точным соответствием, без учета регистра, но при реализации они не выполняют то, что я ищу.
Прежде чем пометить этот вопрос как дубликат, прочитайте весь пост.
Учитывая имя пользователя, я хочу запросить в моей базе данных Elasticsearch вернуть только тот документ, который точно соответствует имени пользователя, но также нечувствителен к регистру.
Я попытался указать lowercase анализатор для моего username собственность и использование match запрос для реализации этого поведения. Хотя это решает проблему сопоставления без учета регистра, при точном сопоставлении происходит сбой.
Я посмотрел на использование lowercase нормализатор, но это сделало бы все мои имена пользователей строчными перед индексацией, поэтому, когда я собираю имена пользователей, они возвращаются в строчной форме, а это не то, что я хочу. Мне нужно сохранить исходный регистр каждой буквы в имени пользователя.
То, что я хочу, это следующее поведение:
Вставка пользователей
Этот документ будет храниться в индексе users именно так оно и есть.
Получение пользователя по имени пользователя
НЕ должен ничего возвращать.
1 ответ
Для достижения точного соответствия без учета регистра вам необходимо определить собственный анализатор. Анализатору необходимо выполнить два действия:
Два вышеупомянутых могут быть достигнуты путем:
Теперь этот пользовательский анализатор можно применить к текстовому полю, где требуется точный поиск без учета регистра.
Поэтому для создания индекса вы можете использовать ниже:
В выше case_insensitive_analyzer является необходимым анализатором, и, как вы можете видеть, он применяется на username поле.
Поэтому, когда вы индексируете документ, как показано ниже:
Теперь вы можете использовать запрос на совпадение, как показано ниже, для поиска по полю имени пользователя:
Поля без учета регистра в Elasticsearch
Я использую NEST с ElasticSearch и пытаюсь выполнить поиск, позволяя пользователям вводить поисковые фразы в поле поиска. Все работает нормально, за исключением того факта, что когда пользователь вводит поисковую фразу, ему необходимо убедиться, что имя поля совпадает с регистром имени поля в эластичном поиске.
Например, одно из моих полей называется bookTitle. Если они ищут, как показано ниже, то это работает
BookTitle: «Повесть о двух городах»
Если они будут искать, как в примере ниже, это не сработает.
Название книги: «Повесть о двух городах» Название книги: «Повесть о двух городах»
Код, который я использую для поиска, приведен ниже. Есть ли у кого-нибудь идеи, как я могу это исправить. Я надеялся, что есть настройка ElasticSearch / NEST, которая позволяет мне делать это, а не делать что-то некрасивое с поисковым текстом, например, найти «BookTitle» и заменить его на «bookTitle».
Любая помощь очень ценится.
3 ответа
С Elasticsearch это невозможно так, как вы хотите. Вы контролируете отображение, вы определяете имена полей, вы тот, кто контролирует запросы.
Согласно этому мнению, вам нужно следить за тем, что ваши пользователи будут вводить в поле поиска, Elasticsearch из коробки не поможет вам с именами полей в нижнем регистре или чем-то в этом роде.
Итак, какое бы решение вы ни выбрали, это будет обходной путь.
Обучайте пользователей и определите набор правил, которых следует придерживаться, как я упоминал выше.
Начните с создания соответствующей стратегии именования:
И соответствующий сериализатор:
Затем используйте сериализатор в настройках подключения вашего клиента NEST:
Это сохранит ваши поля в нижнем регистре. Затем, когда вы запрашиваете, просто установите все поля, предоставленные пользователем, в нижний регистр, и все должно выровняться.
Если вы не начинаете с нуля, вам придется повторно заполнить свои данные, чтобы сохранить единую стратегию именования.
Вы можете кэшировать отображение в C # в памяти и подтвердить, что все поля поиска найдены в нем. Если точное совпадение не найдено, попробуйте найти наиболее подходящие поля. Если есть несколько вариантов на выбор, выведите ошибку и попросите пользователя уточнить.
На самом деле пользовательский интерфейс может делать это « на лету » по мере ввода текста и помогать им выбрать правильный вариант.
Точное совпадение без учета регистра без нормализации в Elasticsearch 6.2
Я просмотрел все статьи и сообщения о выполнении запросов с точным соответствием и без учета регистра, но после реализации они не выполняют то, что я ищу.
Прежде чем пометить этот вопрос как повторяющийся, прочтите сообщение целиком.
Учитывая имя пользователя, я хочу запросить мою базу данных Elasticsearch, чтобы вернуть только документ, который точно соответствует имени пользователя, но также нечувствителен к регистру.
Я попытался указать анализатор lowercase для своего свойства username и использовать запрос match для реализации этого поведения. Хотя это решает проблему нечувствительного к регистру сопоставления, оно не дает точного сопоставления.
Я хочу следующее поведение:
Вставка пользователей
Этот документ будет сохранен в индексе под названием users в точности так, как он есть.
Получение пользователя по имени пользователя
Не должен ничего возвращать.
1 ответ
Чтобы добиться точного совпадения без учета регистра, вам необходимо определить собственный анализатор. Анализатору необходимо выполнить два действия:
Вышеупомянутые два могут быть достигнуты с помощью:
Теперь этот пользовательский анализатор можно применить к текстовому полю, где требуется точный поиск без учета регистра.
Итак, чтобы создать индекс, вы можете использовать ниже:
Итак, когда вы индексируете документ, как показано ниже:
Теперь вы можете использовать запрос соответствия, как показано ниже, для поиска по полю имени пользователя:
Точное совпадение без учета регистра без нормализации в Elasticsearch 6.2
Я просмотрел все статьи и посты, которые мог найти о выполнении запросов с точным соответствием, без учета регистра, но при реализации они не выполняют то, что я ищу.
Прежде чем пометить этот вопрос как дубликат, прочитайте весь пост.
Учитывая имя пользователя, я хочу запросить в моей базе данных Elasticsearch вернуть только тот документ, который точно соответствует имени пользователя, но также нечувствителен к регистру.
Я попытался указать lowercase анализатор для моего свойства username и использовать запрос на match для реализации этого поведения. Хотя это решает проблему сопоставления без учета регистра, при точном сопоставлении происходит сбой.
То, что я хочу, это следующее поведение:
Вставка пользователей
Получение пользователя по имени пользователя
НЕ должен ничего возвращать.
Для этого вам нужно определить свой собственный анализатор. Анализатору необходимо выполнить два действия:
строчная вводимое значение. (без учета регистра) нет какой-либо модификации ввода после действия в нижнем регистре. (для точного поиска)
Два вышеупомянутых могут быть достигнуты путем:
Теперь этот пользовательский анализатор можно применить к текстовому полю, где требуется точный поиск без учета регистра.
Поэтому для создания индекса вы можете использовать ниже:
Поэтому, когда вы индексируете документ, как показано ниже:
Теперь вы можете использовать запрос на совпадение, как показано ниже, для поиска по полю имени пользователя:
Основы Elasticsearch
Elasticsearch — поисковый движок с json rest api, использующий Lucene и написанный на Java. Описание всех преимуществ этого движка доступно на официальном сайте. Далее по тексту будем называть Elasticsearch как ES.
Подобные движки используются при сложном поиске по базе документов. Например, поиск с учетом морфологии языка или поиск по geo координатам.
В этой статье я расскажу про основы ES на примере индексации постов блога. Покажу как фильтровать, сортировать и искать документы.
Чтобы не зависеть от операционной системы, все запросы к ES я буду делать с помощью CURL. Также есть плагин для google chrome под названием sense.
По тексту расставлены ссылки на документацию и другие источники. В конце размещены ссылки для быстрого доступа к документации. Определения незнакомых терминов можно прочитать в глоссарии.
Установка ES
Для этого нам сначала потребуется Java. Разработчики рекомендуют установить версии Java новее, чем Java 8 update 20 или Java 7 update 55.
После установки и запуска проверим работоспособность:
Нам придет приблизительно такой ответ:
Индексация
ES автоматически создал индекс blog и тип post. Можно провести условную аналогию: индекс — это база данных, а тип — таблица в этой БД. Каждый тип имеет свою схему — mapping, также как и реляционная таблица. Mapping генерируется автоматически при индексации документа:
В ответе сервера я добавил в комментариях значения полей проиндексированного документа:
Стоит отметить, что ES не делает различий между одиночным значением и массивом значений. Например, поле title содержит просто заголовок, а поле tags — массив строк, хотя они представлены в mapping одинаково.
Позднее мы поговорим о маппинге более подобно.
Запросы
Извлечение документа по его id:
Ключ _version показывает версию документа. Он нужен для работы механизма оптимистических блокировок. Например, мы хотим изменить документ, имеющий версию 1. Мы отправляем измененный документ и указываем, что это правка документа с версией 1. Если кто-то другой тоже редактировал документ с версией 1 и отправил изменения раньше нас, то ES не примет наши изменения, т.к. он хранит документ с версией 2.
Ключ _source содержит тот документ, который мы индексировали. ES не использует это значение для поисковых операций, т.к. для поиска используются индексы. Для экономии места ES хранит сжатый исходный документ. Если нам нужен только id, а не весь исходный документ, то можно отключить хранение исходника.
Если нам не нужна дополнительная информация, можно получить только содержимое _source:
Также можно выбрать только определенные поля:
Давайте проиндексируем еще несколько постов и выполним более сложные запросы.
Сортировка
Мы выбрали последний пост. size ограничивает кол-во документов в выдаче. total показывает общее число документов, подходящих под запрос. sort в выдаче содержит массив целых чисел, по которым производится сортировка. Т.е. дата преобразовалась в целое число. Подробнее о сортировке можно прочитать в документации.
Фильтры и запросы
ES с версии 2 не различает фильты и запросы, вместо этого вводится понятие контекстов.
Контекст запроса отличается от контекста фильтра тем, что запрос генерирует _score и не кэшируется. Что такое _score я покажу позже.
Фильтрация по дате
Используем запрос range в контексте filter:
Фильтрация по тегам
Используем term query для поиска id документов, содержащих заданное слово:
Полнотекстовый поиск
Три наших документа содержат в поле content следующее:
Смешная история про котят
Смешная история про щенков
Душераздирающая история про бедного котенка с улицы
Используем match query для поиска id документов, содержащих заданное слово:
Однако, если искать «истории» в поле контент, то мы ничего не найдем, т.к. в индексе содержатся только оригинальные слова, а не их основы. Для того чтобы сделать качественный поиск, нужно настроить анализатор.
Поле _score показывает релевантность. Если запрос выпоняется в filter context, то значение _score всегда будет равно 1, что означает полное соответствие фильтру.
Анализаторы
Анализаторы нужны, чтобы преобразовать исходный текст в набор токенов.
Анализаторы состоят из одного Tokenizer и нескольких необязательных TokenFilters. Tokenizer может предшествовать нескольким CharFilters. Tokenizer разбивают исходную строку на токены, например, по пробелам и символам пунктуации. TokenFilter может изменять токены, удалять или добавлять новые, например, оставлять только основу слова, убирать предлоги, добавлять синонимы. CharFilter — изменяет исходную строку целиком, например, вырезает html теги.
В ES есть несколько стандартных анализаторов. Например, анализатор russian.
Воспользуемся api и посмотрим, как анализаторы standard и russian преобразуют строку «Веселые истории про котят»:
Стандартный анализатор разбил строку по пробелам и перевел все в нижний регистр, анализатор russian — убрал не значимые слова, перевел в нижний регистр и оставил основу слов.
Посмотрим, какие Tokenizer, TokenFilters, CharFilters использует анализатор russian:
Опишем свой анализатор на основе russian, который будет вырезать html теги. Назовем его default, т.к. анализатор с таким именем будет использоваться по умолчанию.
Сначала из исходной строки удалятся все html теги, потом ее разобьет на токены tokenizer standard, полученные токены перейдут в нижний регистр, удалятся незначимые слова и от оставшихся токенов останется основа слова.
Создание индекса
Выше мы описали default анализатор. Он будет применяться ко всем строковым полям. Наш пост содержит массив тегов, соответственно, теги тоже будут обработаны анализатором. Т.к. мы ищем посты по точному соответствию тегу, то необходимо отключить анализ для поля tags.
Создадим индекс blog2 с анализатором и маппингом, в котором отключен анализ поля tags:
Добавим те же 3 поста в этот индекс (blog2). Я опущу этот процесс, т.к. он аналогичен добавлению документов в индекс blog.
Полнотекстовый поиск с поддержкой выражений
Познакомимся с еще одним типом запросов:
Т.к. мы используем анализатор с русским стеммингом, то этот запрос вернет все документы, хотя в них встречается только слово ‘история’.
Запрос может содержать специальные символы, например: