如何在 MySQL 中更快地进行“欧式距离计算”?

腰带

我正在创建一个人脸识别系统,但搜索速度很慢。你能分享一下如何加快搜索速度吗?

100,000 个数据项大约需要 6 秒。

  • MySQL
mysql> SHOW VARIABLES LIKE '%version%';
+--------------------------+------------------------------+
| Variable_name            | Value                        |
+--------------------------+------------------------------+
| version                  | 8.0.29                       |
| version_comment          | MySQL Community Server - GPL |
| version_compile_machine  | x86_64                       |
| version_compile_os       | Linux                        |
+--------------------------+------------------------------+
  • 桌子
CREATE TABLE `face_feature` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `f1` decimal(9,8) NOT NULL,
  `f2` decimal(9,8) NOT NULL,
  ...
  ...
  `f127` decimal(9,8) NOT NULL,
  `f128` decimal(9,8) NOT NULL,
  PRIMARY KEY (id)
);
  • 数据
mysql> SELECT count(*) FROM face_feature;
+----------+
| count(*) |
+----------+
|   110004 |
+----------+

mysql> SELECT * FROM face_feature LIMIT 1\G;
  id: 1
  f1: -0.07603023
  f2: 0.13605964
  ...
f127: 0.09608927
f128: 0.00082345
  • SQL
SELECT 
  id,
  sqrt(
    power(f1 - (-0.09077361), 2) +
    power(f2 - (0.10373443), 2) +
    ...
    ...
    power(f127 - (0.0778369), 2) +
    power(f128 - (0.00951046), 2)
  ) as distance
FROM 
  face_feature
ORDER BY 
  distance
LIMIT
  1
;
  • 结果
+----+--------------------+
| id | distance           |
+----+--------------------+
|  1 | 0.3376853491771237 |
+----+--------------------+
1 row in set (6.18 sec)

更新1:

从更改decimal(9,8)float(9,8)

然后,从改进approximately 4sec3.26 sec

mysql> desc face_feature;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int        | NO   | PRI | NULL    | auto_increment |
| f1    | float(9,8) | NO   |     | NULL    |                |
| f2    | float(9,8) | NO   |     | NULL    |                |
..
| f127  | float(9,8) | NO   |     | NULL    |                |
| f128  | float(9,8) | NO   |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+

更新 2:

从更改POWER(z, 2)z*z

然后,结果从更改3.26 sec4.65 sec

SELECT 
  id,
  sqrt(
    ((f1 - (-0.09077361)) * (f1 - (-0.09077361))) +
    ((f2 - (0.10373443)) * (f2 - (0.10373443))) +
    ((f3 - (0.00798536)) * (f3 - (0.00798536))) +
    ...
    ...
    ((f126 - (0.07803915)) * (f126 - (0.07803915))) +
    ((f127 - (0.0778369)) * (f127 - (0.0778369))) +
    ((f128 - (0.00951046)) * (f128 - (0.00951046))
  ) as distance
FROM 
  face_feature
ORDER BY 
  distance
LIMIT
  1
;

更新 3

我正在研究 MySQL GIS 的使用。

如何在 MySQL 中从“float”迁移到“points”?


更新 4

我也在研究 PostgreSQL,因为我找不到在 MySQL 中处理 128 维的方法。

里克·詹姆斯
  • DECIMAL(9,8)- 这是很多有效数字。你需要那么精确吗?

  • FLOAT-- 约 7 位有效数字;更快的算术。

  • POWER(z, 2)- 可能比z*z. (这可能是最慢的部分。)

  • SQRT-- 在许多情况下,您可以简单地使用正方形。在这种情况下:

    SELECT SQRT(closest)
        FROM ( SELECT -- leave out SQRT
                 ... ORDER BY .. LIMIT 1 )
    

这里有一些其他的想法。它们不一定与正在讨论的查询相关:

  • 精确测试——当心比较“相等”的舍入错误可能会意外地使事情变得不相等。不精确的测量增加了这个问题。如果我测量两次,我可能一次得到 1.23456789,下一次得到 1.23456788。(特别是在那个“精度”级别。

  • 交易复杂性与速度——ABS(a - b)用作距离公式;以这种方式找到最接近的 10 个项目,然后使用欧几里得距离来获得“正确”的距离。

  • 将面分成多个区域。找出项目所在的区域,然后仅检查该区域中 128 个点的子集。(靠近边界——在两个区域中放置一些点。)

  • 开箱即用——我不熟悉你的面部识别,所以我已经用完了数学技巧。

  • 切换到POINTs和一个SPATIAL索引。您的任务可能会更快几个数量级。(这对于 128 维空间可能不实用。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章