Подтвердить что ты не робот

Как найти сходство между строками mySQL?

Я пытаюсь создать script, который находит соответствующий процент между моими строками таблицы. Например, моя база данных mySQL в продуктах таблицы содержит имя поля (indexed, FULLTEXT) со значениями, такими как

LG 50PK350 PLASMA TV 50" Plasma TV Full HD 600Hz 
LG TV 50PK350 PLASMA 50"
LG S24AW 24000 BTU
Aircondition LG S24AW 24000 BTU Inverter

Как вы можете видеть, у всех из них есть одно и то же ключевое слово. Но первое имя и второе имя более похожи. Кроме того, у третьих и четвертых есть более похожие ключевые слова между ними, чем 1-й и 2-й.

В моей базе данных mySQL есть тысячи имен продуктов. Я хочу найти те имена, которые имеют более чем процент (допустим, 60%) сходства.

Например, как я уже сказал, первое, второе (и любое другое имя), совпадающее между ними с более чем 60%, будет отражено в формате группового стиля, чтобы сообщить мне, что эти продукты похожи. 3-й и 4-й и любой другой, имеющий более 60% соответствия, будут повторяться в другой группе, сообщая мне, что эти продукты соответствуют.

Если это возможно, было бы здорово повторить ключевые слова, удовлетворяющие всем сгруппированным совпадающим именам. Например, LG S24AW 24000 BTU - это ключевое слово, которое содержится в 3-м и 4-м имени.

В конце я создам список всех этих ключевых слов.

Теперь у меня есть следующий запрос (как предложил Дзитамаро)

Select t1.name, t2.name From products t1, products t2

который создает новое поле имени рядом со всеми другими именами. Извините, что я не знаю, как правильно это объяснить, но это то, что он делает: (Реальные значения - это названия продуктов, как указано выше)

Перед запросом

-name-
A
B
C
D
E

После запроса

-name- -name-
A        A
B        A
C        A
D        A
E        A
A        B
B        B
C        B
D        B
E        B
.
.
.

Есть ли способ с mySQL или PHP, который найдет мне совпадающие имена и извлеките ключевые слова, как описано выше? Просьба поделиться примерами кода.

Спасибо сообществу.

4b9b3361

Ответ 1

Запросить БД с помощью LIKE OR REGEXP:

SELECT * FROM product WHERE product_name LIKE '%LG%';
SELECT * FROM product WHERE product_name REGEXP "LG";

Завершите результаты и используйте функцию like_text():

$a = "LG 50PK350 PLASMA TV 50\" Plasma TV Full HD 600Hz"; // DB value
$b = "LG TV 50PK350 PLASMA 50\"" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

//outputs: Matched: 21 Percentage: 58.3333333333%

Второй пример соответствует 62.0689655172%:

$a = "LG S24AW 24000 BTU"; // DB value
$b = "Aircondition LG S24AW 24000 BTU Inverter" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

Вы можете определить процент выше, чем, скажем, 40%, для соответствия товарам.
Обратите внимание, что подобный_текст() - это случай SensItivE, поэтому вы должны ввести строку в нижний регистр.

Ответ 2

Что касается вашего второго вопроса, levenshtein() функция (в MySQL) будет хорошим кандидатом.

Ответ 3

Когда я смотрю на ваши примеры, я рассматриваю, как я попытаюсь найти похожие продукты на основе названия. Из ваших двух примеров я вижу одну вещь в каждой строке, которая выделяется выше всего остального: номера моделей. 50PK350, вероятно, не отображается нигде, кроме как связанного с этой моделью.

Теперь сама MySQL не предназначена для решения таких вопросов, но некоторые инструменты для болтовки над ней. Частью проблемы является то, что запрос по всем этим полям во всех позициях является дорогостоящим. Вы действительно хотите разбить его определенным образом и индексировать это. Класс подобия Lucene предоставит высокий балл для слов, которые редко появляются во всех данных, но выглядят как высокий процент ваших данных. См. Высокое объяснение класса сходства для Lucene?

Вы также должны посмотреть Сравнение полнотекстового поискового движка - Lucene, Sphinx, Postgresql, MySQL?

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

Независимо от того, что вы делаете, поймите, что, если вы не измените структуры данных, используя другой инструмент поверх системы SQL для создания улучшенных структур данных, ваши запросы будут слишком медленными и дорогими. Я думаю, что Луцен, наверное, путь. Сфинкс или другие варианты, не упомянутые, также могут быть рассмотрены.

Ответ 4

Это сложнее, чем кажется, и в вашем сообщении отсутствует информация.

  • Как люди будут использовать эту функцию автозаполнения?
  • Насколько актуально то, что вы можете найти все имена для продукта? Потому что, видимо, не все магазины называют их продукты одинаково, поэтому клерк, возможно, не сможет найти найденные им продукты.
  • У вас есть информация о том, какие имена продуктов относятся к одному продукту?
  • Насколько релевантно, из какого магазина вы ищете? где используется этот автозаполнение?
  • Если автозаполнение действительно предлагает только продукты, соответствующие всем введенным вами словам? (это не так сложно, технически, исправлять опечатки)

Я думаю, вам нужно более четкое представление о том, что вам (или еще лучше: пользователям) нужна функция автозаполнения.

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

Сначала выясните, чего вы хотите, а затем о технологиях.

Ответ 5

Одним из возможных решений является использование расстояние Дамерау-Левенштайн. Он может быть использован как

select *
from products p
where DamerauLevenstein(p.name, '*user input here*')<=*X*

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

