编者按:本文具体介绍 Milvus 2.0 如何通过查问表达式、查问语法生成、查问操作执行来实现属性过滤。
纲要分享:
- 查问表达式的文法规定
- 查问语法的生成
- 语法树的解释和执行
查问表达式的文法规定
Milvus 反对的查问表达式
如下图所示,Milvus 使用 EBNF 语法,此处用等式和语法图体现了 Milvus 所反对的查问表达式的整体规定。
表达式 LogicalExpr 有四种组合来进行示意,比方通过二元的逻辑运算符,在逻辑表达式前加一元的逻辑运算符,或者用一些比较简单的 Single Expr 等。
因为 EBNF 自身就是一个递归的构造,LogicalExpr 既能够是这四条组合起来的整体,也能够是其中独自的某个节点,并且能够持续嵌套上来。也就是说,Milvus 反对的表达式规定是能够有限的递归嵌套的。如果有很多属性须要过滤,就能够通过不同的组合和嵌套,进而示意出须要的过滤条件。
底层操作服务及具体表达式
上图是前文提到的几种表达式。首先能够在表达式后面加单元的逻辑运算符,目前 Milvus 反对的是增加“not”,示意在表达式做出计算当前取它的非。其次二元逻辑运算符就是与和或的两种不同体现办法。而后 Single Expr 目前实现的是 Term 和 Compare。
另外如根本的加减乘除等其余运算也是反对的。下图是操作服务的优先级,由 1 – 9 递加。
查问语法的生成
开源工具 ANTLR 介绍
ANTLR 能够了解为解析器或者生成器,它可能对结构化文本或者二进制文件做读解决,包含执行和翻译的过程。具体来说,ANTLR 能够依据定义的文法规定进行解析,也能够生成解析器来构建解析数;同时它外部也提供了 WALKER 的一些 API,能够帮忙遍历解析数。例如图中的表达式“SP =100;”,ANTLR 自带的语言识别器 LEXER 会生成四个 token,再各自进行解析生成 Parse-Tree。
其中比拟重要的性能是给生成的 Parse-Tree 提供了 WALKER 的机制,通过 WALKER 对这解析数进行遍历。比方每个节点是否合乎文法规定、单词有无波及敏感词汇,都能够失去合法性检查。从左边列出的 Parse-Tree 遍历的 API 能够看出,ANTLR 从 根节点始终到最末端的子节点,是依照一种深度遍历的程序来进行遍历的,由此也不须要人为辨别多叉树的前序、中序、后序,间接看 API 即可。
PlanAST generation
Milvus 的运作办法和 ANTLR 较为类似,但后者比拟原始化,须要依据需要从新定义绝对简单的文法规定。Milvus 应用的 expression 这种同样常见的语法规定,并且依附 GitHub 上 ant-expr 这一开源工具来实现生成语法的查问与解析。
首先用户会传过来一个表达式 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
Milvus 里定义了一种 proto 构造来示意前文提及的 plan AST 形象语法树。如图中右上角定义的一个 protobuf 构造的 message,查问形式就是通过 expression 失去,且 Expr 有六种抉择,其中 BinaryExpr 和 UnaryExpr 存在进一步递归的 LogicalExpr。
上图为表达式的一个 UML 的图,是 C++ 中依据 proto 构造去实现类的继承关系结构图,蕴含各个 Expr 的基类与派生类。每个类上面都实现了一个 accept 的办法,承受的是 visitor 的参数。这就是典型的访问者设计模式(Visitor design pattern),以此对后面生成的查问语法树进行遍历的执行。这一模式的劣势在于用户不须要对 Expr 原始进行操作,能够间接通过拜访的办法对其中一些具体的类与元素进行批改。
PlanAST execution
上图总结了查问语法树执行的工作流程。首先从 C++ 接管到一个 proto 类型的 PlanNode,通过 C++ 外部的 ProtoParse 失去 segcore 类型的 PlanNode。在此基础上,通过 accept 的办法承受一系列的访问者类,再对 PlanNode 外部的构造进行批改、执行。最初对每个具体的 ExecPlanNode 进行递归遍历,失去过滤的后果 Filtered_result,以下图的 Bitmap 作为具体模式。
完整版视频解说请戳:https://www.bilibili.com/vide…
如果你在应用的过程中,对 Milvus 有任何改良或倡议,欢送在 GitHub 或者各种官网渠道和咱们保持联系~