共用方式為


管理 Azure DocumentDB 的索引

索引是一種透過快速存取集合中欄位來提升資料檢索速度的結構。 它們透過建立一組有序的資料指標來運作,通常基於關鍵欄位。 Azure DocumentDB 在多種情境中使用索引,包括查詢推送、獨特限制與分片。

這很重要

「_id」欄位是 預設唯一 被索引的欄位,且欄位最大大小可為 2 KB。 建議根據查詢篩選器與謂詞新增索引,以優化效能。

索引類型

為了簡化起見,讓我們來舉一個部落格應用程式的範例,其設置如下:

  • 資料庫名稱cosmicworks
  • 收藏名稱products

此範例應用程式以以下結構將文章儲存為文件。 所有引用的例子都進一步利用了本收藏的結構。

{
  "_id": ObjectId("617a34e7a867530bff1b2346"),
  "title": "Azure DocumentDB - A Game Changer",
  "content": "Azure DocumentDB is a globally distributed, multi-model database service.",
  "author": {lastName: "Doe", firstName: "John"},
  "category": "Technology",
  "launchDate": ISODate("2024-06-24T10:08:20.000Z"),
  "published": true
}

單一欄位索引

單一欄位索引儲存集合中單一欄位的資訊。 單一欄位索引的排序順序不重要。 _id 欄位預設仍保持索引。

Azure DocumentDB 支援在以下位置建立索引。

  • 頂層文件欄位。
  • 嵌入文件。
  • 嵌入文件中的欄位。

以下指令在欄位 author 建立單一欄位索引,並於嵌入欄位 firstName建立索引。

use cosmicworks

db.products.createIndex({"author": 1})

// indexing embedded property
db.products.createIndex({"author.firstName": -1})

一個查詢可在可用時使用多個單一欄位索引。

備註

Azure DocumentDB 允許在一個集合上建立最多 64 個索引。 依照層級,我們可依需求規劃延長至最多300個索引。

複合指數

複合索引透過允許對文件中的多個欄位進行 高效查詢與排序,來提升資料庫效能。 此優化減少掃描整個收藏的需求,加快資料檢索與組織。

以下指令將在欄位 authorlaunchDate 上建立複合索引,並對其進行相反的排序。

use cosmicworks

db.products.createIndex({"author":1, "launchDate":-1})

Order 欄位會影響索引的選擇性或使用率。 find查詢不會使用所建立的索引。

use cosmicworks

db.products.find({"launchDate": {$gt: ISODate("2024-06-01T00:00:00.000Z")}})

局限性

  • 複合索引內最多可包含 32 個欄位/路徑。

部分索引

索引中附有查詢過濾器,描述何時在索引中產生詞彙。

use cosmicworks

db.products.createIndex (
   { "author": 1, "launchDate": 1 },
   { partialFilterExpression: { "launchDate": { $gt: ISODate("2024-06-24T10:08:20.000Z") } } }
)

局限性

  • 部分索引不支援 ORDER BYUNIQUE 除非篩選器符合條件。

文字索引

文字索引是特殊資料結構,用來優化基於文字的查詢,使其更快更有效率。

使用 createIndex 方法並搭配 text 選項以在 title 欄位上建立文字索引。

use cosmicworks;

db.products.createIndex({ title: "text" })

備註

雖然每個集合只能定義一個文字索引,但 Azure DocumentDB 允許你在多個欄位組合上建立文字索引,讓你能在文件中不同欄位間進行文字搜尋。

設定文字索引選項

Azure DocumentDB 中的文字索引提供多種自訂行為的選項。 例如,你可以指定文字分析的語言、設定權重以優先處理特定欄位,以及設定大小寫不區分的搜尋。 這裡有一個建立帶有選項的文字索引範例:

  • 建立一個索引,以支援titlecontent欄位的搜尋,並提供英文語言支援。 另外,給欄位分配較高權重 title ,以在搜尋結果中優先排序。

    use cosmicworks
    
    db.products.createIndex(
        { title: "text", content: "text" },
        { default_language: "english", weights: { title: 10, content: 5 }, caseSensitive: false }
    )
    

備註

當客戶端執行包含「DocumentDB」一詞的文字搜尋查詢時,該集合中每份文件的分數會根據該詞在「標題」與「內容」欄位的出現與頻率計算,其中「標題」欄位因權重較高而獲得更高重要性。

使用文字索引進行文字搜尋

建立好文字索引後,你可以在查詢中使用「text」運算子進行文字搜尋。 文字操作員會將搜尋字串與文字索引比對,以找到相關文件。

  • 請對短語 DocumentDB進行文字搜尋。

    use cosmicworks
    
    db.products.find(
      { $text: { $search: "DocumentDB" } }
    )
    
  • 可選擇性地,在查詢中使用 $meta 投影運算子與 textScore 欄位一同查看權重

    use cosmicworks
    
    db.products.find(
    { $text: { $search: "DocumentDB" } },
    { score: { $meta: "textScore" } }
    )
    

