如何加快汉明距离的BIT_COUNT查询?

时间:2016-01-28 15:36:15

标签: php mysql performance

我有一个PHP脚本,用于检查从安全摄像头拍摄的2张静态照片之间的汉明距离。

该表是具有2.4M行的mySQL,由一个Key和4个INT(10)组成。 INT(10)已被单独索引,并与Key一起索引,但我没有明显证据表明任何组合都比其他组合更快。如果你建议,我可以再试一次。

通过将图像转换为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&#34; A&#34;将永远在pHash&#34; B&#34; +/-汉明距离。

特别感谢@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&#34;?&#34;表示正在检查的文件的4个32位哈希值,接下来的2&#34;?&#34;表示该文件的预先计算的bitcount +/-所需的汉明距离,以及最后的&#34;?&#34;代表汉明的距离。 ORDER BY子句仅用于将最接近的匹配项置于顶部,其中LIMIT 1子句将返回最佳匹配项。 bitcount字段有一个B-TREE索引。

来自240万个文件的bitcounts分散成钟形曲线,极端有3或4个,中心有70,000个。如果给出一个bitcount为64的文件(这是最坏的情况),在汉明距离3内查找文件意味着比较20%的文件(在我的情况下为490,000),而寻找汉明距离为0将比较只有2.8%的记录(当然是70,000)。

1 个答案:

答案 0 :(得分:5)

根据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 … 位于以下。 (也就是说,它始终至少等于差异,并且可能更大。)如果您预先计算每一行的总位数,则可以使用它来排除总位数为“s”的行。离你的目标太远了。更好的是,您可以在该列上创建索引,并使用该索引。

我想到的是:

google index-->content keywords

请注意,有了这个,就不需要将哈希分成四个块。将它们组合成一个列可以使事情变得更容易。