iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 20
0
AI & Data

從入門到精通 MongoDB系列 第 23

Day23: 索引 index(4) - 聯合索引 Compound Indexes 與文本索引 Text Index

在介紹 MongoDB 索引的系列文章中,我們介紹了為什麼要使用索引、使用索引的優缺點、唯一值索引及超時刪除索引。今天接著介紹 聯合索引 Compound Indexes文本索引 Text Index


聯合索引 Compound Indexes

我們之前介紹的索引都是只由單一欄位去創建索引,而 聯合索引 就是由兩個以上的欄位去聯合創建的索引。


由上圖來說明,如果我們只用 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()

接著我們先對 name 欄位執行 find() :db.people.explain().find({name: "Jack"})

從查詢結果中觀察以下兩點:

  • "indexName" : "name_1_age_1"
  • "IXSCAN"

可以知道我們剛才的查詢動作,是對 "name_1_age_1" 這個索引進行 Index Scan。

對 name 及 age 兩個欄位同時執行 find()

我們再對 name 及 age 這兩個欄位同時查詢:db.people.explain().find({name: "Jack", age: 27})

觀察查詢結果:

  • "indexName" : "name_1_age_1"
  • "IXSCAN"

發現同時對 name 及 age 這兩個欄位同時查詢,也是對 "name_1_age_1" 這個索引進行 Index Scan。

對 age 欄位執行 find()

而如果我們只對 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,以下分別來說明:

winningPlan

  • "IXSCAN"
  • "indexName" : "name_1"
    表示系統選擇的查詢方法是在 "name_1" 這個索引使用 Index Scan 去查詢。

rejectedPlans

  1. 第一個 inputStage
  • "IXSCAN"
  • "indexName" : "age_1"
    第一個沒被採用的方法是在 "age_1" 這個索引使用 Index Scan 去查詢。
  1. 第二個 inputStage
  • "AND_SORTED"
    • "IXSCAN" , indexName" : "name_1"
    • "IXSCAN" , indexName" : "age_1"

第二個沒被採用的方法是同時對 "name_1" 及 "age_1" 這兩個索引進行 Index Scan。


文本索引 Text Index

創建文本索引

我們對 title 欄位創建文本索引:db.demo.createIndex({title: "text"})

查看剛創建的索引:db.demo.getIndexes()

  • 創建的索引名稱:"title_text"
  • 預設語言:english

使用文本索引查詢關鍵字

接著,我們可以透過剛才建立的文本索引來查詢關鍵字。

首先,我們想要查詢有關鍵字 "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 中的地理空間數據處理。


上一篇
Day22: 索引 index(3) - Unique Index 與 TTL Index
下一篇
Day24: MongoDB 中的地理空間資料處理
系列文
從入門到精通 MongoDB26

尚未有邦友留言

立即登入留言