Назад

Разбиение слитных поисковых запросов: смена класса, словарь, фуззи и n-граммный индекс

Слитный запрос — это строка, в которой поисковая система потеряла границы слов полностью или частично: powershotsd500, newyorktimessubscription, adidasultraboost, квартиравцентре. Здесь ломается не ранжирование, а самый ранний слой: токенизация. Исторически эту задачу решали не одной “умной” моделью, а каскадом простых и жестких механизмов: разбиением по смене класса символов, словарным разбиением через динамическое программирование, фуззи-коррекцией по расстоянию редактирования и быстрым отбором кандидатов через символьный k-граммный индекс. В этой статье разберем основные механизмы разбиение слитных написаний слов.

1. Разбиение по смене класса

Это самый простой способ найти границы в слитном запросе. Система режет строку там, где меняется тип символов: буквы сменяются цифрами, строчные — заглавными, либо встречается разделитель вроде дефиса. Поэтому Wi-Fi превращается в Wi и Fi, PowerShot — в Power и Shot, SD500 — в SD и 500.

Этот метод просто использует видимые признаки границы. В этом его сила: работает быстро, стоит дешево, хорошо снимает самые очевидные случаи.

В поиске такой механизм обычно стоит в самом начале. Он не решает задачу целиком, а подготавливает строку для следующих этапов. В Lucene за это отвечают стандартный токенизатор и фильтры вроде WordDelimiterFilter и WordDelimiterGraphFilter. Первый режет строку на части, второй следит, чтобы после такого разбиения поиск по фразе не сломался.

Но возможности у этого подхода узкие. Он помогает только там, где граница уже видна в самой строке. Если пользователь написал newyorktimes или александрверещагинизрекламы, такой метод сам по себе бесполезен: никаких внешних признаков границы там нет.

2. Словарное разбиение

По-настоящему задача начинается там, где в строке нет видимых границ. Тогда система уже не может опираться на регистр, цифры или дефисы и идет другим путем: перебирает возможные куски строки, сверяет их со словарем и выбирает лучший вариант разбиения. Обычно это делается через динамическое программирование: для каждого варианта считается вес, а потом выбирается разбор с наибольшим суммарным баллом. Чаще всего этот балл строится на частоте слов и фраз. Чем привычнее кусок для языка или для поиска, тем выше его вес.

На простых примерах это работает хорошо. Строку wheninrome система разобьет как when in rome, потому что такая последовательность слов встречается чаще и выглядит естественнее, чем любые другие комбинации.

Но здесь быстро выясняется проблема: обычного словаря слов недостаточно. Поисковый запрос почти никогда не состоит только из “нормальных” слов. В нем есть бренды, названия компаний, модели товаров, география, имена людей, устойчивые сочетания. Если система знает только отдельные слова, она начинает резать строку формально правильно, но поисково бесполезно.

Поэтому сильные системы давно перешли от словаря слов к словарю слов и фраз. Это уже не просто набор лексем, а база сущностей и устойчивых сочетаний. Иначе запрос вроде newyorktimessubscription развалится на куски, которые по отдельности выглядят допустимо, но вместе не держат смысл. Если же в словаре есть фраза new york times, система сохранит ее как единый блок и уже потом достроит остальное разбиение.

Нормальная словарная сегментация держится на двух вещах. Первая: в словаре должны быть не только одиночные слова, но и многословные конструкции. Вторая: мало знать, что кусок “существует”. Надо еще понимать, насколько он типичен именно для запросов и корпуса. Одно дело — редкое слово, которое формально есть в словаре. Другое — фраза, которую пользователи действительно вводят и которую документы действительно содержат.

У этого подхода есть и слабое место. Он любит короткие и частые куски. Из-за этого система может разрезать строку так, что формально все части будут словарными, а смысл развалится. В сложных языках проблема еще хуже: слова в составе композитов меняют форму, сокращаются, получают соединительные элементы. В итоге точное словарное совпадение начинает врать. Система видит знакомые куски, но собирает из них не то, что имел в виду человек.

3. Фуззи-механизмы

Фуззи — не способ разбиения сам по себе. Он нужен в другом месте: когда система уже почти поняла, какой тут должен быть сегмент, но строка написана с шумом. Человек опечатался, пропустил букву, добавил лишнюю, перепутал порядок, написал в транслите или в искаженной форме. В таких случаях точное совпадение не срабатывает, и без фуззи разбор просто рассыпается.

