iT邦幫忙

2025 iThome 鐵人賽

DAY 7
0
佛心分享-SideProject30

Mongory:打造跨語言、高效能的萬用查詢引擎系列 第 8

Day 7:Explain 與 match trace:可觀測性到位

  • 分享至 

  • xImage
  •  

筆者相信:好的可觀測性,能把「不確定」變成「可驗證」
Explain 讓讀者看見 matcher tree 的結構與責任分工,Trace 讓讀者看見每筆資料在每個節點的命中與否
這一篇把兩者的使用方式、閱讀心法與常見踩雷整理成一份可實戰的手冊

為什麼需要可觀測性

  • 條件愈複雜,心智模型愈容易與實際落差(特別是巢狀 $or$elemMatch$in/$nin 對陣列欄位)

  • Explain 幫讀者驗證「樹長得對不對」

  • Trace 幫讀者驗證「資料在樹上怎麼走」

Explain:閱讀 matcher tree 的心法

require 'mongory'
Mongory.enable_symbol_snippets!
Mongory.register(Array)

records = [
  { 'name' => 'Jack', 'age' => 18, 'tags' => [{ 'name' => 'ruby',  'priority' => 6 }] },
  { 'name' => 'Jill', 'age' => 15, 'tags' => [{ 'name' => 'rails', 'priority' => 3 }] },
  { 'name' => 'Bob',  'age' => 21, 'tags' => [{ 'name' => 'ruby',  'priority' => 8 }] }
]

q = records.mongory
  .where(:age.gte => 18)
  .any_of({ :name.regex => /^J/ }, { :tags.elem_match => { :name => 'ruby' } })

q.explain

輸出:

https://ithelp.ithome.com.tw/upload/images/20250901/20151038fE3o54cQi4.png

閱讀要點:

  • And/Or 節點之下是子 matcher 清單,順序代表執行優先度,足以協助閱讀語意

  • Field 只負責取值與轉交,真正的比較在其子節點(Eq/Gte/Regex/...)

  • 單子條件被解包時,Explain 會直接顯示被解包後的節點(層級更淺)

小提醒:explain 前其實會先觸發一次 match?(@records.first) 以促成建樹或初始化
或是觸發 Array 欄位的 elemMatch 轉包
若資料集合為空,輸出可能較簡略,建議準備一筆樣本資料

Trace:逐步檢查每筆資料的匹配過程

records = [
  { 'name' => 'Ann', 'age' => 19 },
  { 'name' => 'Ben', 'age' => 17 }
]

q = records.mongory.where(:age.gte => 18)
q.trace { gets } # 執行一次,使匹配過程被紀錄,並在每筆紀錄間 gets 暫停,直到你按 enter

輸出:

https://ithelp.ithome.com.tw/upload/images/20250901/20151038omSRPTzJRQ.png

閱讀要點:

  • 每個節點都會標示 Matched/Dismatch 以及目前觀察到的值

  • 先觀察失敗的最底層 matcher(例如 Gte),再往上看 Field/And,能快速定位條件不符的原因

  • Trace 僅用於除錯,請勿在大量資料或生產環境長時間開啟

Explain vs Trace:何時用哪一個

  • 條件對不對?先 explain 看樹結構

  • 資料為什麼不符合?再 trace 看每層節點的命中與否

  • 有了這兩個工具,讀者能以「先結構、後動態」的方式縮短問題定位時間

常見踩雷與對策

  • 鍵名(symbol/string/dot notation)不一致 → 使用 KeyConverter 統一

  • 陣列欄位單值條件未命中 → 留意自動包裝 $elemMatch 的語意

  • $in/$nin 對陣列欄位是「交集」而非 include? → 請以 explain/trace 驗證期望

  • 資料集為空時 explain 輸出過於簡略 → 先準備樣本資料或用 limit(1) 取樣

  • Trace 輸出過長 → 以小資料集重現,或在測試層級驗證

綜合範例(Explain + Trace 串用)

records = [
  { 'name' => 'Ann',  'age' => 19, 'tags' => [{ 'name' => 'ruby',  'priority' => 6 }] },
  { 'name' => 'Ben',  'age' => 17, 'tags' => [{ 'name' => 'rails', 'priority' => 3 }] },
  { 'name' => 'Cody', 'age' => 22, 'tags' => [{ 'name' => 'ruby',  'priority' => 8 }] }
]

q = records.mongory
  .where(:age.gte => 18)
  .where(:tags.elem_match => { :name => 'ruby', :priority.gt => 5 })

q.explain
q.trace { |_| }

筆者在實務上會以 explain 驗證語意、用 trace 驗證資料流,兩者搭配能在迭代條件與轉換器(Converters)時保持信心

下一篇開始進入 Week 2:Day 8〈為什麼 Ruby 不夠快〉,談 benchmark 與方法學,以及開始 C 語言的世界!

專案首頁(Ruby 版)


上一篇
Day 6:Query builder 與 converters:ActiveRecord / Mongoid 實戰
下一篇
Day 8:為什麼 Ruby 不夠快?benchmark、目標與方法學
系列文
Mongory:打造跨語言、高效能的萬用查詢引擎11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言