В современных приложениях часто требуется быстро находить записи по частичному или полному совпадению телефонного номера. В случае с «магами» (контактами, хранящимися в Elasticsearch) удобно воспользоваться запросом query_string, который позволяет задавать сложные условия поиска в одной строке, включая префиксные, суффиксные и фразовые совпадения.
Почему именно query_string?
- Поддерживает синтаксис, близкий к Lucene (например,
*,?,~, операторы AND, OR, NOT). - Можно комбинировать поиск по нескольким полям (ФИО, номер, заметка) без необходимости писать несколько отдельных запросов.
- Лёгко интегрируется в пользовательский интерфейс: пользователь вводит строку, а приложение передаёт её напрямую в query_string.
Подготовка данных: какие поля нужны
Для поиска магов по номерам телефонов обычно достаточно трёх полей:
- full_name – ФИО мага.
- phone – очищенный номер телефона (только цифры).
- note – произвольная заметка, где может храниться дополнительная информация.
Перед индексацией рекомендуется привести номер к единому формату: удалить все пробелы, дефисы, скобки и символ «+», оставить только цифры. Это упрощает дальнейшую токенизацию.
Настройка анализатора для поля phone
Ключевой момент – обеспечить возможность поиска:
- по полному номеру;
- по префиксу (например,
8999**); - по суффиксу (последние 4‑6 цифр);
- по произвольной подстроке внутри номера.
- char_filter phone_clean удаляет всё, кроме цифр.
- tokenizer phone_keyword оставляет строку как одно целое (не разбивает на токены по пробелам).
- filter phone_edge_ngram генерирует все начальные подстроки (префиксы) длиной от 2 до .
- filter phone_reverse_edge работает аналогично, но над перевёрнутой строкой, тем самым создавая суффиксы.
- В результате поле phone содержит токены, покрывающие любые префиксы и суффиксы номера, что позволяет эффективно использовать query_string с wildcard‑поиском.
- полный номер:
###-###-####; - префикс:
8999; - суффикс:
5678; - любую часть:
456; - комбинацию с другими полями:
Иванов AND phone:8912. - Часть query_string принимает строку, где можно использовать операторы AND, OR, скобки и wildcard‑символы (любое количество символов) и
?(один символ). - Поле phone уже содержит префикс‑ и суффикс‑ngram‑токены, поэтому запрос
phone:8999будет быстро находить все номера, начинающиеся с8999. - Если нужно искать по суффиксу, достаточно указать
phone:*5678– обратный ngram‑фильтр обеспечит соответствие. - Параметр default_operator задаёт, как обрабатывать условия без явного оператора (по умолчанию OR, но мы ставим AND для более строгого совпадения);
- Ограничьте размер edge_ngram: слишком большие
max_gramувеличивают объём индекса. Для российских номеров достаточно 10‑. - Используйте doc_values для поля phone, если планируете сортировать или агрегировать по номеру.
- Регулярно проверяйте размер индекса через
_cat/indices?vи при необходимости пересоздавайте его с более жёсткими лимитами. - Для очень больших наборов данных можно добавить отдельное подполе phone.prefix с анализатором только edge_ngram (префиксы) и phone.suffix с обратным ngram – тогда запрос будет обращаться к нужному полю напрямую, экономя ресурсы.
Для этого удобно комбинировать keyword‑токенизатор (чтобы сохранять исходную строку) с фильтрами edge_ngram и reverse‑edge_ngram. Ниже пример настроек анализатора, которые можно разместить в разделе settings индекса:
settings:
{
«analysis»: {
«char_filter»: {
«phone_clean»: {
«type»: «pattern_replace»,
«pattern»: «[^0-9]»,
«replace»: «»
}
},
«tokenizer»: {
«phone_keyword»: {
«type»: «keyword»
}
},
«filter»: {
«phone_edge_ngram»: {
«type»: «edge_ngram»,
«min_gram»: 2,
«max_gram»: 20
},
«phone_reverse_edge»: {
«type»: «edge_ngram»,
«min_gram»: 2,
«max_gram»: 20
}
},
«analyzer»: {
«phone_analyzer»: {
«char_filter»: [«phone_clean»],
«tokenizer»: «phone_keyword»,
«filter»: [«phone_edge_ngram», «phone_reverse_edge»]
}
}
}
}
Что делает эта конфигурация:
Маппинг индекса
Пример маппинга, где поле phone использует наш анализатор, а остальные поля – стандартные:
mappings:
{
«properties»: {
«full_name»: { «type»: «text», «analyzer»: «standard» },
«phone»: {
«type»: «text»,
«analyzer»: «phone_analyzer»
},
«note»: { «type»: «text», «analyzer»: «standard» }
}
}
Формирование запроса query_string
Теперь, когда данные готовы, можно построить запрос. Пользователь может ввести:
Пример JSON‑запроса к Elasticsearch:
{ «query»: {
«query_string»: {
«query»: «(full_name:Иванов OR note:заговор) AND phone:8999»,
«default_operator»: «AND»
}
}
}
Пояснения:
Советы по производительности
Использование query_string в сочетании с правильно настроенным анализатором (char_filter + keyword + edge_ngram/reverse_edge_ngram) позволяет реализовать гибкий и быстрый поиск контактов магов по телефонным номерам: по полному номеру, по префиксу оператора, по последним цифрам или по любой подстроке. Такой подход легко масштабируется, поддерживает сложные комбинации с другими полями (ФИО, заметка) и остаёться понятен конечным пользователям благодаря привычному синтаксису wildcard‑поиска.
Если вам понадобится дополнительно искать по фонетическим вариантам или обрабатывать опечатки в номерах, можно добавить фильтр phonetic или fuzzy в запрос, но для большинства задач, описанных выше, представленная конфигурация будет более чем достаточной.