2016-06-15 53 views
1

我有一個Test數據庫的集合稱爲collection解碼:MapReduce的使用命令無法文件從服務器

{ 
    "_id": "576008e5b47a6120c800418d", 
    "UserID": "Paul", 
    "Page": "A" 
} 

我想記錄webactivity和使用的MapReduce得到的結果一樣

{ 
    "_id": "Paul", 
    "value": { 
     "A": 1, 
     "B": 0, 
     "C": 0, 
     "D": 0, 
     "E": 0 
    } 
} 

首先,我嘗試使用PHP 7的簡單代碼MongoDB Driver 1.1.7 MapReduce使用無法解碼來自服務器的文檔的命令:

<?php 
$manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); 
$command = new MongoDB\Driver\Command(array(
    "mapReduce" => "collection", 
    "map" => "function() { emit(this.UserID, 1); }", 
    "reduce" => "function(Users, Pages){". 
    "return Pages;}", 
    "out" => "ex" 
)); 
try { 
    $cursor = $manager->executeCommand('Test.collection', $command); 
    $response = $cursor->toArray()[0]; 
} catch(MongoDB\Driver\Exception $e) { 
    echo $e->getMessage(), "\n"; 
    exit; 
} 
var_dump($response); 
?> 

任何想法將不勝感激謝謝。

回答

0

不太確定,如果我建議MapReduce用於這種類型的操作,會說聚合框架將會執行更好性能的聚合,因爲操作全部在本地代碼中完成,而不會產生代碼以便編譯JavaScript(在MapReduce案例)。

隨着聚合操作,所有你需要的是一個$group管道,它利用了$cond運營商允許你變換分析邏輯條件爲價值。在這種情況下,您需要指定pages作爲鍵和它們的計數值,其中文檔按UserID分組。

考慮蒙戈殼運行以下聚合操作:


db.collection.aggregate([ 
    { 
     "$group": { 
      "_id": "$UserID", 
      "A": { 
       "$sum": { 
        "$cond": [ 
         { "$eq": [ "$Page", "A" ] }, 
         1, 
         0 
        ] 
       } 
      }, 
      "B": { 
       "$sum": { 
        "$cond": [ 
         { "$eq": [ "$Page", "B" ] }, 
         1, 
         0 
        ] 
       } 
      }, 
      "C": { 
       "$sum": { 
        "$cond": [ 
         { "$eq": [ "$Page", "C" ] }, 
         1, 
         0 
        ] 
       } 
      }, 
      "D": { 
       "$sum": { 
        "$cond": [ 
         { "$eq": [ "$Page", "D" ] }, 
         1, 
         0 
        ] 
       } 
      }, 
      "E": { 
       "$sum": { 
        "$cond": [ 
         { "$eq": [ "$Page", "E" ] }, 
         1, 
         0 
        ] 
       } 
      } 
     } 
    } 
]) 

這將產生輸出:

{ 
    "_id": "Paul",  
    "A": 1, 
    "B": 0, 
    "C": 0, 
    "D": 0, 
    "E": 0  
} 

用於上述示例文檔。


爲了簡便起見,如果假設你有頁面的列表事前,可以動態生成管道如下:

var groupOperation = { "$group": { "_id": "$UserID" } }, 
    pages = ["A", "B", "C", "D", "E"]; 

pages.forEach(function (page){ 
    groupOperation["$group"][page] = { 
     "$sum": { 
      "$cond": [ 
       { "$eq": [ "$Page", page ] }, 
       1, 
       0 
      ] 
     } 
    }; 
}) 

db.collection.aggregate([groupOperation]); 

現在,要將這種以PHP如下:

<?php 

$group_pipeline = [ 
    '$group' => [ 
     '_id' => '$UserID', 
     'A' => [ 
      '$sum' => [ 
       '$cond' => [ [ '$eq' => [ '$Page', 'A' ] ], 1, 0 ] 
      ] 
     ], 
     'B' => [ 
      '$sum' => [ 
       '$cond' => [ [ '$eq' => [ '$Page', 'B' ] ], 1, 0 ] 
      ] 
     ], 
     'C' => [ 
      '$sum' => [ 
       '$cond' => [ [ '$eq' => [ '$Page', 'C' ] ], 1, 0 ] 
      ] 
     ], 
     'D' => [ 
      '$sum' => [ 
       '$cond' => [ [ '$eq' => [ '$Page', 'D' ] ], 1, 0 ] 
      ] 
     ], 
     'E' => [ 
      '$sum' => [ 
       '$cond' => [ [ '$eq' => [ '$Page', 'E' ] ], 1, 0 ] 
      ] 
     ] 
    ], 
]; 
$aggregation = $collection->aggregate([ group_pipeline ]); 

?> 

如果您寧願堅持MapReduce,那麼考慮更改地圖並減少功能:

db.collection.mapReduce(
    function() { 
     var obj = {}; 
     ["A", "B", "C", "D", "E"].forEach(function (page){ obj[page] = 0; }); 
     obj[this.Page] = 1;   
     emit(this.UserID, obj); 
    }, 
    function(key, values) { 
     var obj = {}; 
     values.forEach(function(value) { 
      Object.keys(value).forEach(function(key) { 
       if (!obj.hasOwnProperty(key)){ 
        obj[key] = 0; 
       } 
       obj[key]++; 
      }); 
     }); 
     return obj; 
    }, 
    { "out": { "inline": 1 } } 
) 

其中給出的輸出:

{ 
    "results" : [ 
     { 
      "_id" : "Paul", 
      "value" : { 
       "A" : 1, 
       "B" : 0, 
       "C" : 0, 
       "D" : 0, 
       "E" : 0 
      } 
     } 
    ] 
} 

翻譯上述映射精簡操作PHP是微不足道的。

+0

The Results seam只給出了訪問過的所有頁面的總數。假設頁面被訪問,我得到「A」:6,「B」:6,「C」:6,「D」:6,「E」:6.謝謝你的描述性答案。 –

相關問題