Игнорирование специальных символов в query_string Elasticsearch

Бесплатная консультация юриста

+7 (800) 301-07-30

Реклама jurik.ru

В современных системах поиска часто возникает необходимость находить документы, в которых значения полей содержат разделители, дефисы, слэши и другие спецсимволы. При этом пользователь может вводить «чистый» запрос без этих символов (например, 8652589963 вместо 8652 / 58996-3). В данной статье мы подробно рассмотрим, как решить эту задачу с помощью query_string в Elasticsearch, используя техники игнорирования символов, кастомных анализаторов и альтернативных запросов.


Содержание

  1. Что такое query_string?
  2. Проблема специальных символов
  3. Способы игнорирования символов в query_string
  4. Примеры запросов
  5. Настройка кастомного анализатора
  6. Альтернативные типы запросов
  7. Рекомендации и лучшие практики

Тема «10162 часть» относится к серии рекомендаций по работе с поисковыми запросами в Elasticsearch, где рассматриваются типичные сложности, связанные с обработкой специальных символов в полях типа keyword или text. В предоставленном фрагменте из интернета видно, что пользователь пытается найти запись по полю documentData.refNo, где значение хранится как 8652 / 58996-3, а запрос приходит в виде «чистого» номера 8652589963. Ниже мы покажем, как построить такой запрос корректно.

Что такое query_string?

query_string – это гибкий DSL‑запрос Elasticsearch, который позволяет использовать логические операторы (AND, OR, NOT), группировку скобками, wildcard‑символы (*, ?) и регулярные выражения (/pattern/). Он особенно удобен для быстрого тестирования, однако требует внимательного отношения к разбору анализируемого текста.

По умолчанию query_string использует стандартный анализатор, который разбивает текст на токены, удаляя большинство знаков препинания. Если поле индексируется как keyword (не анализируемое), то спецсимволы становятся частью токена, и обычный запрос без них не сработает.

Проблема специальных символов

Рассмотрим пример из предоставленного материала:

documentData : refNo : 8652 / 58996-3, status : Rejected

Пользователь вводит только цифры: 8652589963. Прямой запрос

query_string: { query: "(documentData.refNo: /86525/ -8996/ -3/)" }

