在介紹 MongoDB 索引的系列文章中,我們介紹了為什麼要使用索引、使用索引的優缺點、唯一值索引及超時刪除索引。今天接著介紹 聯合索引 Compound Indexes 及 文本索引 Text Index。
我們之前介紹的索引都是只由單一欄位去創建索引,而 聯合索引 就是由兩個以上的欄位去聯合創建的索引。
由上圖來說明,如果我們只用 userid 來建索引,索引只會存一個 "ca2",用 pointer 去指向 collection 中不同的位置。
但如果我們使用 { userid: 1, score: -1 } 來建立聯合索引,則會先依照 userid 由小到大排序,再依照 score 由大到小排序。
建立聯合索引的指令為:db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
例如我們執行以下指令:db.people.createIndex({name: 1, age: 1})
查詢目前的索引:db.people.getIndexes()
從結果可以發現,我們剛才建立的索引名稱為 "name_1_age_1",key 值有兩個,分別為 "name" 及 "age"。
接著我們先對 name 欄位執行 find() :db.people.explain().find({name: "Jack"})
從查詢結果中觀察以下兩點:
可以知道我們剛才的查詢動作,是對 "name_1_age_1" 這個索引進行 Index Scan。
我們再對 name 及 age 這兩個欄位同時查詢:db.people.explain().find({name: "Jack", age: 27})
觀察查詢結果:
發現同時對 name 及 age 這兩個欄位同時查詢,也是對 "name_1_age_1" 這個索引進行 Index Scan。
而如果我們只對 age 欄位做查詢:db.people.explain().find({age: 27})
從上圖可以發現,如果只對 age 欄位做查詢,則是直接使用 Collection Scan 來執行查詢,而非透過剛才建立的 "name_1_age_1" 這個聯合索引來查詢。
我們可以由以上的範例得知,聯合索引的順序很重要。
我們試著對 name 及 age 個別建立索引:
db.people.createIndex({name: 1})
db.people.createIndex({age: 1})
可以從查詢結果看到我們剛才建立的兩個索引,分別為 "name_1" 及 "age_1"。
如果我們對兩個欄位 name 及 age 同時查詢:db.people.explain().find({name: "Jack", age: 27})
其查詢結果有顯示 winningPlan 及 rejectedPlans,以下分別來說明:
第二個沒被採用的方法是同時對 "name_1" 及 "age_1" 這兩個索引進行 Index Scan。
我們對 title 欄位創建文本索引:db.demo.createIndex({title: "text"})
查看剛創建的索引:db.demo.getIndexes()
接著,我們可以透過剛才建立的文本索引來查詢關鍵字。
首先,我們想要查詢有關鍵字 "room" 的資料,要使用 $text
及 $search
這兩個運算子:db.demo.find({$text: {$search: "room"}})
但如果我們想要查詢含有 "the" 的資料:db.demo.find({$text: {$search: "the"}})
會發現其查詢結果為空,那是因為在 MongoDB 中,"the" 這種無意義的詞不是關鍵字,因此會回傳空白。
我們也可以同時查詢多個關鍵字:db.demo.find({$text: {$search: "war room"}})
此查詢結果會回傳擁有 "war" 或 "room" 這兩個詞的資料。
而如果我們是想要查詢擁有 "war room" 這兩個連續詞的資料,則可以透過以下指令:db.demo.find({$text: {$search: "\"war room\""}})
預設的查詢結果不分大小寫,如果想要分辨分小寫,則需使用 $caseSensitive
這個運算子。
例如我們想查詢擁有的 "room" 的資料:db.demo.find({$text: {$search: "room"}})
但如果只想查詢擁有小寫 "room" 的資料:db.demo.find({$text: {$search: "room", "$caseSensitive": true}})
如果想要刪除所建立的文本索引,須透過 index name 來刪除:db.demo.dropIndex("title_text")
我們之前示範創建索引的方法,都是在前台去創建索引,例如我們使用以下指令來創建索引:db.people.createIndex({name: 1})
,其創建結果須等待索引創建完成後,才會回傳。
但如果我們使用 background: true 來創建索引:db.people.createIndex({name: 1}, {background: true})
透過以上方法來創建索引,索引尚未創建完成(在後台執行),即會回傳訊息,可繼續進行其他操作,不需等待。
這篇文章為索引的系列文章最後一篇,介紹了聯合索引、文本索引以及在後台創建索引的小技巧。下一篇會介紹 MongoDB 中的地理空間數據處理。