最近更新时间:2024-11-26 20:01:31
向量表即存储向量数据的表。本节将通过具体示例演示如何创建向量表。所有示例中使用的语法均遵循 SQL:1999 标准,并兼容部分 SQL:2003 特性。
前提条件
环境中存在向量版数仓服务单元。
该向量版数仓服务单元中存在至少一个数据库。
语法
CREATE TABLE <table_name>
(
C1 <data_type>,
C2 <data_type>,
......,
CN <vector_type>(128),
PRIMARY KEY (<col_name1>[, <col_name2>, ... , <col_nameN>])
) DISTRIBUTED BY (C1);
表中的向量列(<vector_type>
)括号中的数字表示向量的维度,即 <vector_type>(128)
表示向量维度为 128。下表描述了 Relyt Vector DPS 支持的向量列数据类型:
数据类型 | 描述 |
vecf16 | 数据类型为 16 位浮点数组, |
vector | 数据类型为 32 位浮点数组, |
与 vector
相比,vecf16
不仅存储成本小一倍,同时计算性能快一倍,且准度相同,因此更为推荐使用。
示例
执行如下命令,创建一个名为 FACE_TABLE
的堆表,其中 C1
为主键,`C4` 为向量列。
CREATE TABLE FACE_TABLE (
C1 INT,
C2 TIMESTAMP NOT NULL,
C3 VARCHAR(20) NOT NULL,
C4 VECF16(512) NOT NULL
PRIMARY KEY (C1)
) DISTRIBUTED BY (C1);
使用分区表管理增量数据
对于具备时间属性的数据(例如数据按时间维度导入,保留 N
天,超出时间过期),可以使用 PARTITION BY
语句将表划分成多个子表,可以对子表单独进行导入和 TRUNCATE
,从而支持增量的表数据管理。
如下为示例语句:
CREATE TABLE test_tbl
(
C1 VARCHAR,
C2 VECF16(512),
post_publish_time TIMESTAMP
)
DISTRIBUTED BY (C1)
PARTITION BY RANGE (post_publish_time) (START (DATE '2024-08-01') INCLUSIVE END (DATE '2024-08-31') EXCLUSIVE EVERY(INTERVAL '1 day'), DEFAULT PARTITION extra);
在处理大型数据集或需要快速访问和检索数据的场景(数据库查询优化、机器学习和数据挖掘、图像和视频检索、空间数据查询等)中,创建向量索引是加速向量检索的有效方式,可以提高查询性能、加速数据分析和优化搜索任务,从而提高系统的效率和响应速度。
背景介绍
Vector DPS 采用了主流的 HNSW(Hierarchical Small World Graph)算法,将 skip list 的概念与 NSW(Navigable Small World)图相结合,通过分层结构实现了高效的近似最近邻搜索。在该结构中,上层包含较长的边,用于快速定位目标,而下层则包含较短的边,以提升搜索精度。
在构建图时,可以通过调整参数m 来控制新节点与其最近邻节点的连接数量。较高的m 值会使图结构更加密集,节点之间的连接增多,从而提升搜索性能,但同时会增加内存消耗并延长插入时间。在节点插入时,算法会找到最近的m 个节点,并与它们建立双向连接。
此外,Vector DPS 还支持量化(Product Quantization,PQ)功能,可对高维向量进行降维处理。通过在索引中存储降维后的向量,可以减少回表操作的次数,从而提高向量插入和查询时的检索性能。
语法
CREATE INDEX <index_name>
ON <schema_name>.<table_name>
USING vectors (<column_name> <distance_measure>)
WITH (options = $$
<common_option_key1> = <common_option_value1>
<common_option_key2> = <common_option_value2>
...
[indexing.hnsw]
<hnsw_option_key1> = <hnsw_option_value1>
<hnsw_option_key2> = <hnsw_option_value2>
...
$$);
参数说明
1. <index_name>
索引名称,为可选参数。
2. <schema_name>
Schema 名称。
3. <table_name>
表名称。
4. <column_name>
向量索引列名称。
5. <distance_measure>
相似度距离度量算法,其表示形式为 <vector_data_type>_<distance_type>_ops。可选值包括:
vecf16_l2_ops: 16 位浮点数类型的平方欧式距离
vecf16_dot_ops: 16 位浮点数类型的负点积距离
vecf16_cos_ops: 16 位浮点数类型的余弦距离
vector_l2_ops: 32 位浮点数类型的平方欧式距离
vector_dot_ops: 32 位浮点数类型的负点积距离
vector_cos_ops: 32 位浮点数类型的余弦距离
其它可选通用向量索引参数(<common_option_n>)说明如下表所示:
键 | 类型 | 取值范围 | 默认值 | 说明 |
optimizing.optimizing_threads | integer | [1, 65535] | 1 | 构建索引的最大线程数。 |
optimizing.sealing_secs | integer | [1, 60] | 60 | 构建索引合并探测时间。 |
segment.max_growing_segment_size | integer | [1, 4_000_000_000] | 20_000 | 未创建索引的向量的最大大小。 |
segment.max_sealed_segment_size | integer | [1, 4_000_000_000] | 1_000_000 | 用于索引创建的向量的最大大小。 |
HNSW 算法的相关参数(HNSW_OPTION)说明如下表所示:
键 | 类型 | 取值范围 | 默认值 | 说明 |
m | integer | [4, 128] | 12 | 节点的最大度数。 |
ef_construction | integer | [10, 2000] | 300 | 构建中的搜索范围。 |
quantization | table | trivial、scalar 或product | N/A | 可选值为:trivial:不使用量化 scalar:使用标量量化product:使用乘积量化(推荐)计算距离使用的量化算法。 |
quantization.product
的选项:
键 | 类型 | 取值范围 | 默认值 | 说明 |
sample | integer | [1, 1_000_000] | 65535 | 用于量化的样本。 |
ratio | enum | “x4”、“x8”、“x16”、“x32”、“x64” | "x4" | 量化的压缩比。 |
示例
假设有一个文本知识库,将文章分割成块(Chunk)后,转换为 512 维的 Embedding 向量,最后存入数据库中,其中切割生成的 docs 表包含以下字段:
字段 | 类型 | 说明 |
id | serial | 编号。 |
chunk | varchar(1024) | 文章切块后的文本块。 |
intime | timestamp | 文章的入库时间。 |
url | varchar(1024) | 文本块所属文章的链接。 |
embedding | vecf16(512) | 文本块 Embedding 向量。 |
创建存储向量的数据表。
CREATE TABLE docs (
id SERIAL PRIMARY KEY,
chunk VARCHAR(1024),
intime TIMESTAMP,
url VARCHAR(1024),
embedding VECF16(512)
) DISTRIBUTED BY (id);
将向量列的存储模式设置为PLAIN,以降低数据行扫描成本,获得更好的性能。
ALTER TABLE docs ALTER COLUMN embedding SET STORAGE PLAIN;
对向量列建立向量索引。
-- 创建欧氏距离度量的向量索引。
CREATE INDEX idx_docs_feature_l2 ON docs USING vectors(embedding vecf16_l2_ops)
WITH (options = $$
optimizing.optimizing_threads = 3
segment.max_growing_segment_size = 100000
segment.max_sealed_segment_size = 8000000
[indexing.hnsw]
m=30
ef_construction=500
$$);
为常用的结构化列建立索引,提升融合查询速度。
CREATE INDEX ON chunks(intime);
相关参考
支持的运算符类型
名称 | 描述 | 公式定义 |
<-> | 平方欧氏距离 | |
<#> | 负点积 | |
<=> | 余弦距离 |
向量运算符的使用示例:
-- 平方欧氏距离
SELECT '[1, 2, 3]'::vector <-> '[3, 2, 1]'::vector;
-- 负点积
SELECT '[1, 2, 3]'::vector <#> '[3, 2, 1]'::vector;
-- 余弦距离
SELECT '[1, 2, 3]'::vector <=> '[3, 2, 1]'::vector;
向量数据导入
向量的数据导入和普通的堆表数据导入相同,可以采用 INSERT
语法,也可以采用 COPY
语法。
本文以 INSERT
语法为例进行介绍。
-- 向量列采用字符串的方式表示,其格式为浮点型 JSON 数组
INSERT INTO docs VALUES (default, 'xxx', '2023-05-04', 'aaa.bbb.ccc/xxx.pdf',
'[0.1, 0.2, 0.1, 0.3, ... 0.9]');
对于向量列的搜索会使用到 HNSW 索引,此方式搜索速度较快,但得到的结果是一个近似的结果,一般召回率都可以达到 95% 以上。
语法
如下以欧氏距离为例:
SELECT ID, <vector_column_name> <-> '[0.1,0.2,0.3...]' as distance FROM <table_name> ORDER BY <order_column_name> <-> '[0.1,0.2,0.3...]' LIMIT <top_k>;
使用说明
如果没有建立索引,上述近似的索引检索将退化为精确检索,该检索方式速度较慢,但准确率为 100%。
在使用向量索引时,ORDER BY
语句必须包含 <->
、<#>
或 <=>
等操作符,否则不能有效使用向量索引的加速能力。同时, <->
、<#>
或 <=>
等操作符必须有对应距离度量的向量索引存在,否则也不能使用向量索引的加速能力。支持的操作符及其用法,请参见本文 “向量索引”部分。
示例
以 向量索引 中的知识库为例,如果我们要通过文本搜索它的来源文章,那么我们就可以直接通过向量索引检索进行查找。
具体 SQL 如下:
SELECT id, chunk, intime, url, embedding <-> '[10,2.0,..., 1536.0]' as distance FROM docs
ORDER BY
embedding <-> '[10,2.0,..., 1536.0]'
LIMIT 100;
纯净模式
鼠标选中内容,快速反馈问题