Самое сложное здесь - DamerauLevenstein. Это должна быть хранимая процедура, которая реализует алгоритм Дамерау-Левенштейна. У меня здесь нет MySQL, поэтому я могу написать его для вас позже в этот день.

Обновление: MySQL не поддерживает массивы в хранимых процедурах, поэтому нет возможности реализовать Damerau-Levenstein в MySQL, за исключением использования временной таблицы для каждого вызова функции. И это приведет к ужасным результатам. Таким образом, у вас есть два варианта: выполнить петлю через PHP с помощью levenstein, как предлагает Alix Axel, или перенести вашу базу данных в PostgreSQL, где поддерживаются массивы. Существует также возможность создания функции User-Defined, но для этого требуется записать эту функцию в C, связать ее с MySQL и, возможно, перестроить MySQL, так что вы просто добавите больше головной боли.

Ответ 6

Ваш подход кажется звуковым. Для сопоставления похожих продуктов я бы предложил поиск триграмм. Там довольно приличное объяснение того, как это работает вместе с String:: Trigram Perl-модулем.

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

Ответ 7

Возможно, вы хотите найти самую длинную общую подстроку из 2 строк? Затем вам нужно вычислить дерево суффиксов для каждой из ваших строк, см. Здесь http://en.wikipedia.org/wiki/Longest_common_substring_problem.

Ответ 8

Если вы хотите проверить все имена друг против друга, вам нужно перекрестное соединение в mysql. Существует много способов добиться этого:

1. Select a, b From t1, t2

2. Select a, b From t1 Join t2

3. Select a, b From t1 Cross Join t2

Затем вы можете просмотреть результат. Это то же самое, когда я говорю, создавая 2d-массив с n ^ 2- (n-1) элементами, и каждый элемент связан между собой.

P.S.: Выберите t1.name, t2.name Из произведений t1, произведений t2

Ответ 9

Кажется, что вы всегда можете вернуть кратчайшую строку? Это больше или вопрос, чем что-либо. Но тогда у вас может быть что-то вроде...

SELECT * FROM products LIMIT 1
WHERE product_name like '%LG%'
ORDER BY LENGTH(product_name) ASC

Ответ 10

Похоже, вы преодолели всю эту проблему, чтобы объяснить сложный сценарий, а затем сказали, что хотите проигнорировать оптимальные ответы и просто попросите нас дать вам протокол "рукопожатия" (все сравнивается со всем, что hasn с ним еще не сравнивалось). Итак... псевдокод:

select * from table order by id
while (result) {
    select * from table where id > result_id
}

Это сделает это.

Ответ 11

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

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

Пользователи базы данных пытаются поместить уже существующий UPC в базу данных - они получают сообщение об ошибке.

База данных поддерживает свою целостность.

И если такая база данных сохранила свою целостность - необходимость делать то, что вы предлагаете, никогда не возникает.

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

Ответ 12

Это проблема кластеризации, которая может быть решена методом интеллектуального анализа данных. (http://en.wikipedia.org/wiki/Cluster_analysis) Это требует большого количества операций с памятью и вычислением, которые не подходят для механизма базы данных. В противном случае не было бы раздельного интеллектуального анализа данных, текстового поиска или программного обеспечения для бизнес-аналитики.

Ответ 13

Я советую вам использовать полнотекстовую поисковую систему, например sphinx. Он имеет возможности реализовать любой алгоритм, который вы хотите. Например, вы можете использовать поиск "quorom" или "any".

Ответ 15

Вы можете использовать LIKE для поиска похожих имен продуктов в таблице. Например:

SELECT * FROM product WHERE product_name LIKE 'LG%';

Ответ 16

Вот еще одна идея (но я голосую за levenshtein()):

Создайте временную таблицу всех слов, используемых в именах и их частотах.

Выберите диапазон результатов (наиболее популярные слова - это, вероятно, слова, такие как LCD или LED, самые уникальные слова могут быть хорошими, они могут быть фактическими именами продукта).

Предложите для каждого из слов результата:

Ответ 17

Хорошо, я думаю, что пытался реализовать очень похожее. Он может работать так же, как и адресное поле google chrome. Когда вы вводите адрес, он дает вам предложения. Это то, чего вы пытаетесь достичь, насколько мне известно.

Я не могу дать вам точное решение, но некоторые советы.

  • Вам нужно реализовать раскрывающийся список, в котором кто-то начинает вводить продукт, который ищет.
  • Затем вам нужно получить текущее значение раскрывающегося списка, а затем запустить запрос, например, парень, опубликованный выше. Может быть "SELECT * FROM product WHERE product_name LIKE" LG% '; "
  • Сохранить результаты запроса
  • Обновить страницу
  • Добавить результаты запроса в раскрывающийся список

Примечание:

Вам нужно сохранить результаты запроса где-то, как текстовый файл, с кодом HTML, то есть "опцией" LG TS 600 "/option" (добавьте < > скобки для опции, конечно). Эти значения будут использоваться для заполнения вашего окна параметров после обновления страницы. Вам нужно настроить сеанс пользователей для получения одинаковых результатов для одного и того же пользователя, иначе, если большее количество пользователей будет использовать поиск, в то же время он может столкнуться. Таким образом, с идентификатором поиска и идентификатором сеанса вы можете их сопоставить. Вы можете сохранить его в файле или таблице. Таблица была бы более удобной. На самом деле это в моем смысле целая подсистема для этого, что вы ищете.

Надеюсь, это поможет.