не работает, потому что:

  • Слэш (/) и дефис (-) интерпретируются как операторы регулярных выражений или как часть синтаксиса query_string.
  • Пробелы вокруг спецсимволов также влияют на токенизацию.
  • Таким образом, нужно либо «удалить» спецсимволы на этапе индексации, либо преобразовать запрос так, чтобы он игнорировал их при поиске.

    Способы игнорирования символов в query_string

    Использование кастомного анализатора с фильтром pattern_replace

    Самый надёжный способ – изменить способ индексации поля, чтобы спецсимволы удалялись (или заменялись пробелом) ещё при индексации. Тогда поиск по чистому номеру будет работать без изменений в запросе.

    PUT my_index
    {
     "settings": {
     "analysis": {
     "analyzer": {
     "no_special_analyzer": {
     "tokenizer": "keyword",
     "filter": [
     "lowercase",
     { "type": "pattern_replace", "pattern": "[\s\-/]", "replacement": "" }
     ]
     }
     } }
     },
     "mappings": {
     "properties": {
     "documentData": {
     "properties": {
     "refNo": { "type": "text", "analyzer": "no_special_analyzer" }
     }
     }
     }
     }
    }
    

    После этого документ с refNo: "8652 / 58996-3" будет проиндексирован как токен 8652589963. Обычный match или query_string запрос 8652589963 найдёт его без дополнительных усилий.

    Использование query_string с analyzer параметром

    Если менять маппинг нельзя, можно указать анализатор прямо в запросе:

    GET my_index/_search
    {
     "query": {
     "query_string": {
     "query": "8652589963",
     "fields": ["documentData.refNo"],
     "analyzer": "whitespace" // или любой анализатор, который не учитывает спецсимволы
     }
     }}

    Однако стандартные анализаторы (whitespace, simple) всё равно могут оставлять спецсимволы как отдельные токены. Поэтому лучше комбинировать с pattern_replace фильтром на уровне запроса:

    GET my_index/_search
    { "query": {
     "query_string": {
     "query": "8652589963",
     "fields": ["documentData.refNo"],
     "analyzer": "no_special_analyzer"
     }
     }
    }
    

    Экранирование спецсимволов в самом запросе

    Если необходимо оставить поле как keyword и не менять анализатор, можно экранировать спецсимволы в строке запроса, заменив их на пробел или на (в зависимости от того, как они интерпретируются). Пример:

    GET my_index/_search
    {
     "query": {
     "query_string":query": "documentData.refNo:8652\\/\\ 58996\\-3",
     "default_field": "documentData.refNo"
     }
     }}
    

    Здесь каждый спецсимвол предваряется двойным обратным слешем (\), что заставляет query_string рассматривать его как обычный символ, а не как оператор.

    Использование wildcard и regex без query_string

    Иногда проще прибегнуть к wildcard или regexp запросам, которые позволяют указывать «пропуск» любых символов:

    GET my_index/_search
    {
     "query": {
     "wildcard": {
     "documentData.refNo": {
     "value": "8652589963",
     "case_insensitive": true
     }
     }
     }
    }
    

    Или с регулярным выражением:

    GET my_index/_search
    {
     "query": {
     "regexp": {
     "documentData.refNo": ".*8652.58996.3.*"
     }
     }
    }
    

    Эти запросы работают даже если поле хранится как keyword, но они могут быть менее эффективны на больших объёмах данных из‑за полного сканирования термов.

    Примеры запросов

    Ниже собраны готовые примеры, которые можно скопировать в Kibana Dev Tools.

    Пример 1: Поиск с кастомным анализатором (рекомендовано)

    POST my_index/_search
    {
     "query": {
     "match": {
     "documentData.refNo": "8652589963"
     }
     }
    }
    

    Пример 2: query_string с указанием анализатора

    POST my_index/_search
    {
     "query": {
     "query_string": {
     "query": "8652589963",
     "fields": ["documentData;refNo"],
     "analyzer": "no_special_analyzer"
     }
     }
    }
    

    Пример 3: Экранирование спецсимволов в query_string

    POST my_index/_search
    {
     "query": {
     "query_string": {
     "query": "documentData.refNo:8652\\/\\ 58996\\-3",
     "default_field": "documentData.refNo"
     }
     }
    }
    

    Пример 4: wildcard‑поиск

    POST my_index/_search
    { "query": {
     "wildcard": {
     "documentData.refNo": {
     "value": "8652589963",
     "case_insensitive": true
     }
     }
     }
    }
    

    Настройка кастомного анализатора

    Если вы решили идти путём изменения индексации, вот пошаговая инструкция:

    1. Определите токенизатор. Для полей, где нужно сохранять całą строку как один токен, подходит keyword.
    2. Добавьте фильтр lowercase (если нужен регистронезависимый поиск).
    3. Примените pattern_replace с регулярным выражением, которое удаляет все нежелательные символы. Пример: [\s\-/] – пробел, слэш, дефис.
    4. Опционально добавьте другие фильтры (например, asciifolding для удаления диакритики).
    5. Создайте или обновите индекс с новым анализатором и выполните реиндексацию существующих данных (_reindex).

    После реиндексации проверьте токены через API _analyze:

    GET my_index/_analyze
    {
    "analyzer": "no_special_analyzer",
    "text": "8652 / 58996-3"
    }

    Ожидаемый вывод: ["8652589963"].

    Альтернативные типы запросов

    Помимо query_string, стоит рассмотреть:

    • match_phrase – если важно сохранять порядок слов, но спецсимволы можно игнорировать через анализатор.
    • term – для точного совпадения по keyword полю после предварительной нормализации.
    • prefix – полезно, когда пользователь вводит только начало номера.
    • span_near – для сложных позиционных требований с учётом удалённых символов.

    Рекомендации и лучшие практики

    1. Нормализуйте данные на этапе индексации, а не на этапе запроса – это уменьшает нагрузку на кластер и делает поиск предсказуемым.
    2. Используйте keyword тип для полей, где важно точное совпадение (например, номера документов, SKU).
    3. Если поле должно оставаться анализируемым (для полнотекстового поиска), добавьте multi‑field: один text для поиска по словам, второй keyword с кастомным анализатором для точного совпадения;
    4. Тестируйте анализатор через _analyze перед внесением изменений в маппинг.
    5. Следите за производительностью: wildcard и regex запросы могут приводить к медленному сканированию термов; предпочтительно использовать нормализованные поля.
    6. Документируйте псевдонимы (aliases) и шаблоны индексов, чтобы изменения анализатора применялись ко всем новым индексам автоматически.

    Тема «10162 часть» показывает, насколько важно правильно обрабатывать специальные символы при построении поисковых запросов в Elasticsearch. Основные подходы – это:

    • Изменение анализатора (удаление/замена спецсимволов) на этапе индексации;
    • Указание нужного анализатора прямо в query_string;
    • Экранирование спецсимволов в самом запросе;
    • Применение wildcard/regex запросов, когда изменение маппинга невозможно.

    Выбор конкретного метода зависит от ограничений вашей схемы данных, объёма индекса и требований к скорости поиска. Следуя рекомендациям выше, вы сможете обеспечить надёжный и быстрый поиск даже тогда, как пользователи вводят запросы без учёта разделителей, дефисов и других спецсимволов.

    Если у вас остались вопросы по настройке анализатора или оптимизации конкретных запросов – не стесняйтесь задавать их в комментариях или обращаться к официальной документации Elasticsearch.