🚀 免費嘗試 Zilliz Cloud,完全托管的 Milvus,體驗速度提升 10 倍!立即嘗試

milvus-logo
LFAI
  • Home
  • Blog
  • 資料庫如何理解並執行您的查詢?

資料庫如何理解並執行您的查詢?

  • Engineering
May 05, 2022
Milvus

Cover image 封面圖片

本文由Angela Ni 轉載。

在 Milvus 中,向量查詢是透過基於布林表達式的標量篩選來擷取向量的過程。透過標量篩選,使用者可以根據資料屬性的特定條件限制查詢結果。例如,如果使用者查詢 1990-2010 年間上映且分數高於 8.5 的電影,則只有屬性(上映年份和分數)符合條件的電影才會出現。

這篇文章的目的在於檢視 Milvus 如何完成從查詢表達式的輸入、查詢計畫的產生到查詢執行的過程。

跳到

查詢表達

在 Milvus 中,屬性篩選的查詢表達採用 EBNF(Extended Backus-Naur form)語法。下圖是 Milvus 的表達規則。

Expression Syntax 表達語法

邏輯表達式可以使用二元邏輯運算符、一元邏輯運算符、邏輯表達式和單一表達式的組合來建立。由於 EBNF 語法本身是遞歸的,一個邏輯表達式可以是一個更大的邏輯表達式的組合結果或一部分。一個邏輯表達式可以包含許多子邏輯表達式。同樣的規則也適用於 Milvus。如果使用者需要用許多條件來篩選結果的屬性,使用者可以透過組合不同的邏輯運算符和表達式來建立自己的篩選條件集。

Boolean expression 布林表達式

上圖顯示 Milvus 中部分布林表達規則。單元邏輯運算符可加入到表達式中。目前 Milvus 只支援單元邏輯運算符號「not」,表示系統需要取其標量值欄位值不滿足計算結果的向量。二元邏輯運算符包括 "and 「和 」or"。單一表達式包括項表達式和比較表達式。

在 Milvus 的查詢過程中,也支援加、減、乘、除等基本算術運算。下圖展示了運算符號的優先順序。運算符號從上至下依序排列。

Precedence 優先順序

在 Milvus 中如何處理關於某些影片的查詢表達式?

假設 Milvus 儲存了大量的影片資料,而使用者想要查詢某些影片。舉例來說,Milvus 儲存的每部電影資料都有以下五個欄位:電影 ID、上映年份、電影類型、配樂和海報。在此範例中,電影 ID 和上映年份的資料類型為 int64,而電影得分則為浮點資料。此外,電影海報以浮點向量的格式儲存,而電影類型則以字串資料的格式儲存。值得注意的是,支援字串資料類型是 Milvus 2.1 的新功能。

舉例來說,如果使用者想要查詢分數高於 8.5 分的電影。例如,如果使用者要查詢得分高於 8.5 分的電影,而且這些電影必須是在 2000 年之前的十年至 2000 年之後的十年間上映,或是其類型必須是喜劇或動作片,則使用者需要輸入以下的謂語表達式:score > 8.5 && (2000 - 10 < release_year < 2000 + 10 || type in [comedy,action])

收到查詢表達式後,系統會依下列優先順序執行:

  1. 查詢分數高於 8.5 的電影。查詢結果稱為「result1」。
  2. 計算 2000 - 10 得到 "result2" (1990)。
  3. 計算 2000 + 10 得到 "result3" (2010)。
  4. 查詢release_year 的值大於 "result2 「且小於 」result3 "的電影。也就是說,系統需要查詢 1990 年至 2010 年間上映的電影。查詢結果稱為「result4」。
  5. 查詢屬於喜劇片或動作片的電影。查詢結果稱為「result5」。
  6. 結合「result4」和「result5」,取得在 1990 年至 2010 年間上映,或屬於喜劇片或動作片類別的電影。結果稱為 "result6"。
  7. 取「結果 1」與「結果 6」的共同部分,得到符合所有條件的最終結果。