Смысл тут простой: система ищет не только точные совпадения, но и близкие варианты. Если пользователь написал iphon, она должна догадаться, что скорее всего имелся в виду iphone. Если написал adiddas, нужно поднять кандидата adidas, а не выбросить фрагмент как мусор.

Но здесь есть жесткое ограничение. Фуззи нельзя пускать по всему словарю без фильтрации. Если разрешить слишком много правок или проверять каждый кусок строки против всех слов подряд, система захлебнется. Кандидатов станет слишком много, мусора станет еще больше, а скорость упадет. Поэтому фуззи обычно работает только на коротком списке кандидатов, который уже подготовили предыдущие этапы: разбиение по смене класса и словарная сегментация.

На практике это выглядит так: система сначала находит вероятные куски строки, а потом для каждого куска допускает небольшое отклонение от словарной формы. Совпадение не обязано быть точным, но за каждую правку назначается штраф. Чем сильнее искажение, тем ниже оценка. Поэтому фуззи не ломает разбор, а аккуратно дотягивает его там, где точная модель не справилась.

Это и есть его роль: закрыть зазор между точным совпадением и полным промахом. Без него поиск слишком хрупкий. С ним — начинает нормально переживать реальный пользовательский ввод. Но если снять ограничения по длине фрагмента, по частоте кандидатов и по числу допустимых правок, фуззи быстро превращается из полезного механизма в источник мусора.

4. N-граммный индекс

Тут часто мешают в одну кучу две разные вещи.

Первая — n-граммные частоты. Это статистика по кускам слов и фраз. Она нужна, чтобы понять, насколько сочетание вообще похоже на что-то живое. Например, new york times выглядит как нормальная устойчивая фраза, а случайная склейка слов — нет.

Вторая — k-граммный индекс. Это уже не про смысл, а про быстрый поиск похожих строк. Он нужен, чтобы не сравнивать каждый кусок запроса со всем словарем целиком.

Работает это так: каждое слово в словаре заранее режется на короткие последовательности символов одинаковой длины. То же самое делается с фрагментом запроса. Потом система смотрит, у каких слов пересечение по таким кускам самое большое, и берет только их. И уже на этом коротком списке считает более дорогую метрику вроде edit distance.

Смысл тут чисто инженерный: сначала быстро отсечь почти все лишнее, потом точно проверить немногое. Иначе фуззи-поиск по большому словарю будет слишком медленным и слишком грязным.

Поэтому n-граммный индекс обычно работает не вместо фуззи, а перед ним. Он подбирает кандидатов, фуззи их дожимает и ранжирует.

В поисковых движках это давно стало стандартной техникой. Один вариант режет слово на все возможные n-граммы, другой — только на префиксные. Полный набор полезен, когда надо найти похожую форму внутри строки. Префиксный — когда надо быстро проверить начало слова, как в автодополнении или поиске по первым символам.

Для слитных запросов это особенно полезно там, где точное совпадение уже не работает. Если в строке есть искажение, усечение или промежуточная морфологическая форма, n-граммный индекс все равно может вытащить близкого кандидата. За счет этого система находит не только точные словарные формы, но и слова, до которых пользователь “почти дошел”, но написал криво.

Именно поэтому n-граммный индекс в таких задачах — не вспомогательная мелочь, а рабочий слой отбора кандидатов. Без него фуззи слишком дорогой. С ним — становится управляемым.

5. Как это собирается в рабочую систему

В нормальной системе не выбирают что-то одно. Все это собирается в цепочку.

Сначала идет самый дешевый этап: строку режут по очевидным внешним признакам. По смене регистра, по цифрам, по дефисам, по другим разделителям. Это позволяет сразу вытащить простые случаи вроде PowerShotSD500, где границы уже частично видны.

Потом включается словарное разбиение. Система перебирает возможные куски строки, строит из них варианты разбора и через динамическое программирование выбирает лучший путь среди точных совпадений. Если все хорошо, на этом этапе запрос уже можно разобрать без догадок.

Если точного совпадения нет или оно выглядит слабым, подключается n-граммный индекс. Он не решает задачу сам, а быстро находит близкие словарные кандидаты для проблемных участков. После этого фуззи-механизм или модель с edit distance проверяет, насколько эти кандидаты действительно похожи на исходный фрагмент, и штрафует каждую правку.

