2012-06-24 166 views
3

首先,它是我在Mongo的第一次...蒙戈DB的MapReduce在PHP

理念:

  1. 用戶能夠以自然語言描述的圖像。
  2. 劃分用戶輸入並將他描述的單詞存儲在名爲 的單詞中。
  3. 用戶必須能夠查看最常用的單詞並將這些單詞添加到他們的描述中。
  4. 系統將使用最常用的單詞(對於所有用戶)並使用這些單詞來描述圖像。

我的話文件(目前)如下(實施例)

{ 
"date": "date it was inserted" 
"reported": 0, 
"image_id": "image id" 
"image_name": "image name" 
"user": "user _id" 
"word": "awesome" 
} 

的話將被複制,使得每個字都可以關聯到用戶...

問題 :我需要執行一個Mongo查詢來讓我知道最常用的單詞(描述一個圖像),這些單詞不是由給定的用戶創建的。 (滿足上述第3點)

我見過的MapReduce算法,但是從我讀有幾個問題吧:

  1. 無法排序結果(我可以從訂單大多數用於較少使用)
  2. 在數百萬的文檔中,它可能有很大的處理時間。
  3. 不能限制結果返回的數字

我想過,每天在指定時間運行任務來存儲文檔(在不同的集合)的列表中的字詞的排名一個給定的用戶不習慣描述給定的圖像。我不得不此限制在300個結果,或者什麼(在正常的限度?任何想法)喜歡的東西:

{ 
user_id: "the user id" 
[ 
{word: test, count: 1000}, 
{word: test2, count: 980}, 
{word: etc, count: 300} 
] 
} 

問題我用此溶液看到的是:

  1. 結果將有相當的延遲是不可取的。
  2. 服務器負載,同時產生這個文件對所有用戶都可以秒殺(我其實不是很瞭解這一點蒙戈所以這只是一個假設)

也許我的做法沒有任何意義......而也許我在蒙戈方面的經驗不足,正在指向我錯誤的「模式設計」。

對這種問題有什麼可能是一種好方法的想法?

對不起,感謝您的時間和幫助!

若昂

回答

3

但你需要在客戶端的結果進行排序。此外,結果作爲單個BSON對象返回,因此必須相當小 - 小於10,000個鍵,否則您將得到一個異常。根據你的數據結構

代碼示例:

db.words.group({ 
    key : {"word" : true}, 
    initial: {count : 0}, 
    reduce: function(obj, prev) { prev.count++}, 
    cond: {"user" :{ $ne : "USERNAME_TO_IGNORE"}} 
}) 

另一種選擇是使用新的Aggregation framework,這將在2.2版本發佈。像這樣的東西應該工作。

db.words.aggregate({ 
    $match : { "user" : { "$ne" : "USERNAME_TO_IGNORE"} }, 
    $group : { 
    _id : "$word", 
    count: { $sum : 1} 
    } 
}) 

或者你仍然可以使用MapReduce。其實你可以限制和排序輸出,因爲結果是 一個集合。只需在輸出中使用.sort()和.limit()。你也可以使用增量 map-reduce輸出選項,它可以幫助你解決性能問題。看看MapReduce中的out參數。

貝婁是一個例子,它使用增量功能合併在一個words_usage收集新的數據的現有的集合:

m = function() { 
    emit(this.word, {count: 1}); 
}; 


r = function(key , values){ 
    var sum = 0; 
    values.forEach(function(doc) { 
      sum += doc.count; 
    }); 
    return {count: sum}; 
}; 

db.runCommand({ 
    mapreduce : "words", 
    map : m, 
    reduce : r, 
    out : { reduce: "words_usage"}, 
    query : <query filter object> 
}) 

# retrieve the top 10 words 
db.words_usage.find().sort({"value.count" : -1}).sort({"value.count" : -1}).limit(10) 

我想你可以在cron運行上面的MapReduce命令每隔幾分鐘/小時,取決於你想要多準確的結果。對於更新查詢條件,您可以使用文檔創建日期。

一旦你有了系統頂級單詞集合,你可以爲每個用戶建立頂級單詞或者實時計算它們(取決於系統的大小)。

+0

這是一個相當的答案!真的期待着2.2版本。同時我會嘗試您的意見!真的很感謝 – jribeiro

+0

對不起。但是,mapreduce的限制是在一切都計算完畢後應用的,否則它將停止計算10個文檔?另外表現明智什麼是你的推薦考慮到我將在PHP中排序結果(至少在組案例中)。 – jribeiro

+0

在執行MapReduce或在集合上進行排序/查找時應用限制。正如我所說的,你可以隨時重複使用結果。何時更新集合的頻率取決於您。性能明智,你應該沒問題,在PHP端進行排序。如果將來會出現問題,請使用某種緩衝區。 – golja

1

group功能應該是的MapReduce一個簡單的版本。你可以使用它像這樣得到一個總和每個字:已經提到的,你可以使用group命令,它是易於使用的

db.coll.group(
      {key: { a:true, b:true }, 
      cond: { active:1 }, 
      reduce: function(obj,prev) { prev.csum += obj.c; }, 
      initial: { csum: 0 } 
      }); 
+0

它也不支持對結果進行排序嗎? – jribeiro

+0

是啊,排序將不得不發生在客戶端 – matt3141