MongoDB 使用檔案模型,能將關聯式資料函式庫中多表格的資料整合至單一檔案中,提升處理複雜資料的效率。檔案可巢狀儲存子檔案,但受限於最多 100 層的巢狀深度和單一檔案 16MB 的大小限制,以確保效能和穩定性。MongoDB 可透過 createCollection 方法的 validator 選項以及 JSON Schema 格式來定義檔案結構,確保資料符合預期格式。MongoDB Wire Protocol 根據 TCP/IP,定義了客戶端與伺服器間的通訊,理解此協定有助於使用診斷工具。不同程式語言的 MongoDB Driver 將程式碼轉換為 Wire Protocol,語法雖不同,但傳送的封包格式一致。MongoDB 命令涵蓋查詢、資料操作、資料定義和管理等導向,find 命令是主要的資料查詢工具,提供靈活的篩選和排序功能。

MongoDB 結構與概念解析

MongoDB 的檔案模型允許將傳統關聯式資料函式庫中需要多張表格儲存的資料,集中儲存在單一檔案中。這種靈活的檔案結構使得 MongoDB 在處理複雜資料時更具優勢。

檔案巢狀結構與限制

考慮以下 MongoDB 檔案範例:

{
  "_id": 1,
  "name": 'Ron Swanson',
  "address": 'Really not your concern',
  "dob": ISODate('1971-04-15T01:03:48Z'),
  "orders": [
    {
      "orderDate": ISODate('2015-02-15T09:05:00Z'),
      "items": [
        { "productName": 'Meat damper', "quantity": 999 },
        { "productName": 'Meat sauce', "quantity": 9 }
      ]
    },
    { /* other orders */ }
  ]
}

如上述範例所示,檔案可以包含子檔案,而子檔案也可以繼續包含子檔案,形成巢狀結構。然而,這種巢狀結構受到兩項限制:

  1. 預設巢狀層級限制:最多100層巢狀
  2. 檔案大小限制:單一檔案(包含所有子檔案)最大為16MB

內容解密:

  • 檔案巢狀結構使得資料儲存更靈活,但也需要考慮其限制。
  • 巢狀層級限制避免了過深的結構導致的效能問題。
  • 檔案大小限制確保了 MongoDB 在處理大型資料時仍能保持穩定性。

MongoDB 結構定義

在資料函式庫術語中,結構定義了資料函式庫物件內資料的組織方式。預設情況下,MongoDB 資料函式庫不強制執行結構定義,因此可以在集合中儲存任意資料。然而,可以透過 createCollection 方法的 validator 選項建立結構定義,以強制執行檔案的結構。

建立結構定義範例