Film example 電影範例

計劃 AST 生成

Milvus 利用開放原始碼工具ANTLR(ANother Tool for Language Recognition) 來產生計劃 AST (抽象語法樹)。ANTLR 是一個功能強大的解析器產生器,用於讀取、處理、執行或翻譯結構文字或二進位檔案。更明顯的是,ANTLR 可以根據預先定義的語法或規則,產生建立和行走解析樹的解析器。下圖是輸入表達式為 "SP=100;" 的範例。ANTLR 內建的語言識別功能 LEXER 會為輸入的表達式產生四個標記 - "SP"、"="、"100"、";"。然後工具會進一步解析這四個詞彙,產生相對應的解析樹。

parse tree 解析樹

行走機制是 ANTLR 工具中的重要部分。它的設計目的是在所有的解析樹中行走,以檢查每個節點是否遵守語法規則,或是偵測某些敏感字詞。下圖列出了一些相關的 API。由於 ANTLR 是從根節點開始,一路通過每個子節點到底,所以不需要區分如何走過解析樹的順序。

parse tree walker 解析樹步行器

Milvus 以類似 ANTLR 的方式產生查詢用的 PlanAST。然而,使用 ANTLR 需要重新定義相當複雜的語法規則。因此,Milvus 採用最普遍的規則之一 - 布林表達規則,並依賴 GitHub 上開放的Expr套件來查詢和解析查詢表達式的語法。

在進行屬性篩選的查詢時,Milvus 會在接收到查詢表達式後,使用 Expr 提供的解析方法 ant-parser 來產生原始的未解決計畫樹。我們會得到的原始計畫樹是一棵簡單的二進位樹。之後,Expr 和 Milvus 內建的最佳化器會對計劃樹進行微調。Milvus 中的最佳化器與前述的 walker 機制相當類似。由於 Expr 提供的計劃樹最佳化功能相當複雜,因此在很大程度上減輕了 Milvus 內建最佳化器的負擔。最後,分析器會以遞歸的方式分析已優化的計劃樹,以協議緩衝區(protobuf) 的結構產生計劃 AST。

plan AST workflow 計劃 AST 工作流程

查詢執行

查詢執行的根本是執行前面步驟所產生的 plan AST。

在 Milvus 中,計劃 AST 定義在 proto 結構中。下圖是 protobuf 結構的訊息。有六種表達方式,其中二元表達方式和一元表達方式可以進一步有二元邏輯表達方式和一元邏輯表達方式。

protobuf1 protobuf1

protobuf2 protobuf2

下圖是查詢表達式的 UML 圖像。它展示了每個表達式的基本類別和衍生類別。每個類別都附有接受訪客參數的方法。這是典型的訪問者設計模式。Milvus 使用這個模式來執行計劃 AST,因為它最大的優點是使用者不需要對基本表達式做任何動作,而是可以直接存取模式中的一個方法來修改某些查詢表達式類別和相關元素。

UML UML

當執行一個 Plan AST 時,Milvus 首先會接收到一個 proto-type Plan 節點。然後,透過內部 C++ proto 解析器取得 segcore 類型的計劃節點。取得這兩種類型的計畫節點後,Milvus 會接受一系列的類別存取,然後在計畫節點的內部結構中修改並執行。最後,Milvus 會搜尋所有的執行計畫節點,以獲得篩選後的結果。最後的結果會以 bitmask 的格式輸出。位元掩碼是位元數("0 「和 」1")的陣列。符合篩選條件的資料在位元掩碼中標記為 "1「,而不符合要求的資料在位元掩碼中標記為 」0"。

execute workflow 執行工作流程

關於 Deep Dive 系列

隨著 Milvus 2.0正式宣布全面上市,我們精心策劃了這個 Milvus Deep Dive 系列部落格,提供對 Milvus 架構和原始碼的深入詮釋。本系列部落格涵蓋的主題包括

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

繼續閱讀