iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0

把條件「長成」一棵樹

Day 2 我們講解了「為什麼要有 query engine」
今天開始動手拆解它的骨幹:AST(抽象語法樹)與 Matcher tree
重點是三個最小元件:Eq(等於)、Field(取值)、And(聚合)
把這三個拼起來,就能描述 8 成的日常條件

Eq/Field/And 的語意與實作對照

  1. 我們如何解釋一個條件的運作?試想一個條件表達式如下:
condition = {
  "name": 'John',
  "age": 30
}

背後想要的比對邏輯是:

a. 對資料欄位 name 取值,要等於 "John";
b. 對資料欄位 age 取值,要等於 30;
c. 上述兩者都成立,才算匹配

我們將匹配的概念給展開成樹狀邏輯圖:

AND
  ├─ Field: "name"
  │  └─ Eq: "John"
  └─ Field: "age"
     └─ Eq: 30

這個結構有幾個角色:

  • 取值比對器(Field Matcher):從 record 裡取出欄位值,交給下一層處理。
  • 數值比對器(Eq Matcher):比對值是否相等。
  • 條件聚合器(And Matcher):聚合子 matcher 的結果。

這就是 matcher tree 的雛形。

  1. Field 與 Eq 的職責邊界
  • Field:只負責「取值」與「轉交」,它不關心比較規則
  • Eq(與其他比較子):只負責「比較」,它不關心值怎麼取來

這個拆分讓我們能針對不同型別(如 String/Number)或不同來源(Hash/自訂物件)各自最佳化,同時保持語意單純

  1. 可執行範例(Ruby 2.6+)
require 'mongory'
Mongory.enable_symbol_snippets!
Mongory.register(Array)

records = [
  { 'name' => 'John', 'age' => 30 },
  { 'name' => 'Mary', 'age' => 18 },
  { 'name' => 'John', 'age' => 25 }
]

q = records.mongory.where(:name => 'John', :age => 30)
q.each { |r| p r }
  1. explain:把 AST 印出來
q.explain

輸出:

And: {"name"=>"John", "age"=>30}
├─ Field: "name" to match: "John"
│  └─ Eq: "John"
└─ Field: "age" to match: 30
   └─ Eq: 30

下一步,讓條件更有力量

今天我們 run 過了 AST 的最小積木:EqFieldAnd
明天(Day 4)會把進階運算子接上來:$gt/$gte/$in/$nin/$elemMatch 與針對陣列欄位的特殊處理,讓樹真正「長」起來

專案首頁(Ruby 版)

— 如果你已經有一段條件,歡迎把 q.explain 的輸出貼在 Issue,我可以在後續文章當範例解析


上一篇
Day 2:為什麼需要 Query Engine:S3 JSON → 匹配引擎的誕生
下一篇
Day 4:進階運算子與 Array 包裝
系列文
Mongory:打造跨語言、高效能的萬用查詢引擎10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言