背景
AI時代離不開向量數據庫,向量數據庫簡單說就是在數據庫中用多維向量存儲某類事物的特征,通過公式計算各個向量在空間坐標系中的位置關系,以此來判斷事物之間的相似性。相關基礎概念如下:
● Embedding
● 距離/相似性度量
○ Cosine distance
○ Inner_product
○ L1 distance
○ L2_distance
○ Jaccard Distance
○ Hamming distance
● 相似性搜索算法
○ 典型算法
■ 倒排 + 數據壓縮
■ 導航圖索引 +分布式
○ HNSW
○ IVF
○ DisKANN
● 索引壓縮算法
○ SQ(Scalar Quantization)
○ PQ(Product Quantization)
OceanBase 在向量檢索方面的優勢
OceanBase 在向量檢索方面的優勢,主要有以下幾點:
1.OceanBase 在通過向量數據類型(vector)實現向量存儲,通過多種類型的向量索引支持了高效的向量檢索。在向量查詢時,不僅支持按 TOPN 排序的相似度計算,還能夠按照標量進行點查。
2.在應用開發方面,為用戶提供了 python API和類似于 MilvusSDK 的開發工具包,而且還可以直接復用 MySQL 生態的客戶端,對開發友好。
3.在運維方面,不需要引入新的工具和組件,可以完全復用現有的運維平臺和工具,如 OBD、OCPobdiag 等。不用學習新的工具,直接復用已有的運維經驗即可。
4.在數據庫的其他能力方面,相比于專用的向量數據庫 Pinecone/Milvus,以及正在逐步補齊向量檢索能力的老牌數據庫廠商 Elasticsearch/Redis 等,OceanBase 是一個支持金融級高可用的分布式向量數據庫,除了基礎的向量檢索能力,還支持金融級高可用和容災、彈性擴縮容、分布式事務,并有著極低的存儲成本和優秀的查詢分析性能。
5.在性能上,ANN Benchmarks GIST 960 排名第一。下圖的 Vsag 即為 OceanBase 向量化引擎插件,和目前最好的 glass 相比,在 96.7% 召回率的情況下 QPS 能夠提升 90% 左右,做到了SOTA(State ofthe Art)。并且還會持續依靠螞蟻集團大量的向量化場景和專業的算法團隊,不斷進行性能優
現在 OceanBase 作為向量數據庫,在更低成本的基礎上,還可以獲得比某專業向量數據庫 Milvus 更好的性能。
OceanBase 可以簡單理解成是一個復用了金融級分布式數據庫內核能力的超級向量數據庫。同時,還擁有簡單易用的 API接口和豐富的生態工具體系,大大降低了適配和運維的難度。
向量概念簡述
向量數據庫簡單說就是:在數據庫中用多維向量存儲某類事物的特征,通過公式計算各個向量在空間中的位置關系,判斷事物之間的相似性。向量是一個浮點數組,這個數組中的每個元素代表向量的某個維度,每個元素都是一個浮點數。向量數組的大小(元素個數),代表整個向量空間的維度。
● 一個對象可以抽取多種正交的特征,比如(體型、毛長等),每個特征代表向量的一個維度。
● 每個維度的精度越細,區分度越高。
● 維度數越多,區分度越高,查詢的相對越精確。
● 比如結構化數據都在一維空間做計算,維度越高,計算/查詢空間越大,計算量越大。
Embedding
通過深度學習神經網絡提取非結構化數據里的內容和語義,把圖片、視頻等變成特征向量,這個過程叫Embedding.
Embedding 技術將原始數據從高維度(稀疏)空間映射到低維度(稠密)空間,將具有豐富特征的多態數據,轉換為多維數組(向量),向量可以通過向量距離來做計算,判斷原始多模態數據的相似性。
距離/相似性度量
常見的相似度測量方式會涉及到一些中學數學的基礎知識,例如:余弦相似度、內積(點積)、歐幾里得距離(歐式距離)、曼哈頓距離。
Cosine distance
余弦相似度(cosine similarity):計算兩個向量間夾角的余弦值。當兩個向量方向相同時余弦相似度的值為1;當兩個向量夾角為 90 度時余弦相似度的值為 0,當兩個向量方向完全相反時余弦相似度的值為-1。
余弦相似度的計算方式為:
由于余弦相似度度量越接近于1表示越相似,因此有時也使用余弦距離(或余弦不相似度)作為向量間距離的一種衡量方式,余弦距離可以通過1減去余弦相似度來計算:
余弦距離的取值范圍是[0,2],其中0表示完全相同的方向(無距離),而2表示完全相反的方向。
Inner_product(lP/內積)
內積又稱為點積或數量積,是線性代數中的一種重要運算,它定義了兩個向量之間的一種乘積。在幾何意義上,內積表征了兩個向量的方向關系和大小關系。
除了和余弦相似度一樣都會受到位置(或者叫夾角)關系的影響,向量的內積還會受到向量長度的影響。如果把向量進行歸一化(即將每個向量除以其自身的長度,得到一個長度為1的單位向量),內積就將只反應方向,不涉及大小,此時內積就會變成上面的余弦相似度。
L1_distance
曼哈頓距離(Manhattan Distance)用于計算兩個點在標準的坐標系中的絕對軸距總和。計算公式為:
一圖勝千言,下圖中的兩個線條之和就表示兩個向量在多維坐標系中的曼哈頓距離,也被稱為城市街區距離。
L2 distance
歐幾里得距離(Euclidean Distance)反映的是被比較的向量坐標之間的距離,也就是兩個向量之間的直線距離。這個應該好理解,上圖中的紅色線條就表示兩個向量在多維坐標系中的歐幾里得距離。計算公式如下:
總結
Cosine(余弦距離):通過計算兩個向量之間的夾角余弦值來衡量它們的相似程度,取值范圍為
[-1,1],值越接近 1表示越相似。
● IP(lnner Product,內積):兩個元素的對應元素相乘并求和的結果計算相似度,內積值越大相似度越高.通常在自然語言處理(NLP)領域中使用。
● L1(曼哈頓距離):曼哈頓距離是兩個向量各個維度差值的絕對值之和。與歐氏距離不同,曼哈頓距離更關注各個維度的差異,而不是方向。
● L2(歐式距離):歐氏距離是兩個向量之間的直線距離,可以表示為它們各個維度差值的平方和的平方根。歐氏距離越小,表示兩個向量越相似,通常在自然語言處理(NLP)領域中使用。
針對二值向量的常用相似性度量方法
二值向量即向量中的每個元素要么是 0,要么是 1。二值向量的實現方式相比浮點向量也會有所不同,為了節省空間,數據庫內部往往會用 byte 而非 float 來實現二值向量。
Jaccard Distance
杰卡德距離,計算的是兩個集合并集中,不屬于交集的元素的比例,用于反映差異度。
Hamming distance
漢明距離(Hamming distance)是數據傳輸差錯控制編碼中的概念,表示了兩個字對應位不同的數量定義為將兩個字進行異或運算后1的位數。
相似性搜索算法
向量數據庫相似性搜索,是通過計算輸入向量與目標向量的相似度,快速找出與輸入向量最相似數據的搜索技術。這其中以 Approximate Nearest Neighbor(近似最近鄰,ANN)搜索和以 K-Means 為代表的聚類搜索最具代表性。
典型算法
倒排+數據壓縮
通過聚類算法(常用 KMeans 算法)將數據分為若干聚簇,按照聚簇中心建立倒排索引。每次搜索時先計算與聚簇中心的相似度,選擇相似性最高聚簇進一步搜索。
導航圖索引+分布式
將向量作為點,向量相似度作為邊,建立近似近鄰圖,在圖上進行貪心搜索逼近近鄰區域。圖索引在內存中最高效,因而對內存占用很大,經常基于分區以及分布式的方式,來解決大數據量的問題.缺點是成本高,有點是能夠實現高召回率以及低延遲(思路類似六度分隔理論:最多通過六個人,你就能夠認識任何一個陌生人)。
HNSW
Hierarchical Navigable Small World(分層導航小世界)小世界圖是介于規則圖和隨機圖之間的一種圖結構,其特點是每個節點僅與很小有限的節點有聯系,并且這些節點有一定的集中性。小世界圖中大部分節點彼此并不聯系,但大部分節點經過幾步即可到達。HNSW 是基于“鄰居的鄰居可能是鄰居”的核心思想,社交網絡便是典型的小世界圖結構。先看一個大家都更熟悉的數據結構 – 跳表 SkipList。
跳表是典型的用空間換取時間,索引分了好幾層,最底層(圖中 Level1)存儲了所有的數據,而上面幾層,則存儲了指向某幾個數據的索引,且越往上索引數量越少。跳表的作用就是:先快速的接近要查找的點的附近,然后再精確的搜索,這樣就避免了路上做很多無用功耽誤時間。個人理解,HNSW 就是將跳表運用在了圖結構中。
跳表的每一層,都是一個小世界網絡。其中最底層(Layer=0)是一個完整的 NSW(導航小世界網絡),其它層存儲的則是指向圖節點的指針索引。使用類似于跳表的原因也很簡單,為了少做無用功耽誤時間。
上層小世界圖可以看成是下層的縮放,多層圖的方式目的是為了減少搜索時距離計算和比較的次數。檢索時,從最高一層(即最稀疏的一層)開始,每一層得到的檢索結果再作為下一層的輸入,如此,不斷迭代到最后一層。最后得到查詢點的 K個近鄰。HNSW 是目前最流行的向量檢索算法,性能和召回率都比較不錯,但是對內存有強依賴。
IVF
IVF(lnverted File Index)索引通過聚類算法將向量空間劃分為多個子空間,并為每個子空間建立索引。在搜索過程中,IF 索引首先根據查詢向量找到其所屬的子空間(下圖中紅框表示子空間),然后在對應子空間中進行精確搜索。
優點是搜索速度快,缺點是召回率不優。因為聚類中心是預建的,增量數據的導入不會影響聚類中心的分布,數據更新后,依賴聚類的重建。
DiskANN
期望解決的問題:
如何能夠減少訪問磁盤的頻率?先訪問內存,只有真正需要原始向量時再去訪問磁盤如何組織數據結構?保證一次讀盤操作便可以取出相關的節點邊圖信息。DiskAnn 的思路:
DiskANN 算法結合了兩類算法 – 聚類壓縮算法和圖結構算法。
算法如下:
通過壓縮原始數據,僅將壓縮后的碼表信息和中心點映射信息放到內存中。而原始數據和C構建好的圖結構數據存放到磁盤中,只需在查詢匹配到特定節點時到磁盤中讀取。修改向量數據和圖結構的排列方式,將數據點與其鄰居節點并排存放,這種方式使得一次磁盤操作即可完成節點的向量數據、鄰接節點等信息的讀取。
DiskANN 算法的優點和缺點多很明顯
優點:大幅提升向量召回的讀取效率,降低圖算法的內存,提升召回率。
缺點:索引的構建開銷較大,更適合靜態數據集(或者不經常變的數據集合)
索引壓縮算法
Quantized 是將現有的索引(如INF、HNSW)與量化等壓縮方法結合起來,以減少內存占用并加快搜索速度。
向量的壓縮,一般是基于降低向量維度,降低向量元素的精度的思路,分為兩類:標量量化(ScalarQuantization,SQ)和乘積量化(Product Quantization,PQ)。例如 IVF-PQ、HNSW-PQ。
SQ(Scalar Quantization)
思想是:把一個高精度的浮點向量,主動丟失部分精度,變為一個低精度向量,減少計算和存儲開銷。
例如把向量中的元素 0.1192 和 0.1365 統一用 0.1 來替換。
大致原理:
1.分割范圍:首先確定向量中數值的大致范圍,然后將這個范圍分成若干個等間隔的小段或桶(這稱為量化級別或量化步長)。
2.映射值:將原始向量中的每個元素映射到最近的一個桶中。具體來說,就是將每個浮點數值舍入到其最近的量化級別的中心值,這個過程通常稱為量化。
編碼:被映射到各個桶中的值可以用更緊湊的形式表示,例如,用桶的索引(一個整數)來代替原3.始的浮點數,從而實現壓縮。
PQ(Product Quantization)
思想是:把高維向量空間降維。因為低維向量的存儲和計算開銷都遠遠低于高維。
大致原理:
1.分組(Dimension Splitting):首先,將原始的高維向量空間分成多個子空間,通常是將 d維向量分為 m 個大小相等的子集,每個子集包含 d/m 維。這樣做的目的是將一個復雜的高維問題分解為多個較低維度的問題,便于處理。
2.量化編碼(Codebook Generation):對于每個子空間,構建一個碼本(codebook)。碼本是一個由k個向量組成的集合,這些向量是該子空間內所有訓練向量的聚類中心。這一步通常通過聚類算法完成,每個子空間的向量被分配到離它最近的聚類中心。
3.編碼(Encoding):對于每一個高維向量,將其在每個子空間上的投影與相應的碼本進行比較,找出距離最近的碼本向量,并記錄下這個向量在碼本中的索引。這樣,原始的高維向量就被轉換為了一個長度為 m 且每個元素范圍在 0到k-1之間的整數序列,即可得到一個緊湊的量化表示。
召回率
最后再來一個大家都可以輕松理解的概念 – 召回率。召回率是說:檢索出來的結果集中,接近目標向量的結果比例。召回率=真正例/(真正例 + 假反例)。暴力搜索的召回率可以100%,但是基本不可接受。基于向量索引搜索的召回率一般低于 100%,是一個非精確的搜索。召回率和向量索引的組織算法,壓縮(壓縮本質是通過降低精度,減少計算開銷)算法等相關。
實驗:通過 SQL 快速使用 OceanBase 向量檢索
OceanBase 向量檢索能力基于多模一體化能力上構建,在融合查詢、擴展性、高性能、高可用、低成本、多租戶、數據安全等方面均有優異的表現。有關向量檢索的詳細介紹,參考 向量檢索。
注意:本篇教程以 MySQL 模式為例進行說明。
連接數據庫
obclient -h127.0.0.1 -P2881 -uroot@mysql_tenant -A -Dtest
創建向量表
創建表時,可以使用 VECTOR(dim) 數據類型聲明指定列為向量列及其維度。向量索引需要創建在向量列上,且至少需要提供 type 和 distance 兩個參數。
示例中創建向量列 embedding,向量數據維度為 3,并在 embedding 列上創建 HNSW 索引,指定距離算法為 L2。
CREATE TABLE t1( id INT PRIMARY KEY, doc VARCHAR(200), embedding VECTOR(3), VECTOR INDEX idx1(embedding) WITH (distance=L2, type=hnsw) );
在數據量較大的情況下建議先導入完數據再創建向量索引,后建索引詳情請參見 向量索引。
寫入向量數據
為了模擬在向量檢索的場景,需要先構造一些向量數據,每行數據都包括對數據的描述和對應的向量。示例中假設 ‘蘋果’ 對應的向量為 ‘[1.2,0.7,1.1]’, ‘胡蘿卜’ 對應的向量為 ‘[5.3,4.8,5.4]’ 等。
INSERT INTO t1 VALUES (1, ‘蘋果’, ‘[1.2,0.7,1.1]’), (2, ‘香蕉’, ‘[0.6,1.2,0.8]’), (3, ‘橙子’,‘[1.1,1.1,0.9]’), (4, ‘胡蘿卜’, ‘[5.3,4.8,5.4]’), (5, ‘菠菜’, ‘[4.9,5.3,4.8]’), (6, ‘西紅柿’,‘[5.2,4.9,5.1]’);
為了方便展示,本例簡化了向量的維度,僅使用了 3 維向量,且向量是人工生成的。在實際應用中,需要使用嵌入模型對真實的文本進行生成,維度會達到數百或上千維。
可以通過查詢表中的數據查看是否寫入成功。
SELECT * FROM t1;
返回結果如下:
obclient [test]> SELECT * FROM t1;
±—±----------±--------------+
| id | doc | embedding |
±—±----------±--------------+
| 1 | 蘋果 | [1.2,0.7,1.1] |
| 2 | 香蕉 | [0.6,1.2,0.8] |
| 3 | 橙子 | [1.1,1.1,0.9] |
| 4 | 胡蘿卜 | [5.3,4.8,5.4] |
| 5 | 菠菜 | [4.9,5.3,4.8] |
| 6 | 西紅柿 | [5.2,4.9,5.1] |
±—±----------±--------------+
6 rows in set (0.008 sec)
執行向量檢索
進行向量檢索需要提供向量作為搜索條件。假設我們需要找到所有 ‘水果’,其對應的向量為 [0.9, 1.0, 0.9],則對應 SQL 為:
SELECT id, doc FROM t1 ORDER BY l2_distance(embedding, ‘[0.9, 1.0, 0.9]’) APPROXIMATE LIMIT 3;
返回結果如下:
obclient [test]> SELECT id, doc FROM t1 ORDER BY l2_distance(embedding, ‘[0.9, 1.0, 0.9]’) APPROXIMATE LIMIT 3;
±—±-------+
| id | doc |
±—±-------+
| 3 | 橙子 |
| 2 | 香蕉 |
| 1 | 蘋果 |
±—±-------+
3 rows in set (0.094 sec)