PolarDB MySQL版新增向量检索功能,完全兼容MySQL 9.0语法并支持InnoDB事务保证,同时提供100%召回率的精确KNN(基于列存加速)与高性能的近似ANN(基于HNSW等索引)检索。
版本要求
目前仅支持PolarDB MySQL版8.0版本且修订版本为8.0.2.2.30或以上,您可以通过内核版本说明确认集群的修订版本。
向量类型
类型定义
向量类型通过VECTOR(N)
定义。
示例
您可以通过以下方式在表t1
中定义向量类型的列v1
:
-- 以下示例表示在表t1中定义列v1的向量维度为4
CREATE TABLE t1 (id INT PRIMARY KEY, v1 VECTOR(4));
其中N表示向量维度,目前支持的最大维度为16383,每一维均为单精度浮点数(4字节)。如果定义维度超过16383,建表语句将返回错误:
CREATE TABLE t1 (id INT PRIMARY KEY, v1 VECTOR(16384)); ERROR 9040 (HY000): Data size (65536 Bytes, 16384 dimensions) exceeds VECTOR max (65532 Bytes, 16383 dimensions) for column: 'v1'
向量类型仅支持与向量类型进行等值比较,禁止与其他任意类型进行比较。
向量类型的列无法作为主键、外键、唯一键、分区键。
类型转换
STRING_TO_VECTOR
向量通过STRING_TO_VECTOR
将向量的字符串表示转换为Binary表示。
SELECT STRING_TO_VECTOR('[1,2,3,4]');
+-------------------------------+
| STRING_TO_VECTOR('[1,2,3,4]') |
+-------------------------------+
| ?? @ @@ ?@ |
+-------------------------------+
1 row in set (0.000 sec)
SELECT HEX(STRING_TO_VECTOR('[1,2,3,4]'));
+------------------------------------+
| HEX(STRING_TO_VECTOR('[1,2,3,4]')) |
+------------------------------------+
| 0000803F000000400000404000008040 |
+------------------------------------+
1 row in set (0.000 sec)
其中STRING_TO_VECTOR
的输入为向量的字符串表示,输出为向量的Binary表示。
输入格式要求:需为使用方括号包含并用英文逗号分隔的若干浮点数组成的字符串。
如果输入格式错误的字符串,表达式将返回错误:
SELECT STRING_TO_VECTOR('[1,2'); ERROR 9041 (HY000): Data cannot be converted to a valid vector: '[1,2'
VECTOR_TO_STRING
向量通过VECTOR_TO_STRING
将向量的Binary表示转换为向量的字符串表示。
SELECT VECTOR_TO_STRING(0x0000803F000000400000404000008040);
+------------------------------------------------------+
| VECTOR_TO_STRING(0x0000803F000000400000404000008040) |
+------------------------------------------------------+
| [1.00000e+00,2.00000e+00,3.00000e+00,4.00000e+00] |
+------------------------------------------------------+
1 row in set (0.000 sec)
其中VECTOR_TO_STRING
的输入为向量的Binary表示,输出为向量的字符串表示。
输入格式说明:每4个字节为向量中某一维的浮点数的Binary表示。如浮点数1的Binary表示为0x3F800000,对应上述示例中输入的前4个字节0x0000803F。
如果输入格式错误的Binary表示,表达式将返回错误,例如:
SELECT VECTOR_TO_STRING(0x0000803F000000); ERROR 9041 (HY000): Data cannot be converted to a valid vector: ''
距离计算
通过DISTANCE
函数可以采用指定方式计算两个向量之间的相似度。
SELECT DISTANCE(v1, STRING_TO_VECTOR('[1.2,2.3,3.4,4.5]'), 'COSINE') FROM t1;
其中DISTANCE
函数需要三个输入参数,前两个输入为向量,最后一个输入为相似度计算方法,目前支持的相似度计算方法包括COSINE
,DOT
和EUCLIDEAN
,相似度计算方法的参数为字符串类型,必须使用引号进行包裹。
参数说明
参数 | 说明 |
| 余弦相似度。 说明 衡量两个向量之间的方向相似性,结果为两个向量夹角的余弦值。 |
| 点积。 说明 两个向量对应分量相乘后再相加的结果。 |
| 欧式距离。 说明 衡量两个向量或点在欧几里得空间中的直线距离。 |
向量写入
创建包含向量列的新表
CREATE TABLE t1 (id INT PRIMARY KEY, v1 VECTOR(4));
将向量列添加到现有表中
ALTER TABLE t1 ADD COLUMN v1 VECTOR(4);
插入向量
向量通过STRING_TO_VECTOR
以字符串的形式插入。
INSERT INTO t1 VALUES (1, STRING_TO_VECTOR('[1,2,3,4]'));
向量可以直接以Binary的形式插入。
INSERT INTO t1 VALUES (1, 0x0000803F000000400000404000008040);
更新/插入向量
向量通过STRING_TO_VECTOR
以字符串的形式插入或更新。同时,也支持直接以Binary的形式插入或更新。
INSERT INTO t1 VALUES (1, STRING_TO_VECTOR('[1,2,3,4]')) ON DUPLICATE KEY UPDATE v1 = STRING_TO_VECTOR('[1,2,3,4]');
更新向量
向量通过STRING_TO_VECTOR
以字符串的形式更新。同时,也支持直接以Binary的形式更新。
UPDATE t1 SET v1 = STRING_TO_VECTOR('[1,2,3,4]') WHERE id = 1;
删除向量
向量通过STRING_TO_VECTOR
以字符串的形式删除。同时,也支持直接以Binary的形式删除。
DELETE FROM t1 WHERE v1 = STRING_TO_VECTOR('[1,2,3,4]');
使用向量索引
创建向量索引
类似于创建列存索引,PolarDB支持通过修改列的备注信息在列存索引中创建向量索引。向量索引所使用的算法及相关参数均通过备注信息进行指定。
备注信息说明
COMMENT "imci_vector_index=向量索引算法(索引参数列表) 其他备注信息"
格式说明
参数 | 说明 |
向量索引算法 | 指定构建向量索引的算法;当前版本仅支持HNSW,后续版本将支持更多算法。 |
索引参数列表 |
|
HNSW算法支持参数说明
参数 | 可用别名 | 作用 | 可选值 / 范围 | 默认值 |
metric | distance | 向量相似度度量 |
| cosine |
max_degreee | M | 图中节点的最大连接度 | 正整数 | 16 |
ef_construction | - | 构建阶段的候选邻居数量 | 正整数 | 200 |
CREATE TABLE时添加向量索引
-- 创建表级列存索引,列存索引初始化时会自动根据v1列上的备注信息创建向量索引
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
v1 vector(4) COMMENT "imci_vector_index=HNSW(metric=cosine,max_degree=16;ef_construction=300)"
) COMMENT "COLUMNAR=1";
-- 或者仅为v1列创建列存索引,列存索引初始化时会自动根据v1列上的备注信息创建向量索引
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
description TEXT,
v1 vector(4) COMMENT "COLUMNAR=1 imci_vector_index=HNSW(metric=cosine,max_degree=16;ef_construction=300)"
);
ALTER TABLE动态添加向量索引
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
v1 vector(4)
);
-- 添加表级列存索引同时修改VECTOR列备注信息指定向量索引算法及参数
ALTER TABLE t1 comment "COLUMNAR=1", MODIFY COLUMN v1 vector(4) COMMENT "imci_vector_index=HNSW(metric=cosine,max_degree=16,ef_construction=300)";
-- 或者 仅为v1列创建列存索引,列存索引初始化时会自动根据v1列上的备注信息创建向量索引
ALTER TABLE t1 MODIFY COLUMN v1 vector(4) COMMENT "COLUMNAR=1 imci_vector_index=HNSW(metric=cosine,max_degree=16,ef_construction=300)";
或者
-- CREATE TABLE时表上没有任何列存索引,不会根据v1列上的备注信息创建向量索引
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
v1 vector(4) COMMENT "imci_vector_index=HNSW(metric=cosine,max_degree=16,ef_construction=300)"
);
-- 创建表级列存索引,列存索引初始化时会自动根据v1列上的备注信息创建向量索引
ALTER TABLE t1 COMMENT "COLUMNAR=1";
构建IMCI中的向量索引,在表上或者向量索引列上构建列存索引是前置要求,即仅列存索引只读节点才会构建向量索引以支持向量检索。
参数说明
参数名 | 说明 |
imci_enable_inline_vector_index | 是否允许创建向量索引。
|
imci_vector_index_dump_rows_threshold | 用于控制向量索引增量写入大小。后台任务定期检查当前向量索引快照位点与列存索引快照位点间的增量,当增量行数超过该阈值时提交后台任务将新增数据行追加到向量索引中。 取值范围为:1-4294967295。默认值为1000。单位行。 |
删除向量索引
删除列存索引时删除向量索引
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
v1 vector(4) COMMENT "imci_vector_index=HNSW(metric=cosine,max_degree=16,ef_construction=300)") COMMENT 'COLUMNAR=1';
-- 向量索引不能独立于列存索引存在,会被级联删除
ALTER TABLE t1 COMMENT 'COLUMNAR=0';
向量查询
近似最近邻检索
使用限制
满足下列约束条件时,SQL语句才能使用向量索引加速近似最近邻检索功能:
SQL语句中必须同时包含
ORDER BY
和LIMIT
。ORDER BY
中首个表达式必须是DISTANCE
,且排序方向必须为升序 (ASC)。DISTANCE
表达式中的字段必须存在可用的向量索引。DISTANCE
表达式中的距离函数必须与创建向量索引时使用的距离函数保持一致。例如,如果向量索引采用COSINE
距离构建,则DISTANCE函数也必须指定COSINE。若SQL包含
JOIN
,执行计划必须采用右深树(right-deep tree)结构,且DISTANCE表达式中引用的字段必须来自JOIN的驱动表。SQL语句中不能包含
GROUP BY
。
操作步骤
将参数
imci_enable_vector_search
的值设置为ON,来开启向量索引加速近似最近邻检索功能。开启后优化器会选择合适的查询语句使用向量索引加速近似最近邻检索。SET imci_enable_vector_search = ON;
将参数cost_threshold_for_imci的值设置为0,来强制SQL语句使用列存执行计划,否则SQL语句可能会因为预估代价低于行列分流阈值而使用行存执行计划(参见配置行列手动分流),无法使用向量索引加速近似最近邻检索功能。
SET cost_threshold_for_imci = 0;
执行满足约束条件的SQL即可使用向量索引完成近似最近邻检索。
SELECT * FROM t1 ORDER BY DISTANCE(v1, STRING_TO_VECTOR('[1.2, 2.3, 3.4, 4.5]'), 'COSINE') LIMIT 2;
您可以通过EXPLAIN语句来判断在SQL语句中使用的向量索引加速近似最近邻检索功能是否生效。如果执行计划中包含
Vector Search
,则表示向量索引加速近似最近邻检索功能生效。EXPLAIN SELECT * FROM t1 ORDER BY DISTANCE(v1, STRING_TO_VECTOR('[1.2, 2.3, 3.4, 4.5]'), 'COSINE') LIMIT 2; +----+---------------------------+------+---------------------------------------------------------------------------------------+ | ID | Operator | Name | Extra Info | +----+---------------------------+------+---------------------------------------------------------------------------------------+ | 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = unlimited) | | 2 | └─Compute Scalar | | | | 3 | └─Limit | | Offset=0 Limit=2 | | 4 | └─Sort | | Sort Key: VECTOR_DISTANCE(t1.v1,"[1.200000,2.300000,3.400000,4.500000]","COSINE") ASC | | 5 | └─Vector Search | t1 | | +----+---------------------------+------+---------------------------------------------------------------------------------------+ 5 rows in set (0.001 sec)
参数说明
您需要在数据库中将imci_enable_vector_search
参数的值设置为ON
来使用向量索引加速近似最近邻检索,开启后优化器会选择合适的查询语句使用向量索引加速近似最近邻检索。
参数名称 | 参数说明 |
imci_enable_vector_search | 使用向量索引加速近似最近邻检索的控制开关。 取值范围如下:
|
查看向量
SELECT VECTOR_TO_STRING(v1) FROM t1;
精确最近邻检索
SELECT id, VECTOR_TO_STRING(v1) FROM t1 ORDER BY DISTANCE(v1, STRING_TO_VECTOR('[1.2,2.3,3.4,4.5]'), 'COSINE') LIMIT 1;
包含谓词的向量查询
您可以使用额外的列作为谓词,来过滤向量查询结果。例如:
SELECT * FROM t1 WHERE id < 10 ORDER BY DISTANCE(v1, STRING_TO_VECTOR('[1.2, 2.3, 3.4, 4.5]'), 'COSINE') LIMIT 2;
在使用包含谓词的SQL语句进行向量查询时,可以通过调整imci_vector_search_filter_pct
参数的值来控制向量索引召回和谓词过滤的先后顺序。
参数说明
参数名称 | 参数说明 |
imci_vector_search_filter_pct | 当谓词过滤的预估选择率大于或等于该参数值时,优先使用向量索引召回。 取值范围为0-100,默认值为20。单位%。 表示当谓词的预估选择率大于或等于20%时,优先使用向量索引召回,然后再使用谓词过滤召回结果。 |
向量索引监控
向量索引数据构建任务与列存索引数据快照推进属于不同的后台任务。在持续写入的情况下,向量索引快照位点可能会滞后于列存数据快照。在执行向量检索之前,您需要确认向量索引的可用性。IMCI向量索引通过系统视图展示了向量索引的状态,包括向量索引快照位点以及向量列上向量索引的状态。
向量索引快照位点
INFORMATION_SCHEMA.IMCI_INDEX_STATS
视图中的VECTOR_ROWS
列用于显示列存索引已加载的向量索引快照中的向量数量。若该值为0,说明当前列存索引上暂无可用的向量索引:要么表中尚未存在任何向量索引,要么刚创建的向量索引尚未生成有效向量索引快照。
您还可以把该值与INFORMATION_SCHEMA.IMCI_INDEXES
视图中的ROW_ID
列进行对比,以粗略评估向量索引数据的构建延迟。即便存在延迟情况,向量索引仍可正常使用;检索时,系统会自动处理尚未写入向量数据。
物理向量索引状态
INFORMATION_SCHEMA.IMCI_VECTOR_INDEX_STATS系统视图展示了向量索引快照内部各个物理向量索引的状态信息,其表结构说明如下:
列名 | 说明 |
SCHEMA_NAME | 库名。 |
TABLE_NAME | 表名。 |
COLUMN_NAME | 向量列名。 |
VECTORS | 向量索引中实际的向量数目,因为剔除了NULL标记值以及构建时已删除的行,一般比VECTOR_ROWS小。 |
MEMORY_USAGE | 内存用量。 |
STORAGE_USAGE | 持久化文件大小。 |
INDEX_TYPE | 索引类型,目前仅支持HNSW。 |
INDEX_PARAMETERS | JSON表示的向量索引构建参数。 |
该视图输出的是每个开启向量索引列对应的向量索引的内存状态及统计信息,与向量索引可用性没有直接关联。
任何未包含在该视图查询结果中的列,都无法进行近似向量检索。
在该视图中,若VECTORS列显示为 0,并不代表向量索引不可用。这通常是因为集群重启后尚未执行增量构建或近似查询,向量索引的持久化数据尚未加载,因而暂时无法获取准确的向量数量。请以系统视图
INFORMATION_SCHEMA.IMCI_INDEX_STATS
中的VECTOR_ROWS
列作为向量快照的准确信息来源。
操作示例
确保以下在少量数据的情况下能够正常构建向量索引,需要在列存索引只读节点上将全局参数imci_vector_index_dump_rows_threshold
设置为1。
SET GLOBAL imci_vector_index_dump_rows_threshold=1;
例如,若使用如下语句建表:
CREATE TABLE t1 (
id int auto_increment PRIMARY KEY,
v1 vector(4) COMMENT "imci_vector_index=HNSW(metric=cosine,max_degree=16,ef_construction=300)"
) comment "COLUMNAR=1";
然后向其中写入2条数据:
INSERT INTO t1 VALUES(1, STRING_TO_VECTOR('[1.1,1.2,1.3,1.4]')), (2, STRING_TO_VECTOR('[2,2.2,2.4,2.6]'));
然后检查索引快照状态以及向量索引状态:
SELECT schema_name,table_name,row_id FROM information_schema.imci_indexes;
+-------------+------------+--------+
| schema_name | table_name | row_id |
+-------------+------------+--------+
| test | t1 | 2 |
+-------------+------------+--------+
1 row in set (0.00 sec)
SELECT schema_name,table_name,vector_rows FROM information_schema.imci_index_stats;
+-------------+------------+-------------+
| schema_name | table_name | vector_rows |
+-------------+------------+-------------+
| test | t1 | 2 |
+-------------+------------+-------------+
1 row in set (0.00 sec)
SELECT schema_name,table_name,column_name,vectors FROM information_schema.imci_vector_index_stats;
+-------------+------------+-------------+---------+
| schema_name | table_name | column_name | vectors |
+-------------+------------+-------------+---------+
| test | t1 | v1 | 2 |
+-------------+------------+-------------+---------+
1 row in set (0.00 sec)
再执行如下写入:
INSERT INTO t1 VALUES(3, STRING_TO_VECTOR("[8.8,8.88,8.888,8.8888]"));
可以观察到INFORMATION_SCHEMA.IMCI_VECTOR_INDEX_STATS的相关查询返回结果中VECTORS字段的值为3(增加了1),表示上述INSERT的数据已被后台任务写入向量索引中:
mysql> SELECT schema_name,table_name,column_name,vectors FROM information_schema.imci_vector_index_stats;
+-------------+------------+-------------+---------+
| schema_name | table_name | column_name | vectors |
+-------------+------------+-------------+---------+
| test | t1 | v1 | 3 |
+-------------+------------+-------------+---------+
1 row in set (0.00 sec)
接着重启列存索引只读节点后检查索引状态:
SELECT schema_name,table_name,row_id,state FROM information_schema.imci_indexes;
+-------------+------------+--------+-----------+
| schema_name | table_name | row_id | state |
+-------------+------------+--------+-----------+
| test | t1 | 3 | COMMITTED |
+-------------+------------+--------+-----------+
1 row in set (0.00 sec)
SELECT schema_name,table_name,vector_rows FROM information_schema.imci_index_stats;
+-------------+------------+-------------+
| schema_name | table_name | vector_rows |
+-------------+------------+-------------+
| test | t1 | 3 |
+-------------+------------+-------------+
1 row in set (0.00 sec)
SELECT schema_name,table_name,column_name,vectors FROM information_schema.imci_vector_index_stats;
+-------------+------------+-------------+---------+
| schema_name | table_name | column_name | vectors |
+-------------+------------+-------------+---------+
| test | t1 | v1 | 0 |
+-------------+------------+-------------+---------+
1 row in set (0.00 sec)
可以看到,VECTORS为0,同时向量索引快照位点为3。通过执行计划来确认向量索引的可用性,并在执行近似查询后再次检查向量索引状态:
SET cost_threshold_for_imci = 0;
EXPLAIN SELECT * FROM t1 ORDER BY DISTANCE(v1, STRING_TO_VECTOR("[1.2, 2.3, 3.4, 4.5]"), "COSINE") LIMIT 1;
+----+-----------------------+------+--------+--------+---------------------------------------------------------------------------------------+
| ID | Operator | Name | E-Rows | E-Cost | Extra Info |
+----+-----------------------+------+--------+--------+---------------------------------------------------------------------------------------+
| 1 | Select Statement | | | | IMCI Execution Plan (max_dop = 4, max_query_mem = 858993459) |
| 2 | +-Compute Scalar | | | | |
| 3 | +-Limit | | | | Offset=0 Limit=1 |
| 4 | +-Sort | | | | Sort Key: VECTOR_DISTANCE(t1.v1,"[1.200000,2.300000,3.400000,4.500000]","COSINE") ASC |
| 5 | +-Vector Search | t1 | | | |
+----+-----------------------+------+--------+--------+---------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)
SELECT id, vector_to_string(v1) FROM t1 ORDER BY DISTANCE(v1, STRING_TO_VECTOR("[1.2, 2.3, 3.4, 4.5]"), "COSINE") LIMIT 1;
+----+---------------------------------------------------+
| id | vector_to_string(v1) |
+----+---------------------------------------------------+
| 2 | [2.00000e+00,2.20000e+00,2.40000e+00,2.60000e+00] |
+----+---------------------------------------------------+
1 row in set (0.00 sec)
SELECT schema_name,table_name,column_name,vectors FROM information_schema.imci_vector_index_stats;
+-------------+------------+-------------+---------+
| schema_name | table_name | column_name | vectors |
+-------------+------------+-------------+---------+
| test | t1 | v1 | 3 |
+-------------+------------+-------------+---------+
1 row in set (0.00 sec)
可以观察到执行近似查询后向量索引被加载到内存,向量个数也恢复为3。