Над всем этим стоит общий скоринг. Он решает, какой разбор в итоге считать лучшим. Там учитываются частоты слов и фраз, словарь брендов и моделей, заголовки, статистика из логов запросов, штрафы за незнакомые куски и штрафы за слишком мелкое дробление. Иначе система начнет либо резать строку слишком агрессивно, либо, наоборот, удерживать слитную форму там, где ее давно надо было развалить.

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

Если в запросе уже есть пробелы, этот каркас никуда не девается. Просто задача поднимается на уровень выше. Сначала система разбирает отдельные слова и проблемные склейки внутри них, а потом уже решает, какие соседние слова надо держать вместе как одну фразу. То есть разбиение слитного запроса и сборка фраз — это не две разные задачи, а два шага одного процесса.

6. Ограничения и типовые провалы

Первая ошибка — надеяться только на разбиение по смене класса. Оно полезно, но работает лишь там, где граница уже видна: заглавная буква, цифры, дефис, код модели. На настоящей слитности вроде newyorktimes или купитьайфончехол этот метод беспомощен.

Вторая ошибка — строить словарь только из обычных слов. Для поиска этого мало. Люди ищут не “слова языка”, а бренды, модели, названия магазинов, городов, категорий, серий товаров и устойчивые фразы. Если этого нет в словаре, система будет резать строку формально правильно, но мимо смысла.

Третья ошибка — слишком широко пускать фуззи. Если не ограничивать длину фрагмента, число правок и размер списка кандидатов, поиск быстро тонет в мусоре. Короткие куски начинают совпадать со всем подряд, и вместо полезной подстраховки получается свалка.

Четвертая ошибка — считать, что любое разбиение уже полезно. Это не так. Строку можно разрезать на словарные куски и все равно испортить смысл. Формально разбор будет допустимым, а для поиска — вредным. Такие случаи давно известны на задачах compound splitting: система видит знакомые части, но собирает из них не то, что хотел пользователь.

Отдельно стоит проблема оценки качества. Сравнивать результат только с ручной разметкой слишком удобно и слишком слабо. Можно получить красивое совпадение с человеческой разметкой и при этом никак не улучшить поиск. Для поисковой системы важен не сам вид разбиения, а его эффект на выдачу.

Поэтому главный вопрос всегда один: после сегментации поиск стал лучше или нет. Если выросла полнота, улучшилось ранжирование, стало меньше нулевых результатов — значит механизм работает. Если разбиение выглядит аккуратно только в таблице с примерами, а качество не растет, толку от него нет.

7. Заключение

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

Разбиение по смене класса находит самые очевидные границы. Словарное разбиение дает основной каркас и собирает запрос в осмысленные части. Фуззи подстраховывает там, где пользователь написал криво, и не дает системе развалиться на опечатках и шуме. N-граммный индекс сам ничего не “понимает”, но резко ускоряет поиск близких кандидатов и делает всю схему пригодной для реальной нагрузки.

Сильные старые системы работали именно так: не пытались решить задачу одним красивым трюком, а собирали цепочку из простых механизмов, словарей, частот и штрафов. Это и давало результат.

Как только кто-то пытается заменить этот каскад одной “умной” техникой, начинаются обычные проблемы: система либо режет строку слишком агрессивно, либо пропускает нужные варианты, либо начинает тащить в поиск мусор.

Нормальное разбиение — это не один алгоритм. Это аккуратно собранная система, где каждый слой закрывает слабость предыдущего.

Александр Верещагин
Александр Верещагин
https://vospriyatie.com
Александр В. Верещагин — маркетинговый стратег, основатель и идейный руководитель бюро «Дело Восприятия». Его специализация — стратегии позиционирования и продвижения для рынков, где конкуренция высока, доверие к рекламе снижается, а видимость бренда все сильнее зависит от алгоритмов. В своей практике он соединяет классические маркетинговые принципы с латеральным и антикризисным подходом, адаптируя их к новой цифровой среде. Александр работает на стыке смысловой стратегии и прикладного продвижения: от формирования сильной идеи бренда до SEO, ASO, AEO и GEO — направлений, связанных не только с поисковой выдачей, но и с присутствием бренда в ответах ассистентов и нейросетевых систем. Его фокус — не просто продвижение, а управление тем, как бренд находят, понимают и выбирают в условиях алгоритмической конкуренции.

Мы используем необходимые cookie для работы сайта. Яндекс.Метрика и рекламные блоки Яндекса включаются только после согласия. Подробнее в политике.