Хорошо, давайте предположим, что у нас есть таблица members
. Существует поле, называемое, скажем, about_member
. Для всех будет 1-1-2-1-2
. Предположим, что member_1 имеет эту строку 1-1-2-2-1
и он ищет, кто имеет аналогичную строку или как можно больше похоже. Например, если member_2 имеет строку 1-1-2-2-1
это будет 100% -ное совпадение, но если member_3 имеет строку вроде этого 2-1-1-2-1
она будет соответствовать 60%. И его нужно заказывать по процентам по процентам. Какой самый оптимальный способ сделать это с помощью MYSQL и PHP? Мне очень сложно объяснить, что я имею в виду, но, может быть, вы поняли, если нет, спросите меня. Благодарю.
Редактировать: Пожалуйста, дайте мне идеи без метода Левенштейна. Этот ответ получит щедрость. Благодарю. (щедрость будет объявлена, когда я смогу это сделать)
Первоначально идея Jawa была опубликована; вот моя попытка.
^
– функция XOR. Он сравнивает по 2 двоичных числа побитовое число и возвращает 0, если оба бита одинаковы, и 1 в противном случае.
0 1 0 0 0 1 0 1 0 1 1 1 (number 1) ^ 0 1 1 1 0 1 0 1 1 0 1 1 (number 2) = 0 0 1 1 0 0 0 0 1 1 0 0 (result)
Как это относится к вашей проблеме:
// In binary... 1111 ^ 0111 = 1000 // (1 bit out of 4 didn't match: 75% match) 1111 ^ 0000 = 1111 // (4 bits out of 4 didn't match: 0% match) // The same examples, except now in decimal... 15 ^ 7 = 8 (1000 in binary) // (1 bit out of 4 didn't match: 75% match) 15 ^ 0 = 15 (1111 in binary) // (4 bits out of 4 didn't match: 0% match)
Как мы можем считать эти биты в MySQL:
BIT_COUNT(b'0111') = 3 // Bit count of binary '0111' BIT_COUNT(7) = 3 // Bit count of decimal 7 (= 0111 in binary) BIT_COUNT(b'1111' ^ b'0111') = 1 // (1 bit out of 4 didn't match: 75% match)
Итак, чтобы получить сходство …
// First we focus on calculating mismatch. (BIT_COUNT(b'1111' ^ b'0111') / YOUR_TOTAL_BITS) = 0.25 (25% mismatch) (BIT_COUNT(b'1111' ^ b'1111') / YOUR_TOTAL_BITS) = 0 (0% mismatch; 100% match) // Now, getting the proportion of matched bits is easy 1 - (BIT_COUNT(b'1111' ^ b'0111') / YOUR_TOTAL_BITS) = 0.75 (75% match) 1 - (BIT_COUNT(b'1111' ^ b'1111') / YOUR_TOTAL_BITS) = 1.00 (100% match)
Если бы мы могли просто сделать ваши about_member
полем about_member
виде битов (и быть представлены целым числом), мы могли бы сделать все это легко! Вместо 1-2-1-1-1
используйте 0-1-0-0-0
, но без тире.
Вот как PHP может нам помочь:
bindec('01000') == 8; bindec('00001') == 1; decbin(8) == '01000'; decbin(1) == '00001';
И, наконец, вот реализация:
// Setting a member's about_member property... $about_member = '01100101'; $about_member_int = bindec($about_member); $query = "INSERT INTO members (name,about_member) VALUES ($name,$about_member_int)"; // Getting matches... $total_bits = 8; // The maximum length the member_about field can be (8 in this example) $my_member_about = '00101100'; $my_member_about_int = bindec($my_member_about_int); $query = " SELECT *, (1 - (BIT_COUNT(member_about ^ $my_member_about_int) / $total_bits)) match FROM members ORDER BY match DESC LIMIT 10";
Этот последний запрос отобрал бы 10 членов, наиболее похожих на меня!
Теперь, чтобы повторить, с точки зрения непрофессионала,
Мы используем двоичный код, потому что это упрощает работу; двоичное число похоже на длинную линию переключателей света. Мы хотим сохранить нашу «конфигурацию выключателя света», а также найти элементы, которые имеют наиболее похожие конфигурации.
Оператор ^
, учитывая 2 конфигурации выключателя света, делает для нас сравнение. В результате снова появляется серия переключателей; переключатель будет ON
если 2 оригинальных переключателя находятся в разных положениях и OFF
если они находятся в том же положении.
BIT_COUNT
сообщает нам, сколько коммутаторов ON
, – подсчитывая количество разных переключателей. YOUR_TOTAL_BITS
– общее количество коммутаторов.
Но двоичные числа по-прежнему являются просто цифрами … и поэтому строка из 1 и 0 действительно представляет собой число, например, 133 или 94. Но гораздо сложнее визуализировать нашу «конфигурацию световых переключателей», если мы используем десятичные числа. Вот decbin
и bindec
PHP и bindec
.
Подробнее о бинарной системе цифр.
Надеюсь это поможет!
преобразуйте свои числовые последовательности в бит-маски и используйте BIT_COUNT (столбец ^ поиск) в качестве функции подобия, начиная от 0 (= 100% соответствия, строки равны) до [длина бит] (= 0%, строки полностью разные). Чтобы преобразовать эту функцию подобия в значение процента использования
100 * (bit_length - similarity) / bit_length
Например, «1-1-2-2-1» становится «00110» (при условии, что у вас есть только два состояния), 2-1-1-2-1 – «10010», бит_count (00110 ^ 10010) = 2, бит-длина = 5 и 100 * (5 – 2) / 5 = 60%.
Очевидное решение состоит в том, чтобы взглянуть на расстояние levenstein (в mysql нет реализации, но есть другие варианты реализации, например, в pl / sql и некоторых расширениях), однако, как обычно, правильный способ решения проблемы чтобы нормализовать данные должным образом в первую очередь.
Один из способов сделать это – рассчитать расстояние Левенштейна между вашей поисковой строкой и полями about_member для каждого члена. Вот реализация функции как хранимая функция MySQL.
С этим вы можете сделать:
SELECT name, LEVENSHTEIN(about_member, '1-1-2-1-2') AS diff FROM members ORDER BY diff ASC
% Сходства связано с diff
; если diff=0
то это 100%, если diff – это размер строки (минус количество тире), это 0%.
Прочитав пояснения по первому вопросу, расстояние Левенштейна не является ответом, который вы ищете .
Вы не пытаетесь вычислить наименьшее количество изменений для изменения одной строки в другую.
Вы пытаетесь сравнить один набор чисел с другим набором чисел. То, что вы ищете, это минимальная (взвешенная) сумма различий между двумя наборами чисел.
Поместите каждый ответ в отдельный столбец (Ans1, Ans2, Ans3, Ans4, ….)
Предположим, что вы ищете сходство с 1-2-1-2.
SELECT UserName, Abs (Ans1 – 1) + Abs (Ans2 – 2) + Abs (Ans3 – 1) + Abs (Ans4 – 2) как разница ORDER BY Difference ASC
Перечислит пользователей по сходству с ответами 1-2-1-2, при условии, что все вопросы будут взвешены равномерно.
Если вы хотите сделать определенные ответы более важными, просто умножьте каждое из условий на весовой коэффициент.
Если вопросы всегда будут да / нет, а количество ответов будет достаточно маленьким, чтобы все ответы могли быть установлены в одно целое, и все ответы одинаково взвешены, тогда вы можете кодировать все ответы в одном столбце и использовать BIT_COUNT как предложил. Это было бы быстрее и экономичнее.
Я бы пошел со встроенным встроенным PHP. Кажется, это именно то, что вы хотите:
$percent = 0; similar_text($string1, $string2, $percent); echo $percent;
Он работает, как ожидается.
Я бы пошел с дистанционным подходом Левенштейна , вы можете использовать его в MySQL или PHP .
Если у вас слишком много полей, вы можете создать индекс для целочисленного представления about_member. Затем вы можете найти 100% точным совпадением в поле about_member, за которым следуют 80% совпадений, изменяя 1 бит, 60% совпадений, изменяя 2 бита и так далее.
Если вы представляете свои шаблоны ответов в виде битовых последовательностей, вы можете использовать формулу ( 100 * (bit_length - similarity) / bit_length
).
Следуя приведенному примеру, когда мы конвертируем «1» s в бит, а «2» с бит на «1-1-2-2-1» становится 6 (как base-10, 00110 в двоичном формате) и «2- 1-1-2-1 "становится 18 (10010b) и т. Д.
Кроме того, я думаю, вы должны хранить бит ответов до наименее значимых бит, но это не имеет значения, если вы согласны с тем, что ответы разных членов выравниваются.
Вот пример скрипта для MySQL.
DROP TABLE IF EXISTS `test`; CREATE TABLE `members` ( `id` VARCHAR(16) NOT NULL , `about_member` INT NOT NULL ) ENGINE = InnoDB; INSERT INTO `members` (`id`, `about_member`) VALUES ('member_1', '6'), ('member_2', '18'); SELECT 100 * ( 5 - BIT_COUNT( about_member ^ ( SELECT about_member FROM members WHERE id = 'member_1' ) ) ) / 5 FROM members;
Волшебный 5 в скрипте – это количество ответов (бит_1 длина в формуле выше). Вы должны изменить его в соответствии с вашей ситуацией, независимо от того, сколько бит есть в используемом фактическом типе данных, поскольку BIT_COUNT не знает, сколько байтов вы используете.
BIT_COUNT возвращает количество установленных битов и объясняется в руководстве по MySQL . ^
является двоичным оператором XOR в MySQL.
Здесь сравнение member_1
сравнивается со всеми, в том числе и с их собственными – что приводит к 100% member_1
совпадению, естественно.