NB:
Этот вопрос поднимался много раз, но, прежде чем голосовать, пожалуйста, найдите время, чтобы прочитать следующее. Если этот вопрос повторяется, это может означать, что для такой повторяющейся ситуации, как эта, нет однозначного или четкого приемлемого ответа. Если вы понизили голос, объясните, почему.
Я мог бы задать этот вопрос dba.stackexchange.com, но мой вопрос касается примера с кодом.
Не думайте, что у меня более 10 лет опыта (или у других людей, имеющих такой же вопрос). Я начал программировать 2 года назад, поэтому, пожалуйста, будьте терпимы.
Я мог бы использовать словарь, как Pspell, Заклинание или же Hunspell но этот случай не распространяется должным образом на названия компаний или городов. Более того, я не хочу запрашивать в БД все предложенные исправления (особенно при запуске заголовка каждые 300 мс) (больше вопросов об этих словарях)
Я мог бы использовать дополнительную поисковую систему, такую как Elasticsearch или же сфинкс но у меня нет финансовых или человеческих ресурсов, выделенных для этого 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 или же Изменить файл набора символов или же Добавить новое сопоставление. Например, если я хочу использовать оператор минус (-) для фильтрации некоторых слов в будущем, это больше не будет возможно.
АПОСТРОФ / ЕДИНАЯ ЦИТАТА
Двойные письма пропущены
Потенциальное решение:
ЭКЗОНИМЫ И ПЛЮРАЛЬНЫЕ ФОРМЫ
Потенциальное решение:
диакритические
— как и в случае с экзонимами, это может быть трудно для пользователя. То же самое для i18n. Например, попробуйте найти ресторан в Лодзи в Польше, используя обычную клавиатуру. Польский и английский человек определенно не будет подходить к этой строке одинаково.
Потенциальное решение:
— Потенциальное решение уже управляется во внешнем интерфейсе отображением, используемым библиотекой corejs-typeahead. Остальное очищается с помощью PHP $strCleaned = iconv('UTF-8', 'utf-8//TRANSLIT', $str);
СОКРАЩЕНИЯ & СОКРАЩЕНИЯ
— Сокращения используются взаимозаменяемо для названий компаний и особенно для голубых фишек. Например, LVMH, HP, GM, GE, BMW. То же самое касается городов. Невозможность вернуть компанию или город при поиске с помощью аббревиатур является большой ошибкой с точки зрения пользовательского опыта.
Потенциальное решение:
— Первый, ft_min_word_len
следует уменьшить до двух символов.
— Во-вторых, список стоп-слов должен быть реализован
— В-третьих полнотекстовый индекс перестроен.
— Я не вижу другой устойчивой альтернативы
Этот список не является исчерпывающим ни в вопросах, ни в возможных решениях.
Я буду рад завершить его, если потребуется.
Мое решение вдохновлено и экстраполировано из ответ здесь
По сути, перед каждым поиском пользовательский ввод должен быть лишен символов, таких как апостроф, дефис; упрощено удаление похожих последовательных букв.
Эти очищенные альтернативные слова будут сохранены в столбце с индексом полнотекстового индекса.
Это решение довольно простое и адекватно отвечает моим требованиям. Но мой короткий опыт подсказывает, что я должен быть осторожен, поскольку он определенно страдает недостатками (которые я еще не определил).
Ниже приведена упрощенная версия моего кода.
// 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
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
Напоминаю, что я получил полнотекстовый индекс из двух столбцов (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?, можно перефразировать,
Является ли мое решение наименее масштабируемым?
Вы видите недостатки, которых я не вижу?
Как я могу улучшить этот подход, если он разумный?
Задача ещё не решена.
Других решений пока нет …