Jawa最初发布了这个想法,这是我的尝试。
^
是异或函数。它逐位比较两个二进制数,如果两个位相同,则返回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(7) = 3
BIT_COUNT(b'1111' ^ b'0111') = 1
所以,要获取相似性...
(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)
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个灯开关配置时进行比较。结果仍然是一系列开关;如果两个原始开关处于不同位置,则开关将是ON
,否则为OFF
。
BIT_COUNT
告诉我们有多少开关是ON
——给我们一个不同开关的计数。 YOUR_TOTAL_BITS
是总开关数。
但是二进制数字仍然只是数字...因此,一串1和0实际上只代表像133或94这样的数字。但是,如果我们使用十进制数,很难将我们的“灯开关配置”可视化。这就是PHP的decbin
和bindec
发挥作用的地方。
了解更多关于二进制数系统的信息。
希望这可以帮助你!