如何计算 MySQL 查询中两个哈希之间的差异?
How can I calculate the difference between two hashes in a MySQL query?
我正在尝试计算输入哈希和数据库存储的哈希之间的汉明距离。这些是感知哈希,因此它们之间的汉明距离对我很重要,可以告诉我两个不同图像的相似程度(参见 http://en.wikipedia.org/wiki/Perceptual_hashing, http://jenssegers.com/61/perceptual-image-hashes, )。哈希为 16 个十六进制字符长,如下所示:
b1d0c44a4eb5b5a9
1f69f25228ed4a31
751a0b19f0c2783f
我的数据库是这样的:
CREATE TABLE `hashes` (
`id` int(11) NOT NULL,
`hash` binary(8) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
INSERT INTO `hashes` (`id`, `hash`) VALUES
(1, 0xb1d0c44a4eb5b5a9),
(2, 0x1f69f25228ed4a31),
(3, 0x751a0b19f0c2783f);
现在,我知道我可以像这样查询汉明距离:
SELECT BIT_COUNT(0xb1d0c44a4eb5b5a9 ^ 0x751a0b19f0c2783f)
这将按预期输出 38。但是,我似乎无法为此比较引用列名。以下未按预期工作。
SELECT BIT_COUNT(hash ^ 0x751a0b19f0c2783f) FROM hashes
有谁知道我如何使用数据库中的列计算汉明距离,就像我在上面的第一个 SELECT
查询中那样?我以不同的方式使用 hex()
、unhex()
、conv()
和 cast()
尝试了无数场景。这是在 MySQL.
Update 当 MySQL v8 中的 运行 时,我上面的查询似乎按预期工作(感谢@LukStorms 指出了这一点)。您可以使用下面我的 fiddle 并更改左上角的版本。我现在的问题是:如何确保该行为适用于所有版本的 MySQL?
Fiddle: https://www.db-fiddle.com/f/mpqsUpZ1sv2kmvRwJrK5xL/0
这不是数字,不能用于数学计算:
`hash` binary(8) NOT NULL
改为使用 bigint:
`hash` bigint unsigned NOT NULL
问题似乎与您选择的字符串类型数据类型有关。使用数字数据类型适用于 MySQL 5.7 和 8.0:
CREATE TABLE `hashes` (
`id` int(11) NOT NULL,
`hash` bigint unsigned NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
INSERT INTO `hashes` (`id`, `hash`) VALUES
(1, 0xb1d0c44a4eb5b5a9),
(2, 0x1f69f25228ed4a31),
(3, 0x751a0b19f0c2783f);
SELECT id, HEX(hash), BIT_COUNT(hash ^ 0x751a0b19f0c2783f)
FROM hashes;
输出:
id HEX(hash) BIT_COUNT(hash ^ 0x751a0b19f0c2783f)
1 B1D0C44A4EB5B5A9 38
2 1F69F25228ED4A31 34
3 751A0B19F0C2783F 0
MySQL5.7和8.0使用字符串类型的区别可以通过这个查询看出:
SELECT id, hash, HEX(hash), HEX(hash ^ 0x751a0b19f0c2783f)
FROM hashes;
MySQL 5.7:
id hash HEX(hash) HEX(hash ^ 0x751a0b19f0c2783f)
1 {"type":"Buffer","data":[177,208,196,74,78,181,181,169]} B1D0C44A4EB5B5A9 751A0B19F0C2783F
2 {"type":"Buffer","data":[31,105,242,82,40,237,74,49]} 1F69F25228ED4A31 751A0B19F0C2783F
3 {"type":"Buffer","data":[117,26,11,25,240,194,120,63]} 751A0B19F0C2783F 751A0B19F0C2783F
MySQL 8.0
id hash HEX(hash) HEX(hash ^ 0x751a0b19f0c2783f)
1 {"type":"Buffer","data":[177,208,196,74,78,181,181,169]} B1D0C44A4EB5B5A9 C4CACF53BE77CD96
2 {"type":"Buffer","data":[31,105,242,82,40,237,74,49]} 1F69F25228ED4A31 6A73F94BD82F320E
3 {"type":"Buffer","data":[117,26,11,25,240,194,120,63]} 751A0B19F0C2783F 0000000000000000
MySQL 8.0 正确执行异或,返回一个变量,而 MySQL 5.7 返回被异或的值,表明它正在将 BINARY
字符串视为在数字上下文中为 0。
试试这个:
SELECT id, HEX(hash), CAST(CONV(HEX(hash),16,10) AS UNSIGNED), BIT_COUNT(CAST(CONV(HEX(hash),16,10) AS UNSIGNED) ^ 0x751a0b19f0c2783f) FROM hashes;
我正在尝试计算输入哈希和数据库存储的哈希之间的汉明距离。这些是感知哈希,因此它们之间的汉明距离对我很重要,可以告诉我两个不同图像的相似程度(参见 http://en.wikipedia.org/wiki/Perceptual_hashing, http://jenssegers.com/61/perceptual-image-hashes, )。哈希为 16 个十六进制字符长,如下所示:
b1d0c44a4eb5b5a9
1f69f25228ed4a31
751a0b19f0c2783f
我的数据库是这样的:
CREATE TABLE `hashes` (
`id` int(11) NOT NULL,
`hash` binary(8) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
INSERT INTO `hashes` (`id`, `hash`) VALUES
(1, 0xb1d0c44a4eb5b5a9),
(2, 0x1f69f25228ed4a31),
(3, 0x751a0b19f0c2783f);
现在,我知道我可以像这样查询汉明距离:
SELECT BIT_COUNT(0xb1d0c44a4eb5b5a9 ^ 0x751a0b19f0c2783f)
这将按预期输出 38。但是,我似乎无法为此比较引用列名。以下未按预期工作。
SELECT BIT_COUNT(hash ^ 0x751a0b19f0c2783f) FROM hashes
有谁知道我如何使用数据库中的列计算汉明距离,就像我在上面的第一个 SELECT
查询中那样?我以不同的方式使用 hex()
、unhex()
、conv()
和 cast()
尝试了无数场景。这是在 MySQL.
Update 当 MySQL v8 中的 运行 时,我上面的查询似乎按预期工作(感谢@LukStorms 指出了这一点)。您可以使用下面我的 fiddle 并更改左上角的版本。我现在的问题是:如何确保该行为适用于所有版本的 MySQL?
Fiddle: https://www.db-fiddle.com/f/mpqsUpZ1sv2kmvRwJrK5xL/0
这不是数字,不能用于数学计算:
`hash` binary(8) NOT NULL
改为使用 bigint:
`hash` bigint unsigned NOT NULL
问题似乎与您选择的字符串类型数据类型有关。使用数字数据类型适用于 MySQL 5.7 和 8.0:
CREATE TABLE `hashes` (
`id` int(11) NOT NULL,
`hash` bigint unsigned NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
INSERT INTO `hashes` (`id`, `hash`) VALUES
(1, 0xb1d0c44a4eb5b5a9),
(2, 0x1f69f25228ed4a31),
(3, 0x751a0b19f0c2783f);
SELECT id, HEX(hash), BIT_COUNT(hash ^ 0x751a0b19f0c2783f)
FROM hashes;
输出:
id HEX(hash) BIT_COUNT(hash ^ 0x751a0b19f0c2783f)
1 B1D0C44A4EB5B5A9 38
2 1F69F25228ED4A31 34
3 751A0B19F0C2783F 0
MySQL5.7和8.0使用字符串类型的区别可以通过这个查询看出:
SELECT id, hash, HEX(hash), HEX(hash ^ 0x751a0b19f0c2783f)
FROM hashes;
MySQL 5.7:
id hash HEX(hash) HEX(hash ^ 0x751a0b19f0c2783f)
1 {"type":"Buffer","data":[177,208,196,74,78,181,181,169]} B1D0C44A4EB5B5A9 751A0B19F0C2783F
2 {"type":"Buffer","data":[31,105,242,82,40,237,74,49]} 1F69F25228ED4A31 751A0B19F0C2783F
3 {"type":"Buffer","data":[117,26,11,25,240,194,120,63]} 751A0B19F0C2783F 751A0B19F0C2783F
MySQL 8.0
id hash HEX(hash) HEX(hash ^ 0x751a0b19f0c2783f)
1 {"type":"Buffer","data":[177,208,196,74,78,181,181,169]} B1D0C44A4EB5B5A9 C4CACF53BE77CD96
2 {"type":"Buffer","data":[31,105,242,82,40,237,74,49]} 1F69F25228ED4A31 6A73F94BD82F320E
3 {"type":"Buffer","data":[117,26,11,25,240,194,120,63]} 751A0B19F0C2783F 0000000000000000
MySQL 8.0 正确执行异或,返回一个变量,而 MySQL 5.7 返回被异或的值,表明它正在将 BINARY
字符串视为在数字上下文中为 0。
试试这个:
SELECT id, HEX(hash), CAST(CONV(HEX(hash),16,10) AS UNSIGNED), BIT_COUNT(CAST(CONV(HEX(hash),16,10) AS UNSIGNED) ^ 0x751a0b19f0c2783f) FROM hashes;