2016-06-15 24 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.谢谢你的描述性答案。 –

相关问题