PHP / SQL - Улучшение функции поиска / нечеткий поиск

4

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

  • У меня есть таблица 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';)

Ключевые вопросы:

  • Должна ли моя мета содержать только название продукта или несколько релевантных ключевых слов (слишком много ключевых слов означает, что отдельное слово менее похоже на целое)?
  • Если у меня есть несколько ключевых слов в мета, я должен взять каждое отдельное ключевое слово и сравнить его с поисковым термином?
  • Также было бы возможно иметь минус-слова для отдельных продуктов.
  • 0
    Вы думали об использовании базы данных только для этого требования? Elasticsearch может справиться со всем этим с большей производительностью, чем при написании собственного кода. Несколько одновременных посещений этого поиска в противном случае приведут к очень большому времени загрузки
  • 2
    "Как люди обычно делают это?" - лучший выбор - создать индекс Elastic, он обладает множеством функций, которых вы просто не можете достичь в SQL. Мы пробовали SQL в нашем проекте, но боролись с опечатками, псевдонимами, рейтингами и т. Д. Elastic имеет встроенные функции для обработки естественного языка.
Показать ещё 3 комментария
Теги:
search

3 ответа

2

Вы можете думать немного по-другому, если вы все еще разрабатываете систему. С точки зрения поиска, просто делайте точный поиск и делайте в БД, как предлагалось ранее, потому что это намного быстрее - но "учитесь на каждом взаимодействии".

  • Пользователь вводит в некоторый срок
  • Вы делаете точный поиск, если нашли отличный.
  • если нет, нечеткий поиск для каждой части введенного термина. Все еще не найден, вы делаете Soundex. Вы пытаетесь найти что-то! Но представьте пользователю длинный список для фильтрации.
  • В конце концов пользователь выбирает один. Как только они это сделают, вы добавляете введенный ими термин в выбранный продукт.

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

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

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

  • 0
    Привет, спасибо за ваш ответ, это звучит великолепно в теории, но я не уверен, насколько хорошо это будет работать на практике. Например, если я добавлю термины в мету на основе рейтинга кликов, я могу в конечном итоге добавить к мета неправильное написание и т. Д., Это будет просто означать, что первоначальный точный поиск с большей вероятностью будет нечетким, поскольку существует так много случайные опечатки в мета. Или как бы вы начали первоначальный поиск? Как я сравниваю term с a, comma, seperated, list, of, keywords есть лучший способ сравнить термин с отдельными ключевыми словами
  • 0
    на самом деле орфографические ошибки являются хорошим примером. предметы с ошибками, я думаю, должны идти в мета. Ваша цель не в том, чтобы быть учителем английского языка в 5-м классе, а в том, чтобы вы эффективно предоставляли результаты клиентам. Так что, если достаточно людей неправильно пишут, вы помогли им всем. Я бы даже не рассматривал это как «метаданные» - скорее как данные поиска. Метаданные могут быть более формальной категоризацией продукта. Просто посмотрите в Google, Amazon и т. Д., Как поиски с орфографической ошибкой тоже работают довольно хорошо.
Показать ещё 5 комментариев
2

Вы можете использовать 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

  • 0
    Я не уверен, что вы понимаете, о чем я спрашиваю. Ранее я изучал levenshtein и soundex, но эта статья о soundex похожа на то, что я сказал, сравнивая два простых слова ( SOUNDEX('Sure') ,SOUNDEX('Shore') ). Скажем, у меня есть продукты: manual worker, electric worker, manual gearbox, instruction manual У каждого из них есть мета, которая включает это название и другие соответствующие ключевые слова. Я хочу, чтобы пользователь мог искать руководство или работника на другом языке, и когда он написан с ошибкой.
  • 0
    Вот что я пытался объяснить. Комбинируя Levenshtein и Soundex, это может работать с вашим вариантом использования. Но, возможно, у вас будет слишком много ложных срабатываний. Но если у вас есть такая возможность, вы получите лучший результат, если будете использовать Algolia или третьих лиц, подобных этому. Извините, если мой ответ не был ясен
Показать ещё 1 комментарий
0

Вы ищете полнотекстовый поиск с расширением QUERY

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

  • Производительность: MySQL должен сканировать всю таблицу, чтобы найти точный текст на основе шаблона в операторе LIKE или шаблона в регулярных выражениях.
  • Гибкий поиск: с помощью оператора LIKE и поиска по регулярным выражениям трудно иметь гибкий поисковый запрос, например, найти продукт, описание которого содержит автомобиль, но не классический.
  • Ранжирование по релевантности: невозможно указать, какая строка в наборе результатов больше соответствует условиям поиска.

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

Для этого столбцы, которые будут использоваться для поиска, должны иметь тип TEXT и индекс типа FULLTEXT, индекс может быть задан с помощью ALTER TABLE или CREATE INDEX, и если вы используете phpMyAdmin для управления базами данных, вы можете сделать это, выполнив команду в Структуру этой таблицы, затем нажмите Дополнительно под Действие этого столбца и выберите Полный текст.

После этого вы можете выполнить поиск, используя синтаксис MATCH AGAINST. MATCH() принимает столбцы для поиска. AGAINST принимает строку для поиска и необязательный модификатор, который указывает, какой тип поиска выполнять.

Полнотекстовый поиск с расширением QUERY:

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

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

Расширение запроса используется для расширения результатов поиска полнотекстового поиска на основе автоматической обратной связи по релевантности (или скрытого расширения запроса). Технически, механизм полнотекстового поиска MySQL выполняет следующие шаги при использовании расширения запроса:

  • Во-первых, механизм полнотекстового поиска MySQL ищет все строки, соответствующие поисковому запросу.
  • Во-вторых, он проверяет все строки в результатах поиска и находит соответствующие слова.
  • В-третьих, он снова выполняет поиск на основе релевантных слов вместо исходных ключевых слов, предоставленных пользователями.

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

SELECT * FROM products WHERE MATCH(product_name,product_meta) AGAINST('shirt tshirt' WITH QUERY EXPANSION)

Вы можете прочитать больше информации в документе MYSQL (ссылка в начале ответа) и здесь

Также не пропустите Как тонкая настройка полнотекстового поиска MySQL

Ещё вопросы

Сообщество Overcoder
Наверх
Меню