Дата подготовки: 08:24:07 ()
В Elasticsearch существует несколько способов формировать запросы к полям документа. Два наиболее часто используемых – query_string и match. Оба позволяют искать по тексту, но различаются в способе обработки запроса, поддержке специальных символов и влиянии на производительность. В этой статье мы подробно рассмотрим, как каждый из них ведёт себя при наличии спецсимволов (например, дефиса, точки, слэша, кавычек и т.п.), какие нюансы следует учитывать и когда предпочтительнее использовать тот или иной метод.
Краткий обзор каждого типа запроса
query_string
query_string – это мощный парсер запросов, который позволяет использовать синтаксис Lucene query language. Он поддерживает:
- логические операторы (AND, OR, NOT);
- группировку скобками;
- wildcard‑ и regexp‑поиск;
- фразовый поиск с кавычками;
- указание полей через префикс
field:; - множество дополнительных параметров (
default_operator,analyze_wildcard,lenientи др.).
Из‑за того, что запрос проходит через полноценный парсер, специальные символы могут интерпретироваться как часть синтаксиса (например, дефис – оператор NOT, точка – любой символ в regexp и т.д.). Поэтому при работе с пользовательским вводом, содержащим такие символы, часто требуется экранирование или предварительная обработка.
match query
match относится к семейству «term‑level» запросов, но на самом деле он работает на уровне analysed text: запрос сначала проходит через тот же анализатор, что и поле при индексации, а затем формируется запрос типа bool с соответствующими термами. Основные особенности:
- не поддерживает синтаксис Lucene (нет операторов AND/OR, wildcard, regexp и т.п.);
- автоматически разбивает входную строку на токены согласно анализатору поля;
- по умолчанию использует оператор OR (можно изменить через
operator); - не требует экранирования специальных символов, если они не являются частью синтаксиса query_string (т.к. такого синтаксиса нет).
Таким образом, match более «дружелюбен» к произвольному тексту, содержащему спецсимволы, потому что он просто передаёт строку анализатору, а не пытается интерпретировать её как запрос на языке Lucene.
Как спецсимволы влияют на работу каждого запроса
Примеры спецсимволов
Рассмотрим набор типичных символов, которые могут вызывать проблемы:
- дефис
-(часто используется как оператор NOT); - точка
.(в regexp – любой символ); - слеш
/(открывает/закрывает regexp); - кавычки
"и одинарные'(фразовый поиск); - двоеточие
:(указание поля); - скобки (группировка);
- звёздочка
*и вопросительный знак?(wildcard).
query_string и спецсимволы
При использовании query_string каждый из этих символов может быть воспринят как часть синтаксиса, если не экранировать его обратным слешем . Пример:
Неэкранированный запрос:
GET my_index/_search
{
«query»: {
«query_string»: {
«query»: «error-34567332»,
«default_field»: «message»
}
}
}
Здесь дефис будет интерпретироваться как оператор NOT, и Elasticsearch будет искать документы, содержащие терм error и не содержащие 34567332. Результат, скорее всего, будет пустым или неожиданным.
Экранированный запрос:
GET my_index/_search
{
«query»: {
«query_string»: {
«query»: «error\-34567332»,
«default_field»: «message»,
«lenient»: true
}
}
}
Теперь дефис воспринимается как обычный символ, и поиск вернёт документы, содержащий exact терм error-34567332 (при условии, что поле не анализирует дефис как разделитель).
Важно также отметить параметр analyze_wildcard: если он установлен в true, то wildcard‑символы (*, ?) будут анализироваться, что может изменить результат при наличии спецсимволов внутри шаблона.
match query и спецсимволы
В случае match специальные символы просто передаются анализатору. Если поле использует стандартный анализатор (standard), то:
- дефис обычно считается частью токена (если не настроен иначе);
- точка, слэш и другие символы могут быть удалены или заменены пробелом в зависимости от настроек токенизатора;
- кавычки не имеют особого значения – они воспринимаются как обычные символы.
- использовать поле с
keyword‑типом (не анализируемое); - применить параметр
operator: "and"для match, если нужно, чтобы оба токена присутствовали; - воспользоваться
match_phraseдля поиска фразы (сохраняет порядок токенов). - query_string требует парсинга входной строки, построения абстрактного синтаксического дерева и последующего преобразования в низкоуровневые запросы (term, prefix, wildcard и т.д.). Этот этап добавляет небольшую, но измеримую задержку, особенно при сложных выражениях с множеством операторов и скобок.
- match bypasses парсинг Lucene query language; он сразу передаёт строку анализатору и формирует простой bool‑запрос из полученных термов. Поэтому, как правило, match работает чуть быстрее при простых поисках по одному полю.
- Однако, если нужно воспользоваться расширенным синтаксисом (логические операторы, wildcard, regexp, fuzzy и т.п.), то query_string остаётся единственным практичным вариантом, и его производительность становится приемлемой за счёт кэширования разобранного запроса (query cache).
- Нужен сложный поиск с логическими операторами, скобками, группами полей (
field1:value OR field2:value). - Требуется поддержка wildcard, regexp, fuzzy, proximity search (~), boosting внутри запроса.
- Вы контролируете ввод (например, формируете запрос в админ‑панели) и можете гарантировать корректное экранирование спецсимволов.
- Хотите использовать параметры
lenient,default_operator,analyze_wildcardдля тонкой настройки. - Поиск по пользовательскому вводу, где нельзя гарантировать отсутствие спецсимволов (форма поиска на сайте, лог‑поиск и т.п.).
- Необходимо простое совпадение по одному или нескольким полям без сложного синтаксиса.
- Требуется высокая предсказуемость результатов и минимальная вероятность синтаксических ошибок.
- Вы используете поля типа
keywordдля точного совпадения илиtextс анализатором, который уже обрабатывает дефисы, точки и т.д. так, как вам нужно. - использовать
wildcardилиprefixзапрос отдельно; - или добавить отдельное поле
sku.edge_ngramдля поиска по префиксу. - query_string – мощный, гибкий, но требует осторожного обращения со специальными символами и чуть более тяжёл в обработке.
- match – проще и безопаснее для произвольного пользовательского ввода, особенно когда нужно простое совпадение без сложного синтаксиса.
Пример:
GET my_index/_search
{
«query»: {
«match»: {
«message»: «error-34567332»
}
}
}
Запрос будет разбит на токены согласно анализатору поля message. Если анализатор оставляет дефис внутри токена, то будет выполнен поиск по терму error-34567332. Если же анализатор разбивает по дефису, получим два терма error и 34567332 и поиск будет работать как OR (по умолчанию). Чтобы получить точное совпадение, можно:
Сравнение производительности
С точки зрения нагрузки на кластер:
В реальных нагрузках разница во времени выполнения обычно составляет от нескольких миллисекунд до десятков миллисекунд на запрос, что заметно только при очень высоком QPS (запросов в секунду). Поэтому выбор часто диктуется функциональными требованиями, а не чистой скоростью.
Когда использовать query_string, а когда match
Рекомендации для query_string
Рекомендации для match
Практические примеры с экранированием
Пример 1: Поиск логов с дефисом и точкой
Предположим, у нас есть индекс logs с полем message типа text (анализатор standard). Нужно найти все записи, содержащие строку ERROR-2026.08.07.
С использованием query_string (с экранированием):
GET logs/_search
{
«query»: {
«query_string»: {
«query»: «ERROR\-2026\.08\.07»,
«default_field»: «message»,
«lenient»: true
}
}
}
С использованием match (без экранирования):
GET logs/_search
{
«query»: {
«match»: {
«message»: «ERROR-2026.08.07»
}
}
}
Если анализатор оставляет дефис и точки внутри токена, оба запроса вернут одинаковый результат. Если же анализатор разбивает по этим символам, то match вернёт документы, где присутствуют любые из токенов ERROR, 2026, 08, 07 (по умолчанию OR). Чтобы получить точное совпадение в этом случае, лучше использовать поле keyword или match_phrase.
Пример 2: Поиск product‑кода со звёздочкой (wildcard)
Нужно найти все товары, код которых начинается с ABC- и заканчивается на три цифры, например ABC-123.
Только query_string поддерживает wildcard напрямую:
GET products/_search
{
«query»: {
«query_string»: {
"query": "ABC-*",
"default_field": "sku"
}
}
}
Здесь звёздочка воспринимается как wildcard, а дефис – как обычный символ (предполагаем, что он не экранирован, так как не является оператором NOT в данном контексте).
Match не может выполнить такой запрос напрямую; для подобных задач потребуется либо:
Оба метода – query_string и match – имеют своё место в арсенале Elasticsearch:
При наличии спецсимволов в поисковом запросе ключевым моментом является понимание того, как эти символы интерпретируются выбранным парсером. Если вы можете гарантировать корректное экранирование – query_string даст вам доступ к расширенным возможностям Lucene. Если же вы работаете с открытыми формами ввода, где пользователь может вводить любые символы, то match (или match_phrase) обычно является более надёжным выбором.
Надеемся, данная сравнительная статья поможет вам выбрать оптимальный метод поиска для ваших сценариев использования Elasticsearch при работе со специальными символами.