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 字段将数据存储为位(并用整数表示),我们可以轻松完成所有这些!使用0-1-0-0-0 代替1-2-1-1-1,但不要使用破折号。
以下是 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 个灯开关配置,为我们做了一个比较。结果又是一系列开关;如果 2 个原始开关处于不同位置,则开关将是 ON,如果它们处于相同位置,则为 OFF。
BIT_COUNT 告诉我们有多少个开关是ON——让我们计算有多少个开关是不同的。 YOUR_TOTAL_BITS 是交换机的总数。
但是二进制数仍然只是数字......所以一串 1 和 0 真的只是代表一个像 133 或 94 这样的数字。但是如果我们使用十进制数字,我们的“电灯开关配置”就更难可视化了。这就是 PHP 的 decbin 和 bindec 发挥作用的地方。
Learn more about the binary numeral system.
希望这会有所帮助!