Example #1
0
 /**
  * 执行map reduce操作,为了防止数据量过大,导致无法完成mapreduce,统一采用集合的方式,取代内存方式
  * 内存方式,不允许执行过程的数据量量超过物理内存的10%,故无法进行大数量分析工作。
  *
  * @param array $command            
  */
 public function mapReduce($out = null, $map, $reduce, $query = array(), $finalize = null, $method = 'replace', $scope = null, $sort = array('$natural' => 1), $limit = null)
 {
     if ($out == null) {
         $out = md5(serialize(func_get_args()));
     }
     try {
         // map reduce执行锁管理开始
         $locks = new self($this->_configInstance, 'locks', DB_MAPREDUCE, $this->_cluster);
         $locks->setReadPreference(\MongoClient::RP_PRIMARY_PREFERRED);
         $checkLock = function ($out) use($locks) {
             $check = $locks->findOne(array('out' => $out));
             if ($check == null) {
                 $locks->insert(array('out' => $out, 'isRunning' => true, 'expire' => new \MongoDate(time() + 300)));
                 return false;
             } else {
                 if (isset($check['isRunning']) && $check['isRunning']) {
                     return true;
                 }
                 if ($check['isRunning'] && isset($check['expire']) && $check['expire'] instanceof \MongoDate) {
                     if ($check['expire']->sec > time()) {
                         return true;
                     } else {
                         $releaseLock($out);
                         return false;
                     }
                 }
                 $locks->update(array('out' => $out), array('$set' => array('isRunning' => true, 'expire' => new \MongoDate(time() + 300))));
                 return false;
             }
         };
         $releaseLock = function ($out, $rst = null) use($locks) {
             return $locks->update(array('out' => $out), array('$set' => array('isRunning' => false, 'rst' => is_string($rst) ? $rst : Json::encode($rst))));
         };
         $failure = function ($code, $msg) {
             if (is_array($msg)) {
                 $msg = Json::encode($msg);
             }
             return array('ok' => 0, 'code' => $code, 'msg' => $msg);
         };
         // map reduce执行锁管理结束
         if (!$checkLock($out)) {
             $command = array();
             $command['mapreduce'] = $this->_collection;
             $command['map'] = $map instanceof \MongoCode ? $map : new \MongoCode($map);
             $command['reduce'] = $reduce instanceof \MongoCode ? $reduce : new \MongoCode($reduce);
             $command['query'] = $this->appendQuery($query);
             if (!empty($finalize)) {
                 $command['finalize'] = $finalize instanceof \MongoCode ? $finalize : new \MongoCode($finalize);
             }
             if (!empty($sort)) {
                 $command['sort'] = $sort;
             }
             if (!empty($limit)) {
                 $command['limit'] = $limit;
             }
             if (!empty($scope)) {
                 $command['scope'] = $scope;
             }
             $command['verbose'] = true;
             if (!in_array($method, array('replace', 'merge', 'reduce'), true)) {
                 $method = 'replace';
             }
             $command['out'] = array($method => $out, 'db' => DB_MAPREDUCE, 'sharded' => false, 'nonAtomic' => in_array($method, array('merge', 'reduce'), true) ? true : false);
             $rst = $this->command($command);
             $releaseLock($out, $rst);
             if ($rst['ok'] == 1) {
                 if ($rst['counts']['emit'] > 0 && $rst['counts']['output'] > 0) {
                     $outMongoCollection = new self($this->_configInstance, $out, DB_MAPREDUCE, $this->_cluster);
                     $outMongoCollection->setNoAppendQuery(true);
                     return $outMongoCollection;
                 }
                 return $failure(500, $rst['counts']);
             } else {
                 return $failure(501, $rst);
             }
         } else {
             return $failure(502, '程序正在执行中,请勿频繁尝试');
         }
     } catch (\Exception $e) {
         if (isset($releaseLock) && isset($failure)) {
             $releaseLock($out, exceptionMsg($e));
             return $failure(503, exceptionMsg($e));
         }
         var_dump(exceptionMsg($e));
     }
 }