結構化數據與非結構化數據的混合查詢

Milvus 實戰 | 結構化數據與非結構化數據的混合查詢

通過深度學習的神經網絡模型,可以將圖片、視頻、語音、還有文本等非結構化數據轉換為特徵向量。除了結構化的向量,這些數據往往也需添加其他屬性。如人臉圖片,可以添加性別、是否戴眼鏡、圖片抓取時間等標籤;文本可以添加語言類型、語料分類、文本創建時間等標籤。由於這些特性,往往需要實現結構化數據和非結構化數據的混合查詢。

Milvus 是一款開源的、針對海量特徵向量的相似性搜索引擎,在此之前,Milvus 曾給出過一個結合 PostgreSQL 實現混合查詢的方案。該方案是先將特徵向量在 Milvus 內做相似度檢索,然後 Milvus 返回的結果集再通過 PostgreSQL 過濾結構化屬性,得到最終結果。由於是先做向量的相似度檢索,然後再從相似度搜索得出的結果中篩選滿足屬性條件的結果,可能會造成結果集有損失,因為滿足屬性的一些結果集可能在向量相似度檢索時已經被過濾掉了,而相似度靠前的向量集卻不滿足附加的屬性條件。

得益於 Milvus 0.6.0 新增的分區功能,上述問題在 Milvus 0.6.0 有了新的解決方案,同時 Milvus 的應用場景也更加廣闊( Milvus 分區功能詳解: Milvus 0.6.0新增功能:分區表)。那麼,Milvus 分區功能是如何來解決混合查詢的問題呢?


解決方案

將非結構化數據對應的多個屬性標籤組合為一個字符串作為 Milvus 一個分區的標籤,特徵向量將按分區存儲,檢索時根據屬性在對應的分區檢索,就能快速得到非結構化和結構化數據混合過濾的結果。具體流程如下圖所示(橙色線條表示存儲過程,藍色線條表示檢索過程):

Milvus 實戰 | 結構化數據與非結構化數據的混合查詢

本文將通過一個用例來詳細說明如何使用 Milvus 分區功能實現結構化數據與非結構化數據的混合查詢。


場景說明

底庫中有數億張圖片,通過深度學習模型將其轉化為特徵向量,每一張圖片有其對應的屬性(圖片獲取時間,性別,是否戴眼鏡)。知道待查詢圖片的部分屬性,需要在底庫中快速找出滿足該屬性並給定圖片相似的前 N 張圖片。

利用 Milvus 分區功能,將具有相同屬性的向量歸為同一個分區,並將這些屬性標籤用一個字符串(例如:'2019-11-22/female/False’)代替作為該分區的標籤(Partition_tag)。在進行檢索時,將過濾條件按相應的規則轉化為字符串在對應的一個或多個分區裡查找相似向量。在選擇分區時,支持用正則表達式匹配相對應的分區。


數據準備

本次實現的 Milvus 混合查詢,其特徵向量提取自ANN_SIFT1B中 Base Set 文件中的一億數據( 128 維),特徵向量檢索時從 Query set 中提取,假定 ANN_SIFT1B 數據集為人臉特徵向量。並隨機的生成性別、圖片抓取時間、是否戴眼鏡的標籤,將這三個屬性標籤合為一個字符串作為分區的 partition_tag。本文所述用例中,一共隨機生成了十個分區標籤。

<code># 隨機生成性別、是否戴眼鏡、圖片抓取時間等標籤
sex = random.choice(['female','male'])
get_time = fake.date_between(start_date="-30d",
end_date="today")
is_glasses = random.choice(['True','False'])
#將三個屬性組合為一個字符串作為分區標籤
p_tag = str(get_time)+"/"+ sex +"/"+ str(is_glasses)
/<code>

功能實現

1. 特徵向量存儲

數據準備完成之後需要在 Milvus 中創建一張表,同時按照上述產生的分區標籤在該表上創建十個分區,每個分區有其對應的分區名和分區標籤(各分區名和分區標籤不能重複)。然後將向量導入對應的分區裡。同一個分區裡的特徵向量其屬性標籤相同。數據導入 Milvus 後,其返回的 ids 是對各向量的唯一表示(該 ids 可自定義):

<code>#創建一個分區
milvus.create_partition(MILVUS_TABLE, partition_name
=partition_name, partition_tag=partition_tag)
#將向量導入指定的分區中
status, ids = milvus.add_vectors(table_name=
MILVUS_TABLE, records=vectors, ids=vectors_ids,
partition_tag=partition_tag)
/<code>

2. 特徵向量檢索

向 Milvus 中傳入需要搜索的向量。設定 TOP_K = 10 ,TOP_K 表示搜索與查詢向量相似度最高的前 10 個結果。在檢索時,按照給定的屬性條件,Milvus 會在指定的一個或多個分區進行查找(指定 partition_tag 時支持正則表達式)。

由於分區標籤是按照 'time/sex/glasses’ 方式設定的,在查詢前可按如下方式指定要查詢的分區。

<code>#已知所有屬性(時間、是否戴眼鏡、性別),明確指定一個分區
$ partition_tag1 ='2019-11-22/female/False'
#指定部分屬性對應的分區(性別)
$ partition_tag2 ='.*/male/.*'
#指定部分屬性對應的分區(時間、性別)
$ partition_tag3 ='2019-12-21/male/.*'
#指定分區在某個月且性別為男:
$ partition_tag4 ='2019-12-.*/male/.*'
/<code>

在指定分區裡採用歐氏距離計算兩個向量的相似度,進行查詢時 Milvus 查詢結果將返回向量對應的 ids 。

<code>#指定一個分區查詢
status, results = milvus.search_vectors(MILVUS_TABLE
, query_records=vector, top_k=10, nprobe=64,
partition_tags=[partition_tag1])

#在多個分區查詢
status, results = milvus.search_vectors(MILVUS_TABLE
, query_records=vector, top_k=10, nprobe=64,
partition_tags=[partition_tag1, partition_tag2,
partition_tag3])
/<code>

在對一億數據進行混合查詢時,Milvus 在秒內即可得到檢索結果。

上述解決方案的實現案例可以參考:

https://github.com/milvus-io/bootcamp/tree/0.6.0/solutions/partition_hybrid_search


相比於結合 PostgreSQL 實現的混合查詢方案,基於分區功能實現的混合查詢更貼近實際需求,即先根據已經確定的屬性條件過濾,然後在過濾後的向量集中做向量的相似度檢索,最後得到的結果集將是符合預期的。

屬性標籤類別較少時,基於 Milvus 的分區功能實現特徵向量與結構化數據的混合查詢是一個不錯的選擇。其良好的性能、簡易的操作和維護等都將會帶給你極好的體驗。


分享到:


相關文章: