>我有一个php脚本,可以检查从安全摄像头拍摄的2张静态照片之间的汉明距离。
该表是具有 2.4M 行的 mySQL,由一个密钥和 4 个 INT(10) 组成。INT(10) 已经单独、一起和与密钥一起索引,但我没有重要的证据表明任何组合都比其他组合更快。如果您建议,我可以再试一次。
汉明权重是通过将图像转换为 8x16 像素来计算的,并且每个季度的位存储在一列中,pHash0、pHash1...等。
我有两种写法。第一种方法是使用嵌套派生表。从理论上讲,每个推导要检查的数据应该比其前身少。查询是预准备语句,并且 ?字段是我正在检查的文件的 pHash[0-3]。
Select
`Key`,
Bit_Count(T3.pHash3 ^ ?) + T3.BC2 As BC3
From
(Select
*,
Bit_Count(T2.pHash2 ^ ?) + T2.BC1 As BC2
From
(Select
*,
Bit_Count(T1.pHash1 ^ ?) + T1.BC0 As BC1
From
(Select
`Key`,
pHash0,
pHash1,
pHash2,
pHash3,
Bit_Count(pHash0 ^ ?) As BC0
From
files
Where
Not pHash0 Is Null And
Bit_Count(pHash0 ^ ?) < 4) As T1
Where
Bit_Count(T1.pHash1 ^ ?) + T1.BC0 < 4) As T2
Where
Bit_Count(T2.pHash2 ^ ?) + T2.BC1 < 4) As T3
Where
Bit_Count(T3.pHash3 ^ ?) + T3.BC2 < 4
第二种方法更直接一些。它只是一次完成了所有工作。
Select
`Key`,
From
files
Where
Not pHash0 is null AND
Bit_Count(pHash0 ^ ?) + Bit_Count(pHash1 ^ ?) + Bit_Count(pHash2 ^
?) + Bit_Count(pHash3 ^ ?) < 4
第一个查询在大型记录集上更快,而第二个查询在较小的记录集上更快,但在 2.4M 记录上,每次比较都不会超过 1-1/3 秒。
您是否看到一种调整此过程以使其更快的方法?可以快速尝试任何建议,例如更改数据类型或索引。
设置是Win7x64,MySQL/5.6.6和InnoDB,nginx/1.99,php-cgi/7.0.0启用zend。该脚本从网页调用,并关闭了缓冲以立即反馈。
编辑:
如果我将 4 个32 位整数更改为 1 个二进制(16),这可能会更好地工作,这会将比较从 4 更改为 1,但我还必须将我的 4 个参数转换为 128 位字符,而 php 不会这样做。如果有一种方法可以快速组合它们,它可能会挤出更多的时间。
编辑接受的答案将速度提高了~500%。我们假设的快速概要:pHash "A" 的位计数将始终在 pHash "B" +/- 汉明距离内。
特别感谢@duskwuff的坚韧和耐心。干杯@duskwuff!
编辑这是我最近的查询:
Select
files.`Key`,
Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3) as BC
From
files FORCE INDEX (bitcount)
Where
bitCount Between ? And ?
AND Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3) <= ?
ORDER BY Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3)
其中,前 4 个"?"表示正在检查的文件的 4 个 32 位哈希,接下来的 2 个"?" 表示该文件的预先计算的位计数 +/- 所需的汉明距离,最后一个"?" 表示该汉明距离。ORDER BY 子句仅在将最接近的匹配项置于顶部时才是必需的,其中 LIMIT 1 子句将返回最佳匹配项。bitcount
字段上有一个 B-TREE 索引。
来自 240 万个文件的位计数的分散性陷入钟形曲线,极端有 3 或 4 个,中间有 70,000 个。如果给定一个位计数为 64 的文件(这是最坏的情况),查找汉明距离为 3 的文件意味着比较 20% 的文件(在我的例子中为 490,000),而查找汉明距离为 0 将仅比较 2.8% 的记录(当然是 70,000)。
观察BIT_COUNT(a ^ b)
以 BIT_COUNT(a)
和 BIT_COUNT(b)
之间的差异为界。(也就是说,它始终至少等于差值,并且可能更大。如果预先计算每行的总位数,则可以使用该计数来排除总位数与目标相距太远的行。更好的是,您可以在该列上创建一个索引,该索引将被使用。
我想到的是大致如下:
ALTER TABLE files ADD COLUMN totalbits INTEGER;
CREATE INDEX totalbits_index ON files (totalbits);
UPDATE files SET totalbits = BIT_COUNT(pHash1) + BIT_COUNT(pHash2)
+ BIT_COUNT(pHash3) + BIT_COUNT(pHash4);
SELECT `Key` FROM files WHERE (totalbits BETWEEN … AND …) AND …
请注意,有了这个,就没有必要将哈希拆分为四个块。将它们合并回单个列将使事情变得更容易。