時間過得好快,不知不覺已經來到第二週了,從這週開始會和大家一起閱讀 DataFusion 的原始碼,
從專案的模組架構逐步理解 DataFusion 在程式碼層面如何從解析查詢語法到實際讀取資料的過程。也相信透過這樣的方式能對 DataFusion 有更深入的理解。
閱讀原始碼之前,我們整個 DataFusion 專案大致的結構,可以看到專案中 datafusion 內有非常多的子目錄,這些子目錄其實都是一個個 crate,也可以說是一個獨立的模組。
......
├── datafusion
│   ├── CHANGELOG.md
│   ├── catalog
│   ├── catalog-listing
│   ├── common
│   ├── common-runtime
│   ├── core
│   ├── datasource
│   ├── datasource-avro
│   ├── datasource-csv
│   ├── datasource-json
│   ├── datasource-parquet
│   ├── doc
│   ├── execution
│   ├── expr
│   ├── expr-common
│   ├── ffi
│   ├── functions
......
DataFusion 主要依照功能拆分這些 Crate,這樣的設計有以下三個優點:
為了能有效的管理多個 Crate,DataFusion 使用 Cargo Workspace 來共享 Crate 間相同的引用,避免重複編譯相同的依賴。
# 專案根目錄的 Cargo.toml
[workspace]
members = [
    "datafusion/common",
    "datafusion/expr",
    "datafusion/sql",
    "datafusion/optimizer",
    "datafusion/physical-expr",
    "datafusion/physical-plan",
    "datafusion/core",
    # ... 還有更多
]
由於 DataFusion 的 Crate 實在太多了,所以我們今天只介紹幾個和主要功能相關的 Crate
datafusion 主要入口位置:datafusion/core/
作用:對外的統一介面,重新匯出所有核心功能
主要功能:
SessionContext - 查詢的入口關鍵檔案:
src/execution/context.rs - SessionContext 實作src/dataframe/mod.rs - DataFrame APIsrc/prelude.rs - 常用的重新匯出datafusion-common - 共用基礎設施位置:datafusion/common/
作用:提供各模組共用的基礎型別和工具
主要內容:
DataFusionError 型別ScalarValue、Column、DFSchema
為什麼需要 common?
多個 crate 都需要相同的基礎型別,放在 common 避免循環依賴。
datafusion-expr - 邏輯表達式和計劃位置:datafusion/expr/
作用:定義查詢的邏輯表示(與執行無關)
關鍵特性:
datafusion-sql - SQL 解析器位置:datafusion/sql/
作用:將 SQL 字串轉換成 LogicalPlan
工作流程:
   SQL 字串
      ↓
   DFParser (基於 sqlparser-rs)
      ↓
   AST (抽象語法樹)
      ↓
   SqlToRel
      ↓
   LogicalPlan
datafusion-optimizer - 查詢優化器位置:datafusion/optimizer/
作用:優化 LogicalPlan,提升查詢性能
datafusion-physical-expr - 物理表達式位置:datafusion/physical-expr/
作用:可執行的表達式實作,直接操作 Arrow 資料
與 datafusion-expr 的差異:
| 特性 | datafusion-expr::Expr | datafusion-physical-expr::PhysicalExpr | 
|---|---|---|
| 目的 | 描述邏輯 | 實際執行 | 
| 資料 | 不涉及資料 | 操作 Arrow Arrays | 
| 型別 | Schema-aware | 需要具體型別 | 
| 優化 | 可被優化器重寫 | 針對執行優化 | 
datafusion-physical-plan - 物理執行計劃位置:datafusion/physical-plan/
作用:定義和實作可執行的查詢計劃
理解各個 Crate 之間的依賴關係很重要:
                    ┌─────────────────┐
                    │   datafusion    │  ← 使用者入口
                    │     (core)      │
                    └────────┬────────┘
                             │
        ┌────────────────────┼────────────────────┐
        ↓                    ↓                    ↓
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│ datafusion-  │    │ datafusion-  │    │ datafusion-  │
│   optimizer  │    │     sql      │    │   physical-  │
│              │    │              │    │     plan     │
└──────┬───────┘    └──────┬───────┘    └──────┬───────┘
       │                   │                   │
       │            ┌──────┴───────┐           │
       │            ↓              ↓           │
       │      ┌────────────┐ ┌─────────────┐   │
       └─────→│ datafusion-│ │ datafusion- │←─ ┘
              │    expr    │ │  physical-  │
              │            │ │    expr     │
              └─────┬──────┘ └──────┬──────┘
                    │               │
                    └───────┬───────┘
                            ↓
                    ┌──────────────┐
                    │ datafusion-  │  ← 共用基礎
                    │    common    │
                    └──────────────┘
依賴層級說明:
datafusion-common:所有其他 crate 的基礎datafusion-expr:定義邏輯表示datafusion-sql, datafusion-optimizer:處理輸入和優化datafusion-physical-expr, datafusion-physical-plan:實際執行datafusion:組合所有功能