2010-07-20 86 views
10

我正在使用Mongo MapReduce对一堆文档执行字数统计操作。这些文件是非常简单(只需一个ID和文字的哈希):MongoDB MapReduce不返回PHP中的数据

{ "_id" : 6714078, "words" : { "my" : 1, "cat" : 1, "john" : 1, "likes" : 1, "cakes" : 1 } } 
{ "_id" : 6715298, "words" : { "jeremy" : 1, "kicked" : 1, "the" : 1, "ball" : 1 } } 
{ "_id" : 6717695, "words" : { "dogs" : 1, "can't" : 1, "look" : 1, "up" : 1 } } 

的数据库称为在我的环境,有问题的集合被命名为“wordsX”,其中X是一个类别号码(“词”我知道,不要问)。文档散列中存储单词的字段也称为“单词”。嘎。

我遇到的问题是,在我的PHP应用程序的某些条件下,MapReduce不会返回任何数据。令人烦恼的是,从Mongo shell运行相同的命令给出了完美的结果。我试图找出发生这种错误的位置,但我真的很难过,所以希望有人能够阐明这一点。这个问题的引导确实有点过分,因为环境有点复杂,但请耐心等待。是

我试着从蒙戈shell中运行复制基于PHP的操作的命令如下:

m = function() { 
    if (this.words) { 
     for (index in this.words) { 
      emit(index, this.words[index]); 
     } 
    } 
} 
r = function (key, values) { 
    var total = 0; 
    for (var i in values) { 
     total += values[i]; 
    } 
    return total; 
} 
res = db.words.mapReduce(m, r, { query : { _id : { $in : [6714078,6715298,6717695] } } }); 

这导致临时集合包含字数数据被创建。到目前为止,一切OK。

但是,如果我从PHP(使用标准的Mongo库)运行相同的命令,我最终没有在某些条件下的数据。描述有点棘手,因为我不想让你知道Mongo之外的应用程序/环境的细节,但基本上我使用Sphinx来过滤一些记录,然后向Mongo提供一个内容ID列表, MapReduce被执行。如果我过滤2到3天的数据集,我会从Mongo获得结果;如果我不过滤,我会返回一个空数据集。运行相同操作的PHP代码如下。我没有包含基于Sphinx的部分,因为我不认为它们是相关的(只知道我们得到了一个ID列表),因为我已经尝试在命令行上向Mongo提供完全相同的列表,并获得了正确的结果,而我不从PHP内。希望这是有道理的。

PHP代码我使用看起来像这样:

$objMongo = new Mongo(); 
$objDB = $objMongo->words; 

$arrWordList = array(); 

$strMap = ' 
    function() { 
     if (this.words) { 
      for (index in this.words) { 
       emit(index, this.words[index]); 
      } 
     } 
    } 
'; 

$strReduce = ' 
    function(key, values) { 
     var total = 0; 
     for (var i in values) { 
      total += values[i]; 
     } 
     return total; 
    } 
'; 

$objMapFunc = new MongoCode($strMap); 
$objReduceFunc = new MongoCode($strReduce); 
$arrQuery = array(
    '_id' => array('$in' => $arrIDs) // <--- list of IDs from Sphinx 
); 
$arrCommand = array(
    'mapreduce' => 'wordsX', 
    'map' => $objMapFunc, 
    'reduce' => $objReduceFunc, 
    'query' => $arrQuery 
); 

MongoCursor::$timeout = -1; 

$arrStatsInfo = $objDB->command($arrCommand); 

var_dump($arrStatsInfo); 

结果-信息阵列($arrStatsInfo)的内容下工作和非工作条件(如上面指定的过滤)如下。

工作结果:

array(4) { 
    ["result"]=> 
    string(31) "tmp.mr.mapreduce_1279637336_227" 
    ["timeMillis"]=> 
    int(171) 
    ["counts"]=> 
    array(3) { 
    ["input"]=> 
    int(54) 
    ["emit"]=> 
    int(2517) 
    ["output"]=> 
    int(1526) 
    } 
    ["ok"]=> 
    float(1) 
} 

空的结果:

array(4) { 
    ["result"]=> 
    string(31) "tmp.mr.mapreduce_1279637381_228" 
    ["timeMillis"]=> 
    int(21) 
    ["counts"]=> 
    array(3) { 
    ["input"]=> 
    int(0) 
    ["emit"]=> 
    int(0) 
    ["output"]=> 
    int(0) 
    } 
    ["ok"]=> 
    float(1) 
} 

所以它看起来像破碎的条件下,没有记录,甚至使之成为MapReduce的。我花了很多时间试图弄清楚到底发生了什么,但迄今为止我还没有发现任何见解。正如我所说的,使用完全相同的ID集合直接在Mongo命令行中运行相同的命令(如上所述)会返回正确的结果。

毕竟,我想我的问题是:是否有任何明显的错误与我在上面做的PHP Mongo交互?我可以采取其他措施来尝试调试吗?

请让我知道,如果提供任何进一步的信息将有所帮助。我很欣赏这是一个有点膨胀和不明确的问题,但我尽我所能来沟通这个问题!真的希望有人能提出一个解决方法。

非常感谢您的阅读!

+3

事实证明,这个bug的行为实际上是(惊喜)应用程序中其他地方代码的结果。我们有两个例程来将文件插入数据库;一个跑了一大批,另一个跑得很快。一个使用数字字符串作为ID,另一个使用整数。他们一目了然,但事实上创造了不同的文件!我们现在已经在任何地方都使用了明确的int投射(当然,我们原本应该这样做),现在一切正常。 故事的寓意是,非常肯定你可以区分整数和数字字符串! :) – BigglesZX 2010-07-21 13:58:06

+0

这不是对您的问题的直接回答,但我建议您尝试询问[mongodb用户](http://groups.google.com/group/mongodb-user?hl=en)列表 - - 它可能是PHP库绑定中的一个错误,MongoDB工作人员通常会快速响应问题和错误报告。该列表更有可能为您提供帮助,而不是在本网站发布,恕我直言。 – 2010-07-20 15:23:56

+1

哎唷,希望在阅读完代码之前阅读,但这是我的猜测。 :)你应该投票结束你的问题,或自己回答。 – 2012-08-15 01:30:54

回答

0

对于未来的读者,这个问题原来是由于应用程序中其他地方的ints/numeric字符串处理不一致造成的。对不起,关于红鲱鱼!