Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Транслитерация и раскладка клавиатуры в поиске

Транслитерация и раскладка: поиск при неверной раскладке

Поиск при вводе в неверной раскладке: соответствие клавиш QWERTY и ЙЦУКЕН, транслитерация, нормализация Unicode и обработка запроса.

Прямой ответ

Пользователь вводит кириллический запрос, не переключив раскладку, и отправляет «yjnebr» вместо «ноутбук». Расстояние между такими строками велико, поэтому нечёткий поиск не помогает: требуется преобразование по таблице соответствия клавиш.

EN = "qwertyuiop[]asdfghjkl;'zxcvbnm,."
RU = "йцукенгшщзхъфывапролджэячсмитьбю."
MAP = dict(zip(EN, RU)) | dict(zip(RU, EN))

def switch_layout(s: str) -> str:
    return "".join(MAP.get(c, c) for c in s.lower())

switch_layout("yjnebr")   # "ноутбук"
switch_layout("ноутбук")  # "yjnbye"

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

Транслитерация решает другую задачу — замену букв одного алфавита сочетаниями другого:

Задача Пример
Смена раскладки yjnebr → ноутбук
Транслитерация noutbuk → ноутбук
Обратная транслитерация ноутбук → noutbuk

Различие существенно: при смене раскладки соответствие взаимно однозначно и определяется клавишей, а при транслитерации одно кириллическое письмо может записываться разными способами — «ю» как yu, ju либо û.

Нормализация Unicode выполняется до сравнения строк, поскольку один видимый символ может быть представлен разными последовательностями кодов; о кодировках — в статье про Unicode в Python.

import unicodedata
unicodedata.normalize("NFC", text)   # композиция: ё как один символ
unicodedata.normalize("NFD", text)   # декомпозиция: буква + диакритика

Где применять преобразование раскладки

Преобразование выполняется либо при разборе запроса, либо при индексации, и выбор определяет объём индекса.

При разборе запроса. Запрос выполняется в двух вариантах — исходном и преобразованном, а результаты объединяются. Индекс не увеличивается, но каждый запрос выполняется дважды.

При индексации. В индекс добавляется вариант в другой раскладке. Объём индекса растёт, а запрос выполняется один раз.

На клиенте. Интерфейс определяет неверную раскладку и предлагает исправление. Сервер не меняется, но преобразование зависит от реализации интерфейса.

Распространённый подход — выполнение обоих запросов и объединение результатов с понижением веса преобразованного варианта:

{
  "query": {
    "bool": {
      "should": [
        {"match": {"title": {"query": "yjnebr", "boost": 2}}},
        {"match": {"title": {"query": "ноутбук"}}}
      ],
      "minimum_should_match": 1
    }
  }
}

Исходная форма получает больший вес, поэтому при совпадении обоих вариантов документ с прямым совпадением остаётся выше.

Определение неверной раскладки выполняется эвристически: строка состоит преимущественно из символов одного алфавита, но не содержит слов этого языка. Проверка по словарю надёжнее, но требует словаря.

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

Таблица соответствия и её границы

Таблица клавиш покрывает буквы основного алфавита, но три группы символов требуют отдельного решения.

Цифры и знаки препинания. Клавиши цифр совпадают в обеих раскладках, а знаки отличаются: точка с запятой на клавише «ж» в русской раскладке соответствует точке с запятой в латинской, но символ «.» и «/» распределены иначе. Таблица составляется по фактической раскладке, а не по предположению.

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

Буквы, отсутствующие в другой раскладке. Русская «ъ» и «ь» не имеют соответствия в латинской раскладке на отдельной клавише, поэтому при преобразовании в латиницу остаются без изменения. Обратное преобразование таких символов невозможно, и запрос, содержащий их, не восстанавливается.

Практическое следствие: таблица проверяется по описанию раскладки, а результат преобразования — на наборе реальных запросов. Запрос, который после преобразования не находится, указывает на пропущенное соответствие либо на другую причину пустой выдачи.

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

Практика: обработка ввода в неверной раскладке

1. Нормализуйте Unicode до сравнения. Разные представления одного символа приводят к несовпадению строк, которые выглядят одинаково.

2. Приводите к нижнему регистру до преобразования. Таблица соответствия составляется для одного регистра, поэтому преобразование после приведения упрощает таблицу.

3. Выполняйте оба варианта запроса. Исходная форма сохраняет преимущество, а преобразованная находит документы при неверной раскладке.

4. Понижайте вес преобразованного варианта. Без понижения документ с совпадением по преобразованной форме конкурирует с прямым совпадением.

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

6. Не применяйте преобразование к кодовым полям. Артикулы и идентификаторы содержат латиницу осознанно, и преобразование ломает точное совпадение.

7. Сочетайте с допуском опечаток. Неверная раскладка и опечатка встречаются вместе; о нечётком поиске — в статье про fuzzy-поиск.

Рекомендации:

  1. Фиксируйте таблицу соответствия в коде. Раскладка определяется стандартом, поэтому таблица проверяется по нему, а не составляется на глаз.
  2. Учитывайте раскладки других языков. Украинская, белорусская и другие раскладки содержат клавиши, отсутствующие в русской, поэтому таблица требует расширения.
  3. Измеряйте влияние на задержку. Два запроса вместо одного увеличивают время ответа, что критично для подсказок ввода.
  4. Логируйте срабатывания. Частота применения преобразования показывает, насколько проблема актуальна для конкретной аудитории.
  5. Проверяйте поведение на пустом результате. Преобразование выполняется при пустой либо короткой выдаче, а не безусловно.

Практический сценарий: пустая выдача при вводе в латинской раскладке

Контекст: пользователи сообщали, что поиск не находит товары при вводе названия латиницей.

  1. Диагностика. Запрос «yjnebr» возвращал пустой результат, а «ноутбук» — полный список. Нечёткий поиск с допуском двух правок не находил совпадений, поскольку расстояние между строками превышало порог.
  2. Причина. Соответствие между строками определяется раскладкой клавиатуры, а не редакторским расстоянием, поэтому механизмы нечёткого поиска не применимы.
  3. Действия. (а) Добавили таблицу соответствия клавиш и функцию преобразования; (б) включили нормализацию Unicode и приведение к нижнему регистру до преобразования; (в) реализовали выполнение двух вариантов запроса с понижением веса преобразованного; (г) применили преобразование только при пустом либо коротком результате, чтобы не увеличивать задержку обычных запросов; (д) собрали статистику срабатываний и проверили, что ложные преобразования не приводят к нерелевантной выдаче; (е) добавили набор запросов с неверной раскладкой в тесты.
  4. Результат. Запросы в неверной раскладке находят документы, а обычные запросы выполняются без дополнительной задержки.

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

FAQ

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

Нужна ли нормализация Unicode перед преобразованием? Да, поскольку один видимый символ может быть представлен разными последовательностями кодов, и сравнение без нормализации даёт несовпадение.

Где выполнять преобразование — в индексе или в запросе? В запросе, если объём индекса критичен; в индексе, если важнее скорость ответа. Выбор определяется нагрузкой и размером данных.

Применяется ли преобразование к артикулам? Нет, кодовые поля содержат латиницу осознанно, и преобразование ломает точное совпадение.

Источники: Unicode Standard Annex 15 (Normalization Forms), Annex 35 (LDML), Python unicodedata — ссылки в шапке.