萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> php編程 >> PHP驅動MongoDB整數問題的BUG和策略

PHP驅動MongoDB整數問題的BUG和策略

   本文所說的整數問題,其實並不是MongoDB的問題,而是PHP驅動的問題:MongoDB本身有兩種整數類型,分別是:32位整數和64位整數,但舊版的PHP驅動不管操作系統是32位還是64位,把所有整數都當做32位整數處理,結果導致64位整數被截斷。為了在盡可能保持兼容性的前提下解決這個問題,新版PHP驅動加入了mongo.native-long選項,以期在64位操作系統中把整數都當做64位來處理,有興趣的可參考:64-bit integers in MongoDB。

  那麼PHP驅動真的完全解決了整數問題麼?NO!在處理group操作的時候還有BUG:

  為了說明問題,我們先來生成一些測試數據:

  ini_set('mongo.native_long', 1);

  $instance = new Mongo();

  $instance = $instance->selectCollection('test', 'test');

  for ($i = 0; $i < 10; $i++) {

  $instance->insert(array(

  'group_id' => rand(1, 5),

  'count' => rand(1, 5),

  ));

  }

  ?>

  下面讓我們使用group操作,根據group_id分組,匯總計算count:

  ini_set('mongo.native_long', 1);

  $instance = new Mongo();

  $instance = $instance->selectCollection('test', 'test');

  $keys = array('group_id' => 1);

  $initial = array('count' => 0);

  $reduce = '

  function(obj, prev) {

  prev.count += obj.count;

  }

  ';

  $result = $instance->group($keys, $initial, $reduce);

  var_dump($result);

  ?>

  結果和預想的有出入,count沒有實現累加,而是變成了[object Object],目前,如果必須使用group操作,那麼有兩種方法可以緩解這個問題:

  ini_set('mongo.native_long', 0);

  $initial = array('count' => (float)0);

  這兩種方法都是治標不治本的權宜之計,既然當前PHP驅動裡group的實現有問題,那我們就繞開它,用其它的方式實現同樣的功能,這個方式就是MapReduce:

  ini_set('mongo.native_long', 1);

  $instance = new Mongo();

  $instance = $instance->selectDB('test');

  $map = '

  function() {

  emit(this.group_id, this.count);

  }

  ';

  $reduce = '

  function(key, values) {

  var sum = 0;

  for (var index in values) {

  sum += values[index];

  }

  return sum;

  }

  ';

  $result = $instance->command(array(

  'mapreduce' => 'test',

  'map' => $map,

  'reduce' => $reduce

  ));

  $result = iterator_to_array($instance->{$result['result']}->find());

  var_dump($result);

  ?>

  把大象放冰箱裡需要三步,而使用MapReduce僅僅需要Map和Reduce兩步即可,這裡有一個PDF文檔生動的說明了MySQL中GROUP BY和MongoDB中MapReduce的對應關系:

PHP驅動MongoDB整數問題的BUG和策略  三聯
copyright © 萬盛學電腦網 all rights reserved