(續)MongoDb之MapReduce -- 聚合詳解

1、MongoDB聚合函數說明

max()與min()

一般老是須要找到給定集合裏的某個字段的最大值與最小值。使用sql的數據庫則給咱們提供了max()與min()函數,可是Mongodb並無提供這樣的函數,因此咱們必須本身實現。若是要找到某個字段的最大值,能夠按照該字段降序排序,並限制結果集爲一個文檔;同時,按照相反順序排序則會獲取到該字段的最小值。所以,在monogoDB中的max()與min()則須要對某字段進行排序並限制返回文檔數爲一便可。(利用sort進行排序-1表明降序,1表明升序。)
#返回最大值 
    db.test_test.find().sort({rand:-1}).limit(1)
    #返回最小值
    db.test_test.find().sort({rand:-1}).limit(1)
注意:在實際生產環境中,利用sort排序的時候最好對排序字段加上索引,若是數據量不大,索引與否影響不大,若是數據量大的話,索引的存在對效率影響將是巨大的。
  • distinctsql

    MongoDB的distinct命令是獲取特定字段中不一樣值列表的最簡單工具。該命令既適用於單鍵,也適用於數組鍵。distinct默認覆蓋整個集合,但也能夠經過查詢選擇器進行約束。以下
    **db.test_test.distinct("rand");**

    這個比較簡單。若是但願操做集合的子集,那麼咱們能夠傳入一個查詢選擇器做爲第二個參數。以下:數據庫

    **db.test_test.distinct("rand", {number:5});**
    
    注意:在實用性的方面,distinct與group有一個很大的限制:它們返回的結果集不能超過16MB。16MB的限制並非這些命令自己所強加的的閾值,這是全部的初始查詢結果集大小。distinct與group是以命令的方式實現的,也就是對特殊$cmd集合的查詢,它們賴以生成的查詢受制於該限制。若是distinct與group處理不了你的聚合的結果集,那麼只能用map-reduce代替了,它的結果能夠保存在集合中而非內聯(inline)返回。

group

group和distinct同樣,也是數據庫命令,所以它的結果集也受制於16MB的響應限制。並且,爲了減小內存消耗,group不會處理多於10000個惟一鍵。若是聚合操做在此範圍內,選擇使用group會比使用map-reduce效率高些。group最少須要三個參數。第一個參數是key,定義如何對數據進行分組。第二個參數是一個對結果集作聚合的Javascript函數,叫reduce函數。第三個分組參數是reduce函數的初始文檔。
result = db.test_test.group({
        key: {number:true},
        initial: {rand:0, count:0},
        reduce: function(obj, prev){
            prev.count += 1;
            prev.rand += obj.rand;
        }
    })

PHP中的group簡單應用:數組

# use all fields
    $keys = array();
    # set intial values
    $initial = array("count" => 0);
    # JavaScript function to perform
    $reduce = "function (obj, prev) { prev.count++; }";
    # only use documents where the "a" field is greater than 1
    $condition = array("a" => array( '$gt' => 1));
    $g = $collection->group($keys, $initial, $reduce, $condition);

group選項解釋:框架

  • key:描述分組字段的文檔。鍵的樣式爲:{rand:true, number:true}。除非使用keyf,不然key選項是必需的。分佈式

  • keyf:這是一個JavaScript函數,應用於文檔之上,爲該文檔生成一個鍵,當用於分組的鍵須要計算時,這個函數很是有用。如:function(doc){return函數

  • {day:doc.created_at.getDay();}}。若是沒有指定標準的key的話,則keyf是必需的。工具

  • initial:做爲聚合結果初始文檔。reduce函數第一次運行時,該初始文檔會做爲聚合器的第一個值,一般會包含全部要聚合的鍵。例:{rand:0, count:0}oop

  • reduce:用於執行聚合的JavaScript函數。該函數接受兩個參數:正初迭代的當前文檔和用於存儲聚合結果的聚合器文檔。如上例的應用,注意:reduce函數並不返回任何內容,它只不過是修改聚合器對象,該參數是必需的。大數據

  • cond:過濾要聚合文檔的查詢選擇器,很少解釋了。ui

  • finalize:在返回結果集以前應用於每一個結果文檔的JavaScript函數。該函數支持對分組操做的結果進行後置處理。

map-reduce

在添加map-reduce以前,group是MongoDB惟一的聚合器。map-reduce是後來出於一些緣由加入的。首先,MapReduce風格的操做正在成爲主流(不少開發者是在谷歌那篇著名的關於分佈工計算的論文初次看到MapReduce的。其中的思想後來成了Hadoop的基礎,而Hadoop是一個使用分佈式MapReduce處理大數據的開源框架)。實際緣由,對大數據集進行迭代,尤爲是在分片配置中,須要有分佈式的聚合器,而MapReduce偏偏提供把需的內容。

PHP中的map-reduce的應用:

$query = array('qq_bind_info.openid'=>array('$exists'=>1));
 $map = new MongoCode('function(){emit(this.qq_bind_info.openid, {uid:this._id, step:1})}');
 $reduce = new MongoCode("function(key, vals){".
        "var user_list = new Array();" . 
        "var open_id = new Array();" . 
        "var sum = 0;" . 
        "vals.forEach(function(value){" .
        "sum += value.step;" .
        "open_id.push(key);" .
        "user_list.push(value.uid);" .
        "});" .  
        "return {userlist:user_list, openid:open_id, sum:sum};}");
 $data = $db->command(array(
            'mapreduce' => 'user_profile',
            'map' => $map, 
            'reduce' => $reduce,
            'query' => $query,
            'out' => 'user_profile_temp'
            ));
 print_r($data);

map-reduce選項解釋:

  • map:應用於每一個文檔之上的JavaScript函數。該函數必須調用emit()來選擇要聚合的鍵和值。在函數上下文中,this的值指向當前文檔。例如:function(){emit(this.qq_bind_info.openid,{uid:this._id, step:1})}

  • reduce:一個JavaScript函數,接受一個鍵和一個值列表。該函數對返回值的結構有嚴格要求,必須老是與values數組所提供的結構一致。如上$reduce的MongoCode中的function。

  • query:用於過濾處理的集合的查詢選擇器。與group的con參數相同。 sort:對查詢的排序。

  • limit:一個整數,指定了查詢和排序的條數。

  • out:這個參數決定了如何返回輸出內容。若是須要將輸出做爲命令的返回結果,則須要傳入{inline:true}。注意:這個僅適用於結果集在16MB之內的狀況。另外一個選擇是將結果放到一個集合裏,則out參數則是字符串,即集合的名稱。

  • finalize:一個JavaScript函數,在reduce階段完成後會應用於每一個返回的文檔上。

  • scope:該文檔指定了map、reduce和finalize函數可全局訪問的變量的值。

  • verbose:一個布爾值,爲true時,在命令返回文檔中會包含對map-reduce任務執行時間的統計信息。

注意:在out參數爲存入到新的集合時,會有一個問題:若是最近有運行過相似的map-reduce,那麼可能會覆蓋現有數據。所以,還有兩個集合輸出選項:一個用於合併結果和老數據;另外一個對數據進行reduce處理。合併的場景中,使用{merge:'collectionName'},新結果會覆蓋擁有相同鍵的現有項。若是使用{reduce:'collectionName'},會調用reduce函數根據新值來處理現有的鍵值

相關文章
相關標籤/搜索