簡體   English   中英

MongoDB集合上的MapReduce變成空的

[英]MapReduce on MongoDB collection is turning up empty

我一直在嘗試將許多大數據集集成到一個集合中,但是在編寫MapReduce函數到那里時遇到了問題。

這是我的數據的樣子(這里有17行,實際上我有4+百萬):

{"user": 1, "day": 1, "type": "a", "sum": 10}
{"user": 1, "day": 2, "type": "a", "sum": 32}
{"user": 1, "day": 1, "type": "b", "sum": 11}
{"user": 2, "day": 4, "type": "b", "sum": 2}
{"user": 1, "day": 2, "type": "b", "sum": 1}
{"user": 1, "day": 3, "type": "b", "sum": 9}
{"user": 1, "day": 4, "type": "b", "sum": 12}
{"user": 2, "day": 2, "type": "a", "sum": 3}
{"user": 3, "day": 2, "type": "b", "sum": 81}
{"user": 1, "day": 4, "type": "a", "sum": 22}
{"user": 1, "day": 5, "type": "a", "sum": 39}
{"user": 2, "day": 5, "type": "a", "sum": 8}
{"user": 2, "day": 3, "type": "b", "sum": 1}
{"user": 3, "day": 3, "type": "b", "sum": 99}
{"user": 2, "day": 3, "type": "a", "sum": 5}
{"user": 1, "day": 3, "type": "a", "sum": 41}
{"user": 3, "day": 4, "type": "b", "sum": 106}
...  

我試圖使它最終看起來像這樣(每種類型的數組,其中的內容只是當天確定的適當索引中的總和,如果該類型的那天不存在,那只是0):

{"user": 1, "type_a_sums": [10, 32, 41, 22, 39], "type_b_sums": [11, 1, 9, 12, 0]}
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]}
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 81, 99, 106, 0]}
...

這是我一直在嘗試的MapReduce:

var mapsum = function(){
    var output = {user: this.user, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: this.type, tempSum: this.sum, tempDay: this.day}

    if(this.type == "a") {
        output.type_a_sums[this.day-1] = this.sum;
    }

    if(this.type == "b") {
        output.type_b_sums[this.day-1] = this.sum;
    }

    emit(this.user, output);
};

var r = function(key, values) {
    var outs = {user: 0, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: -1, tempSum: -1, tempDay: -1}

    values.forEach(function(v){

        outs.user = v.user;

        if(v.tempType == "a") {
            outs.type_a_sums[v.tempDay-1] = v.tempSum;
        }

        if(v.tempType == "b") {
            outs.type_b_sums[v.tempDay-1] = v.tempSum;
        }

    });

    return outs;
};


res = db.sums.mapReduce(mapsum, r, {out: 'joined_sums'})

這為我提供了小樣本的輸出,但是當我在全部400萬個樣本上運行時,我會得到大量的輸出,如下所示:

{"user": 1, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]}
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]}
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]}

在我應該用實際函數填充之前,其中應該在其數組中加總的大部分users實際上只是用reduce函數outs對象中的虛擬數組中的0填充。

真正奇怪的是,如果我在同一集合上運行相同的確切函數,但僅檢查一個用戶,則res = db.sums.mapReduce(mapsum, r, {query: {user: 1}, out: 'joined_sums'})我知道它們的數組中應該有總和,但是以前一直都設為全0,因此我實際上將僅為該用戶獲得所需的輸出。 在全部400萬個文件中再次運行,到處都回到0。 就像是在覆蓋虛擬填充數組所做的所有工作一樣。

我有太多數據嗎? 給定時間,它是否應該能夠解決問題? 還是我遇到了我不知道的障礙?

感謝您提供許多細節。 這里有一些問題。

讓我們從頭開始。

我試圖讓它最終看起來像這樣

{“用戶”:2,“ type_a_sums”:[0、3、5、0、8],“ type_b_sums”:[0、0、1、2、0]}

實際上看起來像這樣:

{ _id: { "user": 2 }, value: { "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0] }

請注意, _id類似於您的“ group by”,而value則類似於您的“ sum”列。

因此,問題1是您要釋放user作為您的密鑰,但這也是您價值的一部分。 這不是必需的。 reduce只會減少兩個共享相同密鑰的值,您也不需要這一行: outs.user = v.user;

您還有問題2:您的reduce不正確

我認為這與每個鍵多次調用reduce()有關。

reduce()的目標是它將被多次調用。 它應該跨服務器擴展。 因此,一台服務器可以減少調用兩次,然后將這些結果合並並發送到另一台服務器。

這是另一種看待方式。 Reduce減少了一組value對象,並將它們簡化為單個value對象

這里有一些推論:

  • 如果我確實reduce([a, b]) ,它應該與reduce([b, a])
  • 如果我確實reduce([a, reduce([b,c]))它應該與reduce([reduce([a,b]), c])

因此,以什么順序運行它們或減少多少次值都無關緊要,它始終是相同的輸出。

如果您查看您的代碼,這不是正在發生的事情。 只需看看type_a_sums 如果我減少以下兩個values會怎樣?

reduce([ [0,0,1,0,0], [0,2,0,0,0] ]) => ???

對我來說,這看起來像輸出應該是[0,2,1,0,0] 如果是這樣,則不需要所有這些temp_X字段。 相反,您需要集中精力emit正確的數組,然后正確合並這些數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM