跳到主要内容

向量最近邻搜索

向量最近邻搜索(Similarity Search)是一种基于向量空间中距离度量的搜索方法,其核心是找出与查询向量最相近的一组向量。尽管在计算过程中会使用特定的距离度量方式(Distance Metric),最终输出按距离从小到大排序的 Top K 个最邻近向量。

本文主要介绍 seekdb 的两种向量搜索方式:基于全量扫描的精确最近邻搜索和基于向量索引的近似最近邻搜索,并通过具体示例说明其使用方法。

提示

为方便阅读,正文中将向量最近邻搜索简称为向量搜索,精确最近邻搜索简称为精确搜索,近似最近邻搜索简称为近似搜索。

执行精确搜索

精确搜索采用全量扫描策略,通过计算查询向量与数据集中所有向量的距离来执行精确搜索。这种方法能够保证搜索结果的完全准确性,但由于需要进行全量距离计算,搜索性能会随着数据规模的增长而显著下降。

在执行精确搜索时,系统会将查询向量 vₑ 与向量空间中的所有向量进行距离计算和比对。完成全量距离计算后,系统会选取距离最近的 k 个向量作为搜索结果返回。

示例:欧几里得搜索

欧几里得搜索(Euclidean Similarity Search)用于搜索向量空间中与查询向量最接近的 top-k 个向量,这里使用欧几里得距离作为度量标准。下面是一个示例,展示如何使用精确搜索从表中搜索出与查询向量最接近的前 5 个向量:

-- 创建测试表
CREATE TABLE t1 (
id INT PRIMARY KEY,
c1 VECTOR(3)
);

-- 插入数据
INSERT INTO t1 VALUES
(1, '[0.1, 0.2, 0.3]'),
(2, '[0.2, 0.3, 0.4]'),
(3, '[0.3, 0.4, 0.5]'),
(4, '[0.4, 0.5, 0.6]'),
(5, '[0.5, 0.6, 0.7]'),
(6, '[0.6, 0.7, 0.8]'),
(7, '[0.7, 0.8, 0.9]'),
(8, '[0.8, 0.9, 1.0]'),
(9, '[0.9, 1.0, 0.1]'),
(10, '[1.0, 0.1, 0.2]');

-- 执行精确搜索
SELECT c1
FROM t1
ORDER BY l2_distance(c1, '[0.1, 0.2, 0.3]') LIMIT 5;

返回结果如下:

+---------------+
| c1 |
+---------------+
| [0.1,0.2,0.3] |
| [0.2,0.3,0.4] |
| [0.3,0.4,0.5] |
| [0.4,0.5,0.6] |
| [0.5,0.6,0.7] |
+---------------+
5 rows in set

执行计划分析

获取上文示例的执行计划:

EXPLAIN SELECT c1
FROM t1
ORDER BY l2_distance(c1, '[0.1, 0.2, 0.3]') LIMIT 5;

返回结果如下:

+---------------------------------------------------------------------------------------------+
| Query Plan |
+---------------------------------------------------------------------------------------------+
| ================================================= |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ------------------------------------------------- |
| |0 |TOP-N SORT | |5 |3 | |
| |1 |└─TABLE FULL SCAN|t1 |10 |3 | |
| ================================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1]), filter(nil), rowset=16 |
| sort_keys([l2_distance(t1.c1, cast('[0.1, 0.2, 0.3]', ARRAY(18, -1))), ASC]), topn(5) |
| 1 - output([t1.c1]), filter(nil), rowset=16 |
| access([t1.c1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.id]), range(MIN ; MAX)always true |
+---------------------------------------------------------------------------------------------+
14 rows in set

分析如下:

  • 执行方式:

    • 采用全表扫描的方式,需要遍历表中的所有数据。对应执行计划中的 TABLE FULL SCAN 操作,该操作会扫描表 t1 的所有数据。
    • 对每条记录计算向量距离,然后进行排序。对应执行计划中的 TOP-N SORT 操作,通过 l2_distance 函数计算向量距离,并按距离升序排序。
    • 最终返回距离最小的前 5 条记录。对应执行计划中的 topn(5) 设置,表示只返回排序后的前 5 条记录。
  • 性能特点:

    • 优点:结果完全准确,保证返回的是真实的最近邻。
    • 缺点:需要扫描全表数据,计算所有向量的距离,性能随数据量增长而显著下降。
  • 适用场景:

    • 数据量较小的场景。
    • 对结果准确性要求极高的场景。
    • 不适合大规模数据集的实时查询。