局限性

  • 一個集合只能定義一個文字索引。
  • 排序操作無法使用 MongoDB 中文字索引的排序。
  • Hint() 不支援搭配使用 $text 表達式的查詢。
  • 與其他索引類型相比,文字索引可能相對較大,佔用相當大的儲存空間。

萬用字元索引

對單一欄位建立索引,會索引 field 下的所有路徑,但不包含同一層級的其他欄位。 例如,以下的文件範例

{
 "children":
    {
     "familyName": "Merriam",
     "pets": { "details": {“name”: "Goofy", ”age”: 3} }
   } 
}

在 { “pets.$**”: 1 } 建立索引,會建立詳細資料和子文件屬性的索引,但不會在「familyName」建立索引。

局限性

  • 通配符索引無法支援唯一索引。
  • 萬用字元索引不支援下推 ORDER BY,除非過濾器只包含萬用字元中存在的路徑(因為未定義的元素不會被索引)。
  • 複合萬用字元索引只能包含 one 萬用字元項以及至少 one 個索引項。 { "pets.$**": 1, “familyName”: 1 }

地理空間索引

地理空間索引支援對儲存為 GeoJSON 物件或舊有座標對的資料查詢。 你可以使用地理空間索引來提升對地理空間資料查詢的效能,或執行特定的地理空間查詢。

Azure DocumentDB 提供兩種類型的地理空間索引:

  • 2dsphere 索引,支援解釋球面幾何形狀的查詢。
  • 2D 索引,支援在平面上解讀幾何形狀的查詢。

二維索引

僅支援以傳統座標對格式儲存地理資訊資料的2D索引。

使用 createIndex 方法及 2d 選項,為 location 欄位建立地理空間索引。

db.places.createIndex({ "location": "2d"});

局限性

  • one 位置欄位可成為 2d 索引的一部分,僅 one 非地理空間的其他欄位可成為 compound 2d 索引的一部分 db.places.createIndex({ "location": "2d", "non-geospatial-field": 1 / -1 })

2dsphere 索引

2dsphere 索引支援對類地球球體進行地理空間查詢。 它可以支援 GeoJSON 物件或舊有座標對。 2dSphere 索引可用於 GeoJSON 形式的資料儲存,如果遇到舊版座標點,則會轉換為 GeoJSON 點。

使用 createIndex 方法並搭配 2dsphere 選項,以在 location 字段上建立地理空間索引。

db.places.createIndex({ "location": "2dsphere"});

2dsphere 索引允許在多個地理空間及多個非地理空間資料欄位上建立索引。 db.places.createIndex({ "location": "2d", "non-geospatial-field": 1 / -1, ... "more non-geospatial-field": 1 / -1 })

局限性

  • 不支援使用普通索引和地理空間索引的複合索引。 建立任一地理空間索引都會導致錯誤。

    // Compound Regular & 2dsphere indexes are not supported yet
    db.collection.createIndex({a: 1, b: "2dsphere"})
    
    // Compound 2d indexes are not supported yet
    db.collection.createIndex({a: "2d", b: 1})
    
  • 有洞的多邊形是無法運作的。 插入帶有洞的多邊形並不受限,但 $geoWithin 查詢在以下情境下會失敗:

    1. 如果查詢本身有帶有孔洞的多邊形

      coll.find(
        {
            "b": {
                "$geoWithin": {
                    "$geometry": {
                        "coordinates": [
                            [
                                [ 0, 0], [0, 10], [10, 10],[10,0],[0, 0]
                            ],
                            [
                                [5, 5], [8, 5], [ 8, 8], [ 5, 8], [ 5, 5]
                            ]
                        ],
                        "type": "Polygon"
                    }
                }
            }
        })
      
      // MongoServerError: $geoWithin currently doesn't support polygons with holes
      
    2. 如果有任何未經過濾的文件中含有帶洞的多邊形。

      [mongos] test> coll.find()
        [
          {
            _id: ObjectId("667bf7560b4f1a5a5d71effa"),
            b: {
              type: 'Polygon',
              coordinates: [
                [ [ 0, 0 ], [ 0, 10 ], [ 10, 10 ], [ 10, 0 ], [ 0, 0 ] ],
                [ [ 5, 5 ], [ 8, 5 ], [ 8, 8 ], [ 5, 8 ], [ 5, 5 ] ]
              ]
            }
          }
        ]
      // MongoServerError: $geoWithin currently doesn't support polygons with holes
      
    3. 使用 geoNear時,key欄位是必須的。

       [mongos] test> coll.aggregate([{ $geoNear: { $near: { "type": "Point", coordinates: [0, 0] } } }])
      
       // MongoServerError: $geoNear requires a 'key' option as a String
      

後續步驟