11---
22title : MiniOB 向量数据库
33---
4+
45# MiniOB 向量数据库
56
67## 向量搜索
@@ -10,6 +11,7 @@ title: MiniOB 向量数据库
1011### 向量(Vector)是什么
1112
1213向量是一种表示多维特征的数据结构。每个向量由一组数值组成,这些数值通常对应于某种特定的特征或属性。例如,在图像处理中,一个向量可以表示图像的颜色、纹理等特征。为了更有效地管理非结构化数据,常见的做法是将其转换为向量表示,并存储在向量数据库中,这种转换过程通常被称为 Embedding。通过将文本、图像或其他非结构化数据映射到高维向量空间,我们可以捕捉数据的语义特征和潜在关系。单词、短语或整个文档以及图像、音频和其他类型的数据都可以表示成向量,例如,我们可以将下面的文本表示成向量:
14+
1315```
1416"West Highland White Terrier": [0.0296700,0.0231020,0.0166550,0.0642470,-0.0110980, ... ,0.0253750]
1517```
@@ -30,188 +32,103 @@ title: MiniOB 向量数据库
3032
3133注意:在实现向量数据库相关题目时,不限制向量检索算法的实现方式,可以基于开源的第三方库实现,也可以自行实现。
3234
33- ### 题目一:向量类型基础功能
34- * 向量类型
35- * 语法:` vector(size) ` ,其中,size 表示向量的维度(必须指定)
36- * 最大支持维度为 16000(在基础功能中只需要支持最大 1000 维向量即可)
37- * 向量类型中的浮点数最多保留两位小数,并且去掉多余的0
38- * 向量类型中每个元素都是数值类型(包括int 和 float 类型)。
39- * 支持创建包含向量类型的表:
40- ``` sql
41- CREATE TABLE items (id int , embedding vector(3 ));
42- ```
43- * 支持插入向量类型的记录(注意:这里需要支持将字符串类型的值转换为向量类型存储):
44- ``` sql
45- INSERT INTO items VALUES (1 , ' [1,2,3]' );
46- ```
47- * 支持向量类型的算术运算(加法(+),减法(-),乘法(* ),比较运算):
35+ ### MiniOB 向量类型
36+
37+ VECTOR 是一种结构,最多可以容纳指定数量的条目 N,定义如下:
38+
4839``` sql
49- select embedding + ' [1.5,2.3,3.3] ' , embedding - ' [1,2,3] ' , ' [1,2,3] ' - embedding from items where embedding > ' [0,0,0] ' ;
40+ VECTOR(N)
5041```
51- 其中,算术运算为逐个元素运算,如 ` [1,2,3] + [1,1,1] = [2,3,4], [1,2,3] - [1,1,1]=[0,1,2], [1,2] * [1,3] = [1,6] ` ;比较运算为逐个元素的字典序比较。即两个向量比较时,从左到右逐个数值进行比较,如果某个位置的数值不同,则根据该位置的数值大小比较结果作为向量的比较结果,举例:` [1,2,3]<[1,2,4], [2,1,2]>[1,2,2] `
52-
53- * 支持距离表达式计算:
54- * l2_distance
55- * 语法:l2_distance(vector A, vector B)
56- * 计算公式:$[ D = \sqrt{\sum_ {i=1}^{n} (A_ {i} - B_ {i})^2} ] $
5742
58- * cosine_distance:
59- * 语法:cosine_distance(vector A, vector B)
60- * 计算公式:$[ D = 1 - \frac{\mathbf{A} \cdot \mathbf{B}}{|\mathbf{A}| |\mathbf{B}|} = 1 - \frac{\sum_ {i=1}^{n} A_i B_i}{\sqrt{\sum_ {i=1}^{n} A_i^2} \sqrt{\sum_ {i=1}^{n} B_i^2}} ] $
43+ 每个条目是一个 4 字节(单精度)浮点数值。
6144
62- * inner_product:
63- * 语法:inner_product(vector A, vector B)
64- * 计算公式:$[ D = \mathbf{A} \cdot \mathbf{B} = a_1 b_1 + a_2 b_2 + ... + a_n b_n = \sum_ {i=1}^{n} a_i b_i ] $
45+ 默认长度为 2048;最大条目数为 16383。要声明一个使用默认长度的 VECTOR 列,应定义为 ` VECTOR ` 而不带括号;尝试以 ` VECTOR() ` (空括号)方式定义列将引发语法错误。
6546
66- * 距离表达式的计算精度为保留2位小数。
47+ VECTOR 不能与任何其他类型进行比较。它可以与其他 VECTOR 进行相等性比较,但不支持其他比较操作。
6748
68- ### 题目二:向量类型扩展
49+ - 支持创建包含向量类型的表:
6950
70- 支持使用列表(如:` [1,2,3] ` )来表示向量:
7151``` sql
72- select embedding + [ 1 . 5 , 2 . 3 , 3 . 3 ], embedding - ' [1,2,3] ' ,[ 1 , 2 , 3 ] - embedding from items where embedding > [ 0 , 0 , 0 ] ;
52+ CREATE TABLE items (id int , embedding vector( 3 )) ;
7353```
7454
75- ### 题目三:高维向量
55+ - 支持插入向量类型的记录(注意:这里需要支持 ` STRING_TO_VECTOR ` 函数将字符串类型的值转换为向量类型存储):
7656
77- * 需要支持最大 16000 维向量的存储和检索。
78- * 不需要考虑在高维向量上建立向量索引。
79- * 高维向量的存储可以参考 TEXT 类型的实现。
57+ ``` sql
58+ INSERT INTO items VALUES ( 1 , STRING_TO_VECTOR( ' [1,2,3] ' ));
59+ ```
8060
81- ### 题目四:向量索引(一)
82- 在本次赛题中,需要实现 IVF-Flat 向量索引,下面简单介绍 IVF-Flat 向量索引的工作原理及相关语法。
83- IVF-Flat 是一种常见的高效近似最近邻(Approximate Nearest Neighbor,ANN)搜索算法,尤其适用于大型、高维向量数据集。它通过一种称为倒排文件索引(Inverted File Index)的机制来加速向量检索。IVF-Flat 的主要思想是将所有的高维向量分为多个簇,然后在每个簇内进行精确的向量搜索。这种方法通过减少需要比较的向量数量,大大提高了搜索速度。
61+ - 支持用于处理 VECTOR 值的 SQL 函数。
8462
85- 具体来说,IVF-Flat 包括两个主要步骤:
63+ | 名称 | 描述 |
64+ | ------------------ | ------------------------------------------------ |
65+ | DISTANCE() | 根据指定的方法计算两个向量之间的距离 |
66+ | STRING_TO_VECTOR() | 获取由符合格式的字符串表示的 VECTOR 列的二进制值 |
67+ | VECTOR_TO_STRING() | 获取 VECTOR 列的字符串表示,给定其二进制值 |
8668
87- * 向量分组(簇划分):将所有向量通过聚类算法(如 K-Means)分为多个簇。每个簇都有一个中心点(质心),所有向量都分配到离它最近的质心。下面的左图表示将所有向量分为若干个簇。
69+ ** DISTANCE(vector, vector, string) **
8870
89- * 倒排文件索引:建立一个倒排文件索引,将向量的索引存储在对应簇的列表中。然后,通过这个索引来快速锁定需要比较的向量集合。下面的右图表示向量索引检索的过程。
71+ 计算两个向量之间的距离,根据指定的计算方法。它接受以下参数:
9072
91- ![ ivfflat] ( images/ivfflat.png )
92- 以图像搜索为例的 IVF-Flat 向量索引工作流程如下:
93- 1 . 首先使用 K-Means 算法将所有图像的特征向量分成 1000 个簇。每个簇表示一部分相似的图片。例如,簇 1 可能包含大部分是风景图像的向量,簇 2 可能包含大部分是人物图像的向量,以此类推。对于每个簇,向量索引都维护一个倒排文件索引,存储属于这个簇的所有图像的索引。
94- 比如,簇 1 对应的倒排文件索引可能包括 [ image_23, image_45, image_78...] ,这些是属于簇 1 的图像的索引。
95- 2 . 查询过程:用户指定一张新图像进行搜索。首先,将这张图片通过同样的特征提取模型转换成一个高维向量。然后,通过计算这个向量与1000个质心的距离,找到离它最近的几个质心(假设是前5个)。在这几个质心对应的簇中,你进一步进行精确的向量搜索,找到最相似的图像。
73+ - 一个 VECTOR 数据类型的列。
74+ - 一个 VECTOR 数据类型的输入查询。
75+ - 一个字符串,指定了距离度量方式。支持的值有 COSINE、DOT 和 EUCLIDEAN。由于该参数是字符串,因此必须加引号。
9676
77+ - l2_distance
9778
98- 向量索引语法:
99- ``` sql
100- CREATE VECTOR INDEX vector_idx
101- ON items (embedding)
102- WITH (distance= l2_distance, type= ivfflat, lists= 245 , probes= 5 );
103- ```
104- 其中 embedding 是向量索引列,必须指定是 vector 类型,` VECTOR INDEX ` 必须搭配使用。vector_idx 是向量索引名,` WITH ` 后面为创建向量索引的基本参数, 括号内部是一个表达式列表 其中的 ` distance ` 表示距离算法,必须是 ` inner_product ` ,` l2_distance ` ,` cosine_distance ` 其中的一种,` type ` 为索引算法类型,当前只支持 ivfflat。` lists ` 为 ivfflat 索引构建期间创建的簇的数量。` probes ` 为一个向量检索时参数,用于确定查询期间要查询的簇的数量。注意:所有的关键字都是大小写不敏感的。
79+ - 语法:l2_distance(vector A, vector B)
80+ - 计算公式:$[ D = \sqrt{\sum_ {i=1}^{n} (A_ {i} - B_ {i})^2} ] $
10581
106- 邻近向量检索语法:
107- ``` sql
108- select column_name1,column_name2, ... from table_name order by vector_distance_func(vector_column_name, ' [float0,float1,……]' ) limit K;
109- ```
110- * vector_distance_func是向量距离表达式:
111- * l2_distance
112- * inner_product
113- * cosine_distance
114- * 要求order by子句表达式必须是一个向量距离表达式,且目前只支持向量列与常量向量
115- * 要求limit子句必须是一个整数常量表达式
82+ - cosine_distance:
11683
117- 本题目中只需要支持:
84+ - 语法:cosine_distance(vector A, vector B)
85+ - 计算公式:$[ D = 1 - \frac{\mathbf{A} \cdot \mathbf{B}}{|\mathbf{A}| |\mathbf{B}|} = 1 - \frac{\sum_ {i=1}^{n} A_i B_i}{\sqrt{\sum_ {i=1}^{n} A_i^2} \sqrt{\sum_ {i=1}^{n} B_i^2}} ] $
11886
119- 1 . 创建 Ivf-Flat 向量索引(本题目不考察 ANN 查询)。
120- 2 . 当查询为邻近向量检索且命中向量索引时,需要将 order by + limit 的查询计划改写为通过向量索引进行检索的查询计划。
87+ - inner_product:
88+ - 语法:inner_product(vector A, vector B)
89+ - 计算公式:$[ D = \mathbf{A} \cdot \mathbf{B} = a_1 b_1 + a_2 b_2 + ... + a_n b_n = \sum_ {i=1}^{n} a_i b_i ] $
12190
122- 向量索引检索的查询计划示例如下:
123- ``` sql
124- EXPLAIN SELECT C1, L2_DISTANCE(C1, ' [1,2,3]' ) FROM TEST ORDER BY L2_DISTANCE(' [1,2,3]' , C1) LIMIT 3 ;
91+ ** VECTOR_DISTANCE 是此函数的同义词。**
12592
126- Query Plan
127- OPERATOR(NAME)
128- PROJECT
129- └─VECTOR_INDEX_SCAN(V_I ON TEST)
130- ```
131-
132- ### 题目五:向量索引题目(二)
133-
134- * 需要在没有索引的场景下,支持向量检索功能(即精确检索)。
135- * 需要支持完整的向量检索功能(包括向量索引构建,向量索引查询)。
136-
137- 向量检索示例:
13893``` sql
139- SELECT * FROM TAB_VEC ORDER BY L2_DISTANCE(B, ' [1,2,3] ' ) LIMIT 1 ;
94+ SELECT DISTANCE(STRING_TO_VECTOR( " [1.01231, 2.0123123, 3.0123123, 4.01231231] " ), STRING_TO_VECTOR( " [1, 2, 3, 4] " ), " COSINE " ) ;
14095```
14196
142- ### 题目六:ann-benchmarks
143-
144- [ ann-benchmarks] ( https://github.com/erikbern/ann-benchmarks ) 是一个用于评估近似最近邻(Approximate Nearest Neighbor, ANN)搜索算法性能的工具和框架。我们使用 ann-benchmarks 来测试 MiniOB 向量搜索相关功能。
145- 本地运行支持 MiniOB 的 ann-benchmarks 测试的步骤如下:
97+ ---
14698
147- 赛题测试程序中运行的 ann-benchmarks 只针对 ` fashion-mnist-784-euclidean ` 数据集进行测试,` --runs ` 参数为1,测试使用的 python 脚本与 [ ann-benchmarks] ( https://github.com/oceanbase/ann-benchmarks/tree/miniob ) 完全相同,指定向量索引参数 ` probes = 5, lists = 245 ` 。
148- 测试程序不对性能做过多的限制,满足如下要求即为通过:
99+ ** STRING_TO_VECTOR(string)**
149100
150- 1 . 要求在 10 分钟内完成 ann-benchmarks 的整个运行(即包括:插入数据,创建索引,ANN 查询,不包括下载数据集的时间)。
151- 2 . 要求 ANN 查询的每秒查询数(QPS)达到 100 qps
152- 3 . 要求 ANN 查询的召回率(recall)达到 0.90
153- 4 . 考虑向量索引的内存占用,要求 ann-benchmarks 运行过程中 miniob 的最大内存占用不超过 1 GB。
101+ 将向量的字符串表示转换为二进制形式。字符串的预期格式是一个或多个逗号分隔的浮点数值列表,用方括号([ ] )包围。值可以用十进制或科学记数法表示。由于该参数是字符串,因此必须加引号。
154102
155- 注意: 需要对 MiniOB 代码进行修改,以支持运行 ann-benchmarks 测试(如MiniOB 现有的 MySQL 通讯协议需要兼容 ann-benchmarks 所使用的 pymysql)。
103+ ** TO_VECTOR() 是此函数的同义词。 **
156104
157- #### 在 MiniOB 上运行 ann-benchmark
105+ VECTOR_TO_STRING() 是此函数的逆操作:
158106
159- * 下载 ann-benchmarks 代码
160- ```
161- git clone https://github.com/oceanbase/ann-benchmarks.git -b miniob
162- ```
163- * 安装所需 python 依赖
164- ```
165- cd ann-benchmarks/
166- pip install -r requirements.txt
167- ```
168- * 以 mysql 通讯协议且监听 unix socket 的方式启动 miniob.
169- ``` bash
170- # 示例命令
171- /root/miniob/build_release/bin/observer -s /tmp/miniob.sock -P mysql
172- ```
173- * 运行 ann-benchmark.
174- 注意:需要将 ` algorithms/miniob/config.yml ` 中的 ` arg_groups: [{unix_socket: "/tmp/miniob.sock"}] ` 修改为 miniob 实际使用的 unix socket 文件地址
175- ``` bash
176- # 示例命令
177- python3 run.py --dataset fashion-mnist-784-euclidean --docker-tag ann-benchmarks-miniob --local --timeout 100 --runs 1
178- ```
179- * 生成运行结果.
180- ``` bash
181- # 示例命令
182- python3 plot.py --dataset fashion-mnist-784-euclidean
183- # 示例输出如下,其中每行结果倒数第一个值为该算法对应的QPS,每行结果倒数第二个值为该算法对应的召回率。
184- writing output to results/fashion-mnist-784-euclidean.png
185- Computing knn metrics
186- 0: MiniOBVector () 0.968 167.476
187- Computing knn metrics
188- 1: BruteForceBLAS () 1.000 355.359
107+ ``` sql
108+ SELECT VECTOR_TO_STRING(STRING_TO_VECTOR(" [1.05, -17.8, 32]" ));
189109```
190110
191- ### MiniOB 向量数据库语法示例
111+ 此类值中的所有空白字符(数字后、方括号前或后,或两者的任意组合)在使用时都会被修剪。
192112
193- ``` sql
194- -- 建表语句
195- CREATE TABLE TEST (ID INT , C1 VECTOR(3 ), C2 VECTOR(3 ), C3 VECTOR(4 ));
113+ ---
196114
197- -- 插入语句
198- INSERT INTO TEST VALUES (1 , ' [1,1,1]' , ' [1,2,3]' , ' [1,2,3,4]' );
115+ ** VECTOR_TO_STRING(vector)**
199116
200- -- 查询语句
201- SELECT C1, C2, L2_DISTANCE(C1, C2), L2_DISTANCE(' [1,1,1]' , ' [1,2,3]' ), COSINE_DISTANCE(' [1,1,1]' , C2) FROM TEST;
202- SELECT C1, C2, C1 + ' [1.5,2.3,3.3]' , ' [3.3,55.55,66.66]' - C2, C2 * C1 FROM TEST;
117+ 给定一个 VECTOR 列值的二进制表示,此函数返回其字符串表示,该格式与 STRING_TO_VECTOR() 函数的参数格式相同。
203118
204- -- 创建索引
205- CREATE VECTOR INDEX V_I ON TAB_VEC(B) WITH(TYPE= IVFFLAT, DISTANCE= L2_DISTANCE, LISTS= 3 , PROBES= 3 );
119+ ** FROM_VECTOR() 被接受为此函数的同义词。**
206120
207- -- ANN 查询
208- SELECT * FROM TAB_VEC ORDER BY L2_DISTANCE(B, ' [1,2,3] ' ) LIMIT 1 ;
209- ```
121+ 无法解析为向量值的参数会引发错误。
122+
123+ 此函数的输出最大大小为 262128(16 \* 16383)字节。
210124
211125## 参考资料
126+
212127[ 向量数据库] ( https://en.wikipedia.org/wiki/Vector_database )
213128
214- [ pgvector] ( https://github.com/pgvector/pgvector )
129+ [ MySQL 向量类型介绍] ( https://dev.mysql.com/doc/refman/9.4/en/vector.html )
130+
131+ [ MySQL 向量函数介绍] ( https://dev.mysql.com/doc/refman/9.4/en/vector-functions.html )
215132
216133[ ivfflat 原理介绍] ( https://www.timescale.com/blog/nearest-neighbor-indexes-what-are-ivfflat-indexes-in-pgvector-and-how-do-they-work/ )
217134
0 commit comments