使用向量索引执行近似搜索

向量索引搜索采用近似(Approximate Nearest Neighbor,ANN)策略,通过预构建的索引结构来加速搜索过程。虽然不能保证 100% 的结果精确度,但能显著提升搜索性能,在实际应用中可以在精确度和性能之间取得良好的平衡。

示例:HNSW 索引近似搜索

-- 随表创建 HNSW 向量索引
CREATE TABLE t2 (
id INT PRIMARY KEY,
vec VECTOR(3),
VECTOR INDEX idx(vec) WITH (distance=l2, type=hnsw, lib=vsag)
);

-- 插入测试数据
INSERT INTO t2 VALUES
(1, '[0.1, 0.2, 0.3]'),
(2, '[0.2, 0.3, 0.4]'),
(3, '[0.3, 0.4, 0.5]'),
(4, '[0.4, 0.5, 0.6]'),
(5, '[0.5, 0.6, 0.7]'),
(6, '[0.6, 0.7, 0.8]'),
(7, '[0.7, 0.8, 0.9]'),
(8, '[0.8, 0.9, 1.0]'),
(9, '[0.9, 1.0, 0.1]'),
(10, '[1.0, 0.1, 0.2]');

-- 执行近似搜索,返回最相似的 5 条数据
SELECT id, vec
FROM t2
ORDER BY l2_distance(vec, '[0.1, 0.2, 0.3]')
APPROXIMATE
LIMIT 5;

返回结果如下,由于数据量较小,与上文精确搜索结果一致:

+------+---------------+
| id | vec |
+------+---------------+
| 1 | [0.1,0.2,0.3] |
| 2 | [0.2,0.3,0.4] |
| 3 | [0.3,0.4,0.5] |
| 4 | [0.4,0.5,0.6] |
| 5 | [0.5,0.6,0.7] |
+------+---------------+
5 rows in set

执行计划分析

获取上文示例的执行计划:

EXPLAIN SELECT id, vec
FROM t2
ORDER BY l2_distance(vec, '[0.1, 0.2, 0.3]')
APPROXIMATE
LIMIT 5;

返回结果如下:

+--------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------+
| ==================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------- |
| |0 |VECTOR INDEX SCAN|t2(idx)|10 |29 | |
| ==================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t2.id], [t2.vec]), filter(nil), rowset=16 |
| access([t2.id], [t2.vec]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t2.__vid_1750162978114053], [t2.__type_17_1750162978114364]), range(MIN,MIN ; MAX,MAX)always true |
+--------------------------------------------------------------------------------------------------------------------+
11 rows in set

分析如下:

  • 执行方式:

    • 采用向量索引扫描的方式,通过预构建的 HNSW 索引直接定位相似向量。对应执行计划中的 VECTOR INDEX SCAN 操作,该操作通过索引 t2(idx) 进行搜索。
    • 利用索引的图结构快速找到近邻点,无需计算所有向量的距离。对应执行计划中的 is_index_back=true 设置,表示通过索引回表获取完整数据。
    • 最终返回索引认为最相似的 5 条记录。对应执行计划中的 output([t2.id], [t2.vec]),表示返回 id 和向量数据。
  • 性能特点:

    • 优点:搜索性能高,且随数据量增长保持稳定。
    • 缺点:结果可能存在少量误差,不保证 100% 准确。
  • 适用场景:

    • 大规模数据集的实时搜索。
    • 对搜索性能要求高的场景。
    • 可以接受少量结果误差的场景。

对比总结

两种搜索方式的对比总结如下:

对比项精确搜索近似搜索
执行方式全表扫描(TABLE FULL SCAN)后排序直接通过向量索引(VECTOR INDEX SCAN)搜索
执行计划包含两个操作符:TABLE FULL SCANTOP-N SORT仅包含一个操作符:VECTOR INDEX SCAN
性能特点需要扫描全表数据并进行排序,性能随数据量增长显著下降通过索引直接定位目标数据,性能稳定
结果准确性100% 准确,保证返回真实的最近邻近似准确,可能存在少量误差
适用场景数据量小、对准确性要求高的场景大规模数据集、对性能要求高的场景

相关文档