Milvus 向量資料庫如何實現屬性過濾

Zilliz發表於2022-04-20
編者按:本文詳細介紹 Milvus 2.0 如何通過查詢表示式、查詢語法生成、查詢操作執行來完成屬性過濾。

大綱分享:

  • 查詢表示式的文法規則
  • 查詢語法的生成
  • 語法樹的解釋和執行

查詢表示式的文法規則

Milvus 支援的查詢表示式

如下圖所示,Milvus 運用 EBNF 語法,此處用等式和語法圖體現了 Milvus 所支援的查詢表示式的整體規則。

image.png

表示式 LogicalExpr 有四種組合來進行表示,比如通過二元的邏輯運算子,在邏輯表示式前加一元的邏輯運算子,或者用一些比較簡單的 Single Expr 等。

由於 EBNF 本身就是一個遞迴的結構,LogicalExpr 既可以是這四條組合起來的整體,也可以是其中單獨的某個節點,並且可以繼續巢狀下去。也就是說,Milvus 支援的表示式規則是可以無限的遞迴巢狀的。如果有很多屬性需要過濾,就可以通過不同的組合和巢狀,進而表示出需要的過濾條件。

底層操作服務及具體表示式

image.png

上圖是前文提到的幾種表示式。首先可以在表示式前面加單元的邏輯運算子,目前 Milvus 支援的是新增 “not”,表示在表示式做出計算以後取它的非。其次二元邏輯運算子就是與和或的兩種不同表現方法。然後 Single Expr 目前實現的是 Term 和 Compare 。

另外如基本的加減乘除等其他運算也是支援的。下圖是操作服務的優先順序,由 1 - 9 遞減。

image.png

查詢語法的生成

開源工具 ANTLR 介紹

image.png

ANTLR 可以理解為解析器或者生成器,它能夠對結構化文字或者二進位制檔案做讀處理,包括執行和翻譯的過程。具體來說,ANTLR 可以根據定義的文法規則進行解析,也可以生成解析器來構建解析數;同時它內部也提供了 WALKER 的一些 API,可以幫助遍歷解析數。例如圖中的表示式 “SP =100;" ,ANTLR 自帶的語言識別器 LEXER 會生成四個 token,再各自進行解析生成 Parse-Tree。

image.png

其中比較重要的功能是給生成的 Parse-Tree 提供了 WALKER 的機制,通過 WALKER 對這解析數進行遍歷。比如每個節點是否符合文法規則、單詞有無涉及敏感詞彙,都可以得到合法性檢查。從右邊列出的 Parse-Tree 遍歷的 API 可以看出,ANTLR 從 根節點一直到最末端的子節點,是按照一種深度遍歷的順序來進行遍歷的,由此也不需要人為區分多叉樹的前序、中序、後序,直接看API即可。

PlanAST generation

Milvus 的運作方法和 ANTLR 較為相似,但後者比較原始化,需要根據需求重新定義相對複雜的文法規則。Milvus 使用的 expression 這種同樣常見的語法規則,並且依靠 GitHub上 ant-expr 這一開源工具來實現生成語法的查詢與解析。

image.png

首先使用者會傳過來一個表示式 expression ,然後通過 ant-parser(這個包含在 ant-expr 裡)的 Parse 方法 ,可以生成一個比較原始的 Unsolved Plantree 。就是前面提及的通過四大分析和簡單的 Parse 後生成一個簡單的二叉樹,這個二叉樹都是 ant-expr 內部的一些結構來表示。接下來對這個 Plantree 做一些 optimizer ,這個 optimizer 是 Milvus 自己實現的。類似於前面講的 WALKER 的機制,遍歷並且給每種節點實現一些優化器。由於 ant-expr 本身生成的優化樹功能已經較好,對後續做執行、解析都比較友好,此處的 optimizer 工作也較為簡單。

最後一個這個虛線節點的 analyzer 過程是將已經優化好的 Plantree 進行遞迴遍歷分析。在二叉樹的遍歷過程中,每個節點對應到定義的 protobuf 的語法樹的結構,進而生成一個 protobuf 結構的一個 plan AST (abstract syntax tree)。

語法樹的解釋和執行

PlanAST & Expr definition

image.png

Milvus 裡定義了一種 proto 結構來表示前文提及的 plan AST 抽象語法樹。如圖中右上角定義的一個 protobuf 結構的 message,查詢方式就是通過 expression 得到,且 Expr 有六種選擇,其中 BinaryExpr 和 UnaryExpr 存在進一步遞迴的 LogicalExpr。

image.png

上圖為表示式的一個 UML 的圖,是 C++ 中根據 proto 結構去實現類的繼承關係結構圖,包含各個 Expr 的基類與派生類。每個類下面都實現了一個 accept 的方法,接受的是 visitor 的引數。這就是典型的訪問者設計模式(Visitor design pattern),以此對前面生成的查詢語法樹進行遍歷的執行。這一模式的優勢在於使用者不需要對 Expr 原始進行操作,可以直接通過訪問的方法對其中一些具體的類與元素進行修改。

PlanAST execution

image.png

上圖總結了查詢語法樹執行的工作流程。首先從 C++ 接收到一個 proto 型別的 PlanNode,經過 C++ 內部的 ProtoParse 得到 segcore 型別的 PlanNode。在此基礎上,通過 accept 的方法接受一系列的訪問者類,再對 PlanNode 內部的結構進行修改、執行。最後對每個具體的ExecPlanNode進行遞迴遍歷,得到過濾的結果 Filtered_result,以下圖的Bitmap作為具體形式。

image.png

完整版視訊講解請戳:https://www.bilibili.com/vide...

如果你在使用的過程中,對 Milvus 有任何改進或建議,歡迎在 GitHub 或者各種官方渠道和我們保持聯絡~

相關文章