Как реализовать систему поиска автозамены / альтернативного правописания с полнотекстовым логическим режимом PHP и MySQL для MVP

NB:

  • Этот вопрос поднимался много раз, но, прежде чем голосовать, пожалуйста, найдите время, чтобы прочитать следующее. Если этот вопрос повторяется, это может означать, что для такой повторяющейся ситуации, как эта, нет однозначного или четкого приемлемого ответа. Если вы понизили голос, объясните, почему.

  • Я мог бы задать этот вопрос dba.stackexchange.com, но мой вопрос касается примера с кодом.

  • Не думайте, что у меня более 10 лет опыта (или у других людей, имеющих такой же вопрос). Я начал программировать 2 года назад, поэтому, пожалуйста, будьте терпимы.

  • Я мог бы использовать словарь, такой как Pspell, Aspell или Hunspell, но этот случай не относится должным образом к названиям компаний или городам. Кроме того, я не хочу запрашивать в БД все предложенные исправления (особенно при запуске заголовка через каждые 300 мс) ( больше вопросов об этих словарях)

  • Я мог бы использовать дополнительную поисковую систему, такую ​​как Elasticsearch или Sphinx, но у меня нет финансовых или человеческих ресурсов, выделенных для этого MVP. Как предполагается в этом ответе, полный текст MySQL должен быть достаточно и намного менее сложным.

Доступные технологии:

MySQL 5.7 InnoDB с логическим режимом полнотекстового индекса на желаемых полях, PHP 7.0 с php-fpm, VPS с Centos 7, corejs-typeahead

Цель:

Я хочу вернуть из MySQL результаты поиска пользователя, будь то правильный поиск или поиск с ошибкой.

Пример распространенных проблем:

ДЕФИС

  • слова с дефисами '-' раздражает поиск при частичном поиске.

