CREATE INDEX USING IVFFLAT

向量索引可用于加速对包含向量列的表的 KNN(K-Nearest Neighbors)查询。Matrixone 目前支持具有 l2_distance 度量的 IVFFLAT 向量索引。

语法说明

向量索引可用于加速对包含向量列的表的 KNN(K-Nearest Neighbors)查询。Matrixone 目前支持具有 l2_distance 度量的 IVFFLAT 向量索引。

我们可以指定 PROBE_LIMIT 来决定要查询的聚类中心数量。PROBE_LIMIT 默认为 1,即仅扫描 1 个聚类中心。但如果您将其设置为更高的值,它会扫描更多数量的聚类中心和向量,这使得性能可能会下降一点,但准确率会上升。我们可以指定适当的探针数量来平衡查询速度和召回率。PROBE_LIMIT 的理想值为:

  • 如果总行数<1000000:PROBE_LIMIT=总行数/10

  • 如果总行数>1000000:PROBE_LIMIT=sqrt(总行数)

语法结构

> CREATE INDEX index_name
USING IVFFLAT
ON tbl_name (col,...)
LISTS=lists 
OP_TYPE "vector_l2_ops"
INCLUDE (column_name [, column_name ...])

语法释义

  • index_name:索引名称

  • IVFFLAT:向量索引类型,目前支持 vector_l2_ops

  • lists:索引中所需的分区数,必须大于 0

  • OP_TYPE:要使用的距离度量

INCLUDE (column_name, ...) 将非向量列附加到索引中,使覆盖查询可以直接返回或过滤这些列而无需额外回表。INCLUDE 列不参与向量距离计算。IVFFLAT、CAGRA 和 IVFPQ 均支持该子句:

CREATE INDEX idx_ivf USING IVFFLAT ON table_name (embedding)
    LISTS 10 OP_TYPE 'vector_l2_ops' INCLUDE (category, price);
CREATE INDEX idx_cagra USING CAGRA ON table_name (embedding)
    INCLUDE (category, price);
CREATE INDEX idx_ivfpq USING IVFPQ ON table_name (embedding)
    LISTS 4 BITS_PER_CODE 8 INCLUDE (category, price);

INCLUDE 列必须存在于表中,不能是被索引的向量列或主键列,也不能重复。IVFFLAT 最多允许 10 个 INCLUDE 列,并接受其受支持的标量列类型。CAGRA 和 IVFPQ 接受数值类型 INT32INT64FLOAT32FLOAT64。HNSW 不支持 INCLUDE

NOTE:

  • LISTS 的理想值为:

    • 如果总行数<1000000:lists=总行数/1000

    • 如果总行数>1000000:lists=sqrt(总行数)

  • 建议在数据填充完毕后再创建索引,如果在空表上创建向量索引,则所有向量量都将映射到一个分区,随着时间的推移,数据量不断增长,导致索引变得越来越大,查询性能会下降。

示例

drop table if exists t1;
create table t1(coordinate vecf32(2),class char);
-- 有七个点,每个点代表其在 x 和 y 轴上的坐标,并且每个点的 class 被标记为 A 或 B。
insert into t1 values("[2,4]","A"),("[3,5]","A"),("[5,7]","B"),("[7,9]","B"),("[4,6]","A"),("[6,8]","B"),("[8,10]","B");
--创建向量索引
create index idx_t1 using ivfflat on t1(coordinate)  lists=1 op_type "vector_l2_ops";

mysql> show create table t1;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                           |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `coordinate` vecf32(2) DEFAULT NULL,
  `class` char(1) DEFAULT NULL,
  KEY `idx_t1` USING ivfflat (`coordinate`) lists = 1  op_type 'vector_l2_ops'
) |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> show index from t1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Index_params                            | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
| t1    |          1 | idx_t1   |            1 | coordinate  | A         |           0 | NULL     | NULL   | YES  | ivfflat    |         |               | {"lists":"1","op_type":"vector_l2_ops"} | YES     | coordinate |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
1 row in set (0.01 sec)

--设置扫描的聚类中心数量
SET @PROBE_LIMIT=1;
--现在,我们有一个新点,其坐标为 (4, 4),我们想要使用 KNN 查询来预测这个点的类别。
mysql> select * from t1 order by l2_distance(coordinate,"[4,4]") asc;
+------------+-------+
| coordinate | class |
+------------+-------+
| [3, 5]     | A     |
| [2, 4]     | A     |
| [4, 6]     | A     |
| [5, 7]     | B     |
| [6, 8]     | B     |
| [7, 9]     | B     |
| [8, 10]    | B     |
+------------+-------+
7 rows in set (0.01 sec)

--根据查询结果可预测这个点的类别为 A

INCLUDE 与 SHOW 元数据

以下完整示例创建带 INCLUDE 列的 IVFFLAT 覆盖索引,并展示 INCLUDE 列表的保存位置:

DROP TABLE IF EXISTS vector_include_demo;
CREATE TABLE vector_include_demo (
    id INT PRIMARY KEY,
    embedding VECF32(3),
    category VARCHAR(20),
    price INT
);
INSERT INTO vector_include_demo VALUES
    (1, '[1, 2, 3]', 'book', 10),
    (2, '[2, 3, 4]', 'game', 20);
CREATE INDEX idx_vector_include USING IVFFLAT ON vector_include_demo (embedding)
    LISTS 1 OP_TYPE 'vector_l2_ops' INCLUDE (category, price);
SHOW CREATE TABLE vector_include_demo;
SHOW INDEX FROM vector_include_demo;
DROP TABLE vector_include_demo;

IVF 成员资格预下推

IVF 向量搜索支持成员资格预下推过滤器,可在向量相似度搜索之前应用关系谓词预过滤行。此优化通过 BY RANK WITH OPTION 子句中的 mode=pre 排名选项激活:

SELECT id, category, score
FROM table_name
WHERE category = 'cat1' AND score > 2.0
ORDER BY l2_distance(embedding, '[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1]')
LIMIT 3 BY RANK WITH OPTION 'mode=pre';

关系谓词(如 category = 'cat1' AND score > 2.0)构建候选主键过滤器来裁剪向量搜索范围。该过滤对结果透明。

预下推根据源表主键类型使用不同的内部过滤器结构:

  • 整数主键,小 ID 范围:使用密集 cbitmap。

  • 整数主键,宽 ID 跨度(> 2^23):使用紧凑的 CRoaring bitset。

  • Varchar(非整数)主键:使用 CBloomFilter(近似的、概率性的)。

实验性向量索引变量

experimental_ivf_index 外,还有两个额外的实验性系统变量控制其他向量索引类型:

  • experimental_ivfpq_index:控制 IVF-PQ(乘积量化)向量索引。默认值为 0(禁用)。

  • experimental_cagra_index:控制 CAGRA(GPU 加速图)向量索引。默认值为 0(禁用)。

这些变量可在会话或全局范围内设置:

-- 会话范围
SET experimental_ivfpq_index = 1;
SET experimental_cagra_index = 1;

-- 全局范围
SET GLOBAL experimental_ivfpq_index = 1;
SET GLOBAL experimental_cagra_index = 1;

-- 查询当前值
SELECT @@experimental_ivfpq_index, @@experimental_cagra_index;
SHOW VARIABLES LIKE 'experimental_ivfpq_index';
SHOW VARIABLES LIKE 'experimental_cagra_index';

限制

一次只支持在一个向量列上建立向量索引,如需在多个向量列上建立向量索引,可多次执行创建语句。