索引是一種透過快速存取集合中欄位來提升資料檢索速度的結構。 它們透過建立一組有序的資料指標來運作,通常基於關鍵欄位。 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個索引。
複合指數
複合索引透過允許對文件中的多個欄位進行 高效查詢與排序,來提升資料庫效能。 此優化減少掃描整個收藏的需求,加快資料檢索與組織。
以下指令將在欄位 author 和 launchDate 上建立複合索引,並對其進行相反的排序。
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 BY或UNIQUE除非篩選器符合條件。
文字索引
文字索引是特殊資料結構,用來優化基於文字的查詢,使其更快更有效率。
使用 createIndex 方法並搭配 text 選項以在 title 欄位上建立文字索引。
use cosmicworks;
db.products.createIndex({ title: "text" })
備註
雖然每個集合只能定義一個文字索引,但 Azure DocumentDB 允許你在多個欄位組合上建立文字索引,讓你能在文件中不同欄位間進行文字搜尋。
設定文字索引選項
Azure DocumentDB 中的文字索引提供多種自訂行為的選項。 例如,你可以指定文字分析的語言、設定權重以優先處理特定欄位,以及設定大小寫不區分的搜尋。 這裡有一個建立帶有選項的文字索引範例:
建立一個索引,以支援
title和content欄位的搜尋,並提供英文語言支援。 另外,給欄位分配較高權重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查詢在以下情境下會失敗:如果查詢本身有帶有孔洞的多邊形
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如果有任何未經過濾的文件中含有帶洞的多邊形。
[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使用
geoNear時,key欄位是必須的。[mongos] test> coll.aggregate([{ $geoNear: { $near: { "type": "Point", coordinates: [0, 0] } } }]) // MongoServerError: $geoNear requires a 'key' option as a String
後續步驟
- 了解索引編製最佳做法,以取得最有效率的結果。
- 了解 背景索引
- 點此了解如何使用 文字索引。
- 在這裡了解 Wildcard 索引技術。