db.createCollection("customers", {
  "validator": {
    "$jsonSchema": {
      "bsonType": "object",
      "additionalProperties": false,
      "properties": {
        "_id": { "bsonType": "objectId" },
        "name": { "bsonType": "string" },
        "address": { "bsonType": "string" },
        "dob": { "bsonType": "date" },
        "orders": {
          "bsonType": "array",
          "uniqueItems": false,
          "items": {
            "bsonType": "object",
            "properties": {
              "orderDate": { "bsonType": "date" },
              "items": {
                "bsonType": "array",
                "uniqueItems": false,
                "items": {
                  "bsonType": "object",
                  "properties": {
                    "productName": { "bsonType": "string" },
                    "quantity": { "bsonType": "int" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "validationLevel": "strict",
  "validationAction": "warn"
});

內容解密:

  • 結構定義使用 JSON Schema 格式,可以對檔案的屬性進行驗證。
  • 可以定義必填屬性、限制其他屬性和資料型別或範圍。
  • 當 MongoDB 命令導致檔案不符合結構定義時,會產生警告或錯誤。

MongoDB 通訊協定

MongoDB 通訊協定定義了客戶端和伺服器之間的通訊機制。雖然通訊協定的細節不在效能調校的範圍內,但瞭解通訊協定對於使用診斷工具至關重要。

Wire Protocol

MongoDB 通訊協定也稱為 MongoDB Wire Protocol,是 MongoDB 封包的結構,用於客戶端和伺服器之間的通訊。Wire Protocol 根據 TCP/IP 連線,預設使用27017埠。

Wire Protocol 封包結構

雖然 Wire Protocol 的實際封包結構超出本章的範圍,但每個封包的本質是一個 JSON 檔案,包含請求或回應。例如,當我們在 MongoDB Shell 中執行以下命令:

db.customers.find({FirstName:'MARY'},{Phone:1}).sort({Phone:1})

Shell 會透過 Wire Protocol 傳送一個類別似以下的請求:

{
  "find": "customers",
  "filter": { "FirstName": "MARY" },
  "sort": { "Phone": 1.0 },
  "projection": { "Phone": 1.0 },
  "$db": "mongoTuningBook",
  /* 其他屬性 */
}

內容解密:

  • Wire Protocol 是 MongoDB客戶端和伺服器之間通訊的基礎。
  • 瞭解 Wire Protocol 有助於理解診斷工具顯示的資料格式。

MongoDB Driver

MongoDB Driver 將程式語言中的請求轉換為 Wire Protocol 格式。不同的 Driver 可能有細微的語法差異。例如,在 NodeJS 中,前述 MongoDB Shell 請求的語法如下:

const docs = await db.collection('customers')
                       .find({'FirstName': 'MARY'}, {'Phone': 1})
                       .sort({Phone: 1})
                       .toArray();

而在 Go 語言中,同樣的查詢語法如下:

collection := client.Database("MongoDBTuningBook").Collection("customers")
filter := bson.D{{"FirstName", "MARY"}}
findOptions := options.Find()
findOptions.SetSort(map[string]int{"Phone": 1})
findOptions.SetProjection(map[string]int{"Phone": 1})
cursor, err := collection.Find(ctx, filter, findOptions)
var results []bson.M
cursor.All(ctx, &results)

內容解密:

  • MongoDB Driver 負責將程式語言中的請求轉換為 Wire Protocol 格式。
  • 不同程式語言的 Driver 語法可能有所不同,但最終傳送到 MongoDB Server 的封包格式是標準的。

MongoDB 命令分類別

邏輯上,MongoDB 命令可以分為以下幾類別:

  • 查詢命令:如 find()aggregate(),用於從資料函式庫中檢索資訊。
  • 資料操作命令:如 insert()update()delete(),用於修改資料函式庫中的資料。
  • 資料定義命令:如 createCollection()createIndex(),用於定義資料函式庫中的資料結構。
  • 管理命令:如 createUser()setParameter(),用於控制資料函式庫的操作。

find 命令

find 命令是 MongoDB 資料存取的主要工具,具有快速、簡單的語法和靈活、強大的篩選功能。其基本語法如下:

db.collection.find(
  {filter},
  {projection}
).sort({sortCondition}).skip(skipCount).limit(limitCount)

內容解密:

  • find 命令支援多種選項,如篩選條件、投影、排序、跳過和限制傳回的檔案數量。
  • 正確使用 find 命令對於最佳化查詢效能至關重要。

MongoDB 資料查詢與操作指令

MongoDB 提供多種指令來進行資料查詢與操作,包括 find()aggregate()insert()update()delete() 等。這些指令的正確使用對於資料函式庫的效能和一致性至關重要。

find() 指令

find() 指令用於查詢 MongoDB 中的資料。其基本語法如下:

db.collection.find(filter, projection);
  • filter:定義要傳回的檔案條件。
  • projection:指定要傳回的檔案屬性。

find() 還支援 sort()skip()limit() 等方法來控制查詢結果的排序、跳過的檔案數量和傳回的檔案數量。

內容解密:

  1. filter 引數是一個 JSON 檔案,用於定義查詢條件。例如,查詢特定欄位的值可以使用 { field: value }
  2. projection 引數用於指定傳回的檔案中包含或排除哪些欄位。例如,{ field: 1 } 表示包含該欄位,而 { field: 0 } 表示排除該欄位。
  3. 在網路協定中,find() 命令只傳回第一批次的檔案(通常是 1000 個),後續批次透過 getMore 命令取得。MongoDB 的驅動程式通常會自動處理 getMore 命令。

aggregate() 指令

aggregate() 指令提供比 find() 更強大的資料處理能力,包括資料聚合、轉換和過濾等。其基本語法如下:

db.collection.aggregate(pipeline);
  • pipeline:是一個陣列,包含了多個階段的操作,例如 $match$group$sort 等。

常用的 pipeline 運算子包括:

  • $match:過濾檔案。
  • $group:聚合檔案。
  • $sort:排序檔案。
  • $project:定義傳回的檔案屬性。
  • $unwind:將陣列欄位拆分成多個檔案。
  • $limit:限制傳回的檔案數量。
  • $lookup:連線其他集合的檔案。

內容解密:

  1. $match 運算子用於過濾檔案,其語法與 find()filter 相似。
  2. $group 運算子用於聚合檔案,可以進行諸如求和、平均值等操作。
  3. $sort 運算子用於排序檔案,可以根據一個或多個欄位進行排序。
  4. 在使用 aggregate() 時,可以組合多個運算子來完成複雜的資料處理任務。

資料操作指令

MongoDB 提供了 insert()update()delete() 等指令來進行資料的新增、修改和刪除。

內容解密:

  1. insert() 用於新增檔案到集合中。
  2. update() 用於更新集合中的檔案,需要指定過濾條件和更新操作。
  3. delete() 用於刪除集合中的檔案,同樣需要指定過濾條件。

一致性機制

MongoDB 在預設情況下是強一致性的,但可以透過組態寫入關注(write concern)和讀取偏好(read preference)來調整其一致性和可用性。

寫入關注和讀取偏好:

  • 寫入關注決定了何時認為寫入操作已經完成。可以設定為等待大多數副本整合員確認寫入,或者等待所有成員確認。
  • 讀取偏好決定了客戶端從哪裡讀取資料。可以設定為從主節點讀取、從副本文點讀取,或者從最近的節點讀取。

內容解密:

  1. 預設情況下,寫入操作在主節點確認後即視為完成。如果需要更高的資料安全性,可以設定寫入關注為大多數或所有副本文點。
  2. 讀取偏好影響系統的一致性和效能。從副本文點讀取可以提高讀取效能,但可能導致讀取到舊資料。

綜上所述,MongoDB 提供了一系列強大的指令來進行資料查詢和操作,並且透過組態寫入關注和讀取偏好,可以在一致性、可用性和效能之間取得平衡。

MongoDB 交易與查詢最佳化

MongoDB 自版本 4.0 起支援跨多個檔案的原子交易。交易機制確保資料的一致性和完整性。例如,以下範例將一個帳戶的餘額減少 100,並將另一個帳戶的餘額增加 100,兩者要麼同時成功,要麼同時失敗。

session.startTransaction();
mycollection.update({userId:1},{$inc:{balance:100}});
mycollection.update({userId:2},{$inc:{balance:-100}});
session.commitTransaction();

內容解密:

  1. session.startTransaction();:開始一個新的交易。
  2. mycollection.update({userId:1},{$inc:{balance:100}});:將 userId 為 1 的檔案餘額增加 100。
  3. mycollection.update({userId:2},{$inc:{balance:-100}});:將 userId 為 2 的檔案餘額減少 100。
  4. session.commitTransaction();:提交交易,使變更生效。

這確保了兩個更新操作要麼全部成功,要麼全部失敗,從而維護了資料的一致性。

查詢最佳化

MongoDB 的查詢最佳化器負責決定執行查詢的最有效方法。當一個新的查詢或命令傳送到 MongoDB 時,最佳化器會執行以下步驟:

  1. 檢查計劃快取:查詢是否有匹配的查詢計劃。如果找到,則使用該計劃。
  2. 評估可能的執行計劃:如果沒有找到匹配的計劃,則評估所有可能的執行計劃。
  3. 選擇最佳計劃:選擇工作單元數量最少的計劃,並將其儲存在計劃快取中。

MongoDB 通常會盡可能使用根據索引的計劃,並選擇最具選擇性的索引。

MongoDB 架構

Mongod

在簡單的 MongoDB 佈署中,客戶端透過 wire protocol 訊息與 mongod 程式通訊。mongod 是 MongoDB 的核心程式,負責處理所有的資料函式庫請求。

儲存引擎

儲存引擎負責將資料函式庫操作抽象化為底層儲存介質和格式的操作。MongoDB 支援多種儲存引擎,例如 WiredTiger 和 MMAP。WiredTiger 是從 MongoDB 3.2 版本開始的預設儲存引擎,提供高效能的磁碟存取層,包括快取、一致性和平行控制等功能。

此圖示展示了一個簡單的 MongoDB 佈署架構。

複製集

MongoDB 透過複製集實作容錯。複製集由一個主節點和多個從節點組成。主節點接受所有寫入請求,並將變更同步或非同步地傳播到從節點。複製集透過 RAFT 協定選舉主節點,確保在容錯移轉時盡量減少資料丟失或不一致。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title MongoDB 核心概念與架構解析

package "機器學習流程" {
    package "資料處理" {
        component [資料收集] as collect
        component [資料清洗] as clean
        component [特徵工程] as feature
    }

    package "模型訓練" {
        component [模型選擇] as select
        component [超參數調優] as tune
        component [交叉驗證] as cv
    }

    package "評估部署" {
        component [模型評估] as eval
        component [模型部署] as deploy
        component [監控維護] as monitor
    }
}

collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型

note right of feature
  特徵工程包含:
  - 特徵選擇
  - 特徵轉換
  - 降維處理
end note

note right of eval
  評估指標:
  - 準確率/召回率
  - F1 Score
  - AUC-ROC
end note

@enduml

此圖示展示了一個三成員複製集及其選舉過程。

MongoDB 架構與概念回顧

MongoDB 的架構設計是為了支援高效能、可擴充套件性和高用性。在本章中,我們將回顧 MongoDB 的關鍵架構元素,包括複製集(Replica Sets)和分片(Sharding)。

複製集(Replica Sets)

複製集是 MongoDB 的核心功能之一,提供資料冗餘和高用性。複製集由多個節點組成,其中一個節點是主節點(Primary),其他節點是從節點(Secondary)。主節點負責處理寫入操作,而從節點則複製主節點的資料。

寫入關注(Write Concern)

寫入關注是指 MongoDB 在確認寫入操作成功之前,需要等待的節點數量。如果寫入關注大於 1,則每個寫入操作都需要被多個節點確認。這會導致叢集效能下降,但提高了資料的可靠性。

讀取偏好(Read Preference)

讀取偏好決定了 MongoDB 如何分配讀取操作。如果允許從從節點讀取資料,則可以提高讀取效能,因為讀取負載可以分散到多個伺服器上。

分片(Sharding)

分片是 MongoDB 的另一項重要功能,提供水平擴充套件能力。分片將資料分割成多個部分,每個部分稱為一個分片(Shard)。每個分片由一個獨立的 MongoDB 伺服器負責。

分片機制

MongoDB 支援兩種分片機制:範圍分片(Range-based Sharding)和雜湊分片(Hash-based Sharding)。範圍分片根據分片鍵的值將資料分配到不同的分片中,而雜湊分片則根據分片鍵的雜湊值進行分配。

叢集平衡(Cluster Balancing)

當使用範圍分片時,MongoDB 會定期檢查分片之間的平衡,並在必要時進行重新平衡。這是因為範圍分片容易導致資料分佈不均勻,特別是當分片鍵是連續遞增的值時。