Потенциальное решение:

  • Мне нужно было бы обернуть поисковый запрос в "", чтобы найти фразу (см. [Введите описание ссылки здесь][примеры от man]. Тем не менее, он не найдет компанию с именем '"le dé-k-lé" "из-за в ft_min_word_len=3 AND "de" и "le" - это стоп-слова (слишком часто встречаются во многих языках)

  • Я мог бы, но я не буду вдаваться в следующие решения, потому что я недостаточно квалифицирован или это неуместно. Как предложено руководством MySQL, чтобы Изменить источник MySQL или Изменить файл набора символов или Добавить новый порядок сортировки. Например, если я хочу использовать оператор минус (-), чтобы отфильтровать некоторые слова в будущем, это больше не будет возможно.

АПОСТРОФ / ЕДИНАЯ ЦИТАТА

  • Слова с апострофом часто ищутся без апострофов (особенно на мобильных телефонах). Например, "A'trego" будет вводиться как "atrego". Это будет определенно пропущено полнотекстовым индексом, так как "A'trego" считается двумя словами "a" и "trego"

Двойные письма пропущены

  • слова с двойными буквами часто пропускаются или ошибаются пользователем. Например, "Cerrutti" может быть с ошибкой "Cerutti" или "Cerruti" и т. Д.

Потенциальное решение:

  • Я мог бы использовать SOUNDEX(), но он в основном предназначен для английского языка
  • Я мог бы использовать функцию Левенштейна, но это было бы медленно для больших наборов данных (например, таблица со всеми европейскими городами). Кажется, что он должен сделать полное сканирование, в сочетании с typehhead, это определенно не тот путь. Хотя некоторые предложения интересны здесь и здесь

ЭКЗОНИМЫ И ПЛЮРАЛЬНЫЕ ФОРМЫ

  • Экзонимы могут быть сложны в поиске (с точки зрения пользователя). Например, итальянский город Флоренция называется по-немецки Флоренц, по-французски Флоренция и т. Д. Люди часто переключаются с экзонима на местное имя, когда они находятся в самом городе. Экзонимы не будут обрабатываться должным образом предыдущими алгоритмами. Кроме того, не очень удобно иметь название города без его экзонимов. Это не хорошо ни для i18n.

Потенциальное решение:

  • Самодельный словарь, использующий Pspell или другие подобные библиотеки, возвращает строку, которая хранится и индексируется в MySQL.

ДИАКРИТИЧЕСКИЕ ХАРАКТЕРИСТИКИ - аналогично экзонимам, с ними может быть сложно справиться То же самое для i18n. Например, попробуйте найти ресторан в Лодзи в Польше, используя обычную клавиатуру. Польский и английский человек определенно не будут подходить к этой строке одинаково.

Потенциальное решение: - Потенциальное решение уже управляется во внешнем интерфейсе отображением, используемым библиотекой corejs-typeahead. Остальное очищается с помощью PHP $strCleaned = iconv('UTF-8', 'utf-8//TRANSLIT', $str);

СОКРАЩЕНИЯ И АКРОНИМЫ - Сокращения используются взаимозаменяемо для названий компаний и особенно для голубых фишек. Например, LVMH, HP, GM, GE, BMW. То же самое касается городов. Не возвращать компанию или город при поиске с помощью аббревиатур - большой провал с точки зрения пользовательского опыта.

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

Этот список не является исчерпывающим ни в вопросах, ни в потенциальных решениях. Я буду рад завершить его, если потребуется.

МОЕ РЕШЕНИЕ

Мое решение вдохновлено и извлечено из ответа здесь

По сути, перед каждым поиском пользовательский ввод должен быть лишен символов, таких как апостроф, дефис; упрощено удаление похожих последовательных букв.

Эти очищенные альтернативные слова будут сохранены в столбце с индексом полнотекстового индекса.

Это решение довольно простое и адекватно отвечает моим требованиям. Но мой короткий опыт подсказывает, что я должен быть осторожен, поскольку он определенно страдает недостатками (которые я еще не определил).

Ниже приведена упрощенная версия моего кода.

PHP

// Get input from the typeahead searched word
$query = (!empty($_GET['q'])) ? strtolower($_GET['q']) : null;

// end the script if empty query
if (!isset($query)) {
    die('Invalid query.');
}

// Clean and Strip input
$query = trim($query);
$query = str_replace("'","",$query);
$query = str_replace("-","",$query);
$query = preg_replace('{(.)\1+}','$1',$query);

// filter/sanitize query
if (!preg_match("/^([0-9 '@&\-\.\pL])+$/ui", $input[$field]) !== false) {exit;}
$query = mysqli_real_escape_string($conn, $query); // I will switch to PDO prepared statement soon as mysqli_real_escape_string do not offer enough protection

MySQL Query

SELECT DISTINCT
company.company_name,
MATCH (company_name, company_alternative) AGAINST ('$query*' IN BOOLEAN MODE) AS relevance

FROM company

WHERE 
MATCH (company_name, company_alternative) AGAINST ('$query*' IN BOOLEAN MODE)
AND relevance > 1

ORDER BY
CASE
WHEN company_name = '$query' THEN 0
WHEN company_name LIKE '$query%' THEN 1
WHEN company_name LIKE '%$query' THEN 2
ELSE 3
END

LIMIT 20

MySQL Table

Напоминаю, что я получил полнотекстовый индекс из двух столбцов (company_name,company_alternative)

**company_name**    |   **company_alternative**
l'Attrego           |   lattrego latrego attrego atrego
le Dé-K-Lé          |   dekle dekale decale
General Electric    |   GE  

ЯЗЫКИ моего решения, которое я определил

  • Альтернативные слова не будут содержать распространенных орфографических ошибок, пока я не добавлю их вручную в alternative_name колонка или процесс машинного обучения. Таким образом, сложный в управлении и не масштабируемый (этот недостаток может быть устранен без особых сложностей с машинным обучением, так как я уже собираю все поисковые запросы).
  • Я должен управлять динамическим и сложным списком стоп-слов
  • Я должен восстановить индексы из-за снижения ft_min_word_len до 2

Итак, мой вопрос, как реализовать систему поиска автозамены / альтернативного правописания с полнотекстовым логическим режимом PHP и MySQL для MVP?, может быть перефразировано,

  • Является ли мое решение наименее масштабируемым?

  • Вы видите недостатки, которых я не вижу?

  • Как я могу улучшить этот подход, если он разумный?

0 ответов

Другие вопросы по тегам