Я пытаюсь создать поиск товаров для своего сайта, где пользователь может искать товары на нескольких языках и (надеюсь) получить нечеткие результаты поиска, если нет точного соответствия.
pro_search
которой есть столбцы id, pro_id, en, de, es, fr, it
.pro_id
относится к идентификатору продуктов в их собственной таблице.en, de, es, fr, it
имеют перевод мета каждого продукта на разных языках.$term
- поисковый термин.$lang
относится к выбранному пользователем языку Итак, сначала я делаю простой SQL-запрос "LIKE", чтобы посмотреть, есть ли совпадения, если нет результатов из этого, я запрашиваю все продукты и создаю массив, отсортированный по их сходству, с помощью функции similar_text()
Например, я ищу "рубашка", это нормально, если мета для этого продукта включает в себя только слово "рубашка", но если мета включает "футболку с синей маркой", это более наглядно и дает пользователю возможность поиска по бренду, но означает, что поиск, скорее всего, будет нечетким, а не будет найден с запросом LIKE
SQL.
Это своего рода работа, но мне было интересно, как это можно улучшить, есть ли лучший способ поиска или как люди обычно делают это? Должен ли я разделять мету на каждое ключевое слово и пытаться увидеть, сколько слов соответствует, а не соответствует термину для всей меты?
$ids = [];
$params = ['%'.$term.'%'];
$sql = "SELECT * FROM pro_search WHERE $lang LIKE ?";
$stmt = DB::run($sql,$params);
$count = $stmt->rowCount();
if($count > 0){
// product search
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$id = $row["pro_id"];
array_push($ids,$id);
}
show_products($ids);
}else{
// product fuzzy search
$sql = "SELECT * FROM pro_search";
$stmt = DB::run($sql);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$id = $row["pro_id"];
$result = $row[$lang];
similar_text($term,$result,$similarity);
$similar_array[$similarity][] = $id;
}
$closest_match = array_keys($similar_array);
rsort($closest_match);
$match_count = count($closest_match);
for($i=0; $i<$match_count; $i++){
foreach($similar_array[$closest_match[$i]] as $id){
array_push($ids,$id);
}
}
show_products($ids);
}
Я задавал подобные вопросы и раньше, и люди указывали мне на различные способы сравнения термина с мета (например, Левенштейна), но все, что я видел, сравнивало два простых слова (например, яблоки и апельсины), и это просто не так. t достаточно хорош для реального приложения с тысячами продуктов, и пользователь может искать буквально все что угодно (как в $term='literally anything';
)
Ключевые вопросы:
Вы можете думать немного по-другому, если вы все еще разрабатываете систему. С точки зрения поиска, просто делайте точный поиск и делайте в БД, как предлагалось ранее, потому что это намного быстрее - но "учитесь на каждом взаимодействии".
Итак, основная идея в том, что вы учитесь на каждом взаимодействии и обогащаете свой поисковый набор. Кроме того, всякий раз, когда термином является пользователь, а пользователь фактически нажимает на ваш товар, вы продолжаете рассчитывать на эту ассоциацию термин-продукт, поскольку ваша уверенность в этой ассоциации термин-продукт улучшается.
Точно так же, когда у вас есть опция, пользователь очень легко может сказать "Не это", а затем направить их через предварительно выбранную иерархию ваших товаров, и в конечном итоге, когда они выберут один, вы сохраните поисковый запрос в этом продукте.
Таким образом, в течение нескольких месяцев, если у вас будет достаточно пользователей, у вас будет богатый набор органических поисковых терминов для вашей категории продуктов с уровнем достоверности для каждого термина.
term
с a, comma, seperated, list, of, keywords
есть лучший способ сравнить термин с отдельными ключевыми словами
Вы можете использовать SOUNDEX в SQL
SELECT * FROM users
WHERE SOUNDEX(job)
LIKE CONCAT('%',SUBSTRING(SOUNDEX('Manual worker'),2),'%');
И такие вещи, как Manual worka
труд, будут работать. Вам просто нужно отрегулировать значение (в настоящее время 2
), чтобы соответствовать вашим потребностям.
Я вижу, что вы уже попробовали алгоритм Левенштейна, но вы должны следить за этой адаптацией (которая также совместима со строками UTF-8)
В моем случае, soundex был более эффективным, это будет зависеть от того, как ваши пользователи будут взаимодействовать с вашим приложением.
Но, как сказано в комментарии, третьи стороны, такие как ElasticSearch или Algolia, могут быть намного эффективнее.
Со своей стороны, я никогда не использовал его, потому что компания не позволяет нам использовать стороннее программное обеспечение. Вот почему я попробовал и Levensthein и Soundex
SOUNDEX('Sure') ,SOUNDEX('Shore')
). Скажем, у меня есть продукты: manual worker, electric worker, manual gearbox, instruction manual
У каждого из них есть мета, которая включает это название и другие соответствующие ключевые слова. Я хочу, чтобы пользователь мог искать руководство или работника на другом языке, и когда он написан с ошибкой.
Вы ищете полнотекстовый поиск с расширением QUERY
MySQL поддерживает поиск текста с помощью оператора LIKE
и регулярного выражения. Однако, когда текстовый столбец большой и число строк в таблице увеличено, использование этих методов имеет некоторые ограничения:
LIKE
или шаблона в регулярных выражениях.LIKE
и поиска по регулярным выражениям трудно иметь гибкий поисковый запрос, например, найти продукт, описание которого содержит автомобиль, но не классический.Из-за этих ограничений MySQL расширил очень приятную функцию, так называемый полнотекстовый поиск. Технически MySQL создает индекс из слов включенных столбцов полнотекстового поиска и выполняет поиск по этому индексу. MySQL использует сложный алгоритм для определения строк, сопоставленных с поисковым запросом.
Для этого столбцы, которые будут использоваться для поиска, должны иметь тип TEXT и индекс типа FULLTEXT, индекс может быть задан с помощью ALTER TABLE или CREATE INDEX, и если вы используете phpMyAdmin для управления базами данных, вы можете сделать это, выполнив команду в Структуру этой таблицы, затем нажмите Дополнительно под Действие этого столбца и выберите Полный текст.
После этого вы можете выполнить поиск, используя синтаксис MATCH AGAINST. MATCH() принимает столбцы для поиска. AGAINST принимает строку для поиска и необязательный модификатор, который указывает, какой тип поиска выполнять.
В некоторых случаях пользователи хотят искать информацию на основе имеющихся у них знаний. Пользователи используют свой опыт для определения ключевых слов для поиска информации, и обычно эти ключевые слова слишком короткие.
Чтобы помочь пользователям находить информацию на основе слишком коротких ключевых слов, механизм полнотекстового поиска MySQL представляет концепцию, называемую расширением запросов.
Расширение запроса используется для расширения результатов поиска полнотекстового поиска на основе автоматической обратной связи по релевантности (или скрытого расширения запроса). Технически, механизм полнотекстового поиска MySQL выполняет следующие шаги при использовании расширения запроса:
В следующем примере показано, как искать товар, название или мета товара которого содержит хотя бы одно слово (футболка с надписью).
SELECT * FROM products WHERE MATCH(product_name,product_meta) AGAINST('shirt tshirt' WITH QUERY EXPANSION)
Вы можете прочитать больше информации в документе MYSQL (ссылка в начале ответа) и здесь
Также не пропустите Как тонкая настройка полнотекстового поиска MySQL