2012-02-09 61 views
0

我有一個有趣的問題。我有一個可用的M/R版本,但它在小規模環境中並不是一個真正可行的解決方案,因爲它太慢,查詢需要實時執行。在沒有MapReduce的情況下在MongoDB中應用函數和排序

我想遍歷集合中的每個元素並對它進行評分,按降序排序,限制到前10位並將結果返回給應用程序。

這裏是我想應用於僞代碼中的每個文檔的函數。

var score = 0; 
foreach(tag in document.Tags) { 
    score += someMap[tag]; 
} 
return score; 
+0

'someMap'的內容是否固定?或者他們會隨着時間而改變,或者每個查詢改變一次?如果它們在更新文檔時是固定的並且已知的,那麼最好的辦法是做映射應用程序端並將分數直接插入到文檔中(即插入到與'tags'平行的數組中,或者作爲標量「分數」屬性)。 – dcrosta 2012-02-09 14:42:28

+0

someMap由應用程序生成,因此它是已知的。我沒有更新任何文件,我只是閱讀他們的信息並給他們打分。 – Dharun 2012-02-09 14:55:22

+0

根據'someMap',寫文檔的應用程序可以插入他們的分數嗎? – dcrosta 2012-02-09 15:03:07

回答

3

由於您的someMap正在改變每一次,我沒有看到任何其他的替代比得分的所有文件,並返回得分最高的。無論您採用哪種方法進行此類操作,您都必須考慮集合中的所有文檔,這些文檔的速度會很慢,並且隨着您掃描的集合的增長,它將變得越來越昂貴。

map reduce的一個問題是,每個mongod實例只能運行一個併發map reduce。這是javascript引擎的一個限制,它是單線程的。縮小的多個地圖將被交織,但它們不能彼此同時運行。這意味着,如果您依賴地圖縮減來實現「實時」使用,也就是說,如果您的網頁必須運行地圖縮減渲染,那麼您最終會達到頁面加載時間變得無法接受的緩慢限制。

您可以通過查詢所有文檔到應用程序中,並在應用程序代碼中進行評分,排序和限制來解決此問題。與map reduce不同,MongoDB中的查詢可以同時運行,但這當然意味着您的應用程序服務器將不得不做很多工作。

最後,如果您願意等待MongoDB 2.2發佈(應該在幾個月內),您可以使用新的aggregation framework代替映射縮減。您將不得不按摩someMap以生成正確的管道步驟。下面是什麼,這可能看起來像如果someMap{"a": 5, "b": 2}一個例子:

db.runCommand({aggregate: "foo", 
    pipeline: [ 
     {$unwind: "$tags"}, 
     {$project: { 
      tag1score: {$cond: [{$eq: ["$tags", "a"]}, 5, 0]}, 
      tag2score: {$cond: [{$eq: ["$tags", "b"]}, 3, 0]}} 
     }, 
     {$project: {score: {$add: ["$tag1score", "$tag2score"]}}}, 
     {$group: {_id: "$_id", score: {$sum: "$score"}}}, 
     {$sort: {score: -1}}, 
     {$limit: 10} 
    ]}) 

這是一個有點複雜,和熊解釋:

  1. 首先,我們以「放鬆」的標籤陣列,從而使遵循管道處理文檔中「標記」是標量的步驟 - 數組中標記的值 - 以及所有其他文檔字段(特別是_id)針對每個展開的元素進行復制。
  2. 我們使用投影算子將標籤轉換爲命名分數字段。每個大致的表達式(對於tag1score示例)「如果'tags'字段id中的文檔中的值等於'a',則返回5並將該值分配給新字段tag1score,否則返回0並分配「。對於您的someMap中的每個標記/評分組合,都會重複此表達式。在此流水線中,每個文檔將包含N tagNscore個字段,但其中至多有一個將具有非零值。
  3. 接下來我們使用另一個投影算子創建一個score字段,其​​值是文檔中tagNscore字段的總和。
  4. 接下來,我們將這些文檔按它們的_id進行分組,並將上一步中的score字段的值彙總到每個組中的所有文檔中。
  5. 我們排序score,降(即最大得分第一)
  6. 我們僅限制於前10名的分數。

我會離開它作爲一個練習讀者如何someMap轉換成正確的投影組在步驟2中,和正確的字段集在步驟3中添加

這主要是與應用程序代碼或映射減少相同的一組步驟可以完成,但具有以下獨特優勢:不是map reduce,而是使用C++完全實現了聚合框架,並且它比map reduce更快並且更具併發性;與查詢應用程序中的所有文檔不同,聚合框架可與服務器端的數據配合使用,從而節省網絡負載。但是,與其他兩種方法一樣,這仍然需要考慮每個文檔,並且只能在計算所有分數後限制結果集。

+0

多麼美妙的答案,謝謝。與此混淆了一段時間。我現在正在按照你的建議對應用程序進行所有計算,一旦出現2.2,我將按照你所說的完全遵循。 – Dharun 2012-02-09 17:25:50

+0

我應該提到 - 你可以從http://mongodb.org/downloads下載MongoDB 2.1或夜間開發版本。 2.1和睡衣都有聚合框架,但不推薦用於生產用途。 – dcrosta 2012-02-09 17:55:36

+0

文檔確實提到了2.1中可用的聚合,我們將在開發中進行嘗試。 – Dharun 2012-02-09 22:14:24

相關問題