2013-04-24 113 views
1

我翻譯瞭如下SQL statment映射減少:MongoDB的減少功能沒有運行

select 
    p_brand, p_type,  p_size, 
    count(ps_suppkey) as supplier_cnt 
from 
    partsupp, part 
where 
    p_partkey = ps_partkey 
    and p_brand <> 'Brand#45' 
    and p_type not like 'MEDIUM POLISHED %' 
    and p_size in (49, 14, 23, 45, 19, 3, 36, 9) 
    and ps_suppkey not in (
      select 
      s_suppkey 
      from 
      supplier 
      where 
      s_comment like '%Customer%Complaints%' 
     ) 
group by 
    p_brand, p_type, p_size 
order by 
    supplier_cnt desc, p_brand, p_type, p_size; 

地圖縮小功能:

db.runCommand({ 
    mapreduce: "partsupp", 
    query: { 
     "ps_partkey.p_size": { $in: [49, 14, 23, 45, 19, 3, 36, 9] }, 
     "ps_partkey.p_brand": { $ne: "Brand#45" } 
    }, 
    map: function() { 
     var pattern1 = /^MEDIUM POLISHED .*/; 
     var pattern2 = /.*Customer.*Complaints.*/; 

     var suppkey = this.ps_suppkey.s_suppkey; 

     if(this.ps_suppkey.s_comment.match(pattern1) == null){ 
      if(this.ps_suppkey.s_comment.match(pattern2) != null){ 
       emit({p_brand: this.ps_partkey.p_brand, p_type: this.ps_partkey.p_type, p_size: this.ps_partkey.p_size}, suppkey); 
      } 
     } 
    }, 
    reduce: function(key, values) { 
     return values.length; 
    }, 
    out: 'query016' 
}); 

輸出結果(在我看來)沒有一個減少:

{ 
     "result" : "query016", 
     "timeMillis" : 46862, 
     "counts" : { 
       "input" : 122272, 
       "emit" : 54, 
       "reduce" : 0, 
       "output" : 54 
     }, 
     "ok" : 1 
} 

怎麼了?

+2

你的reduce函數是不正確的,也可能是你的map函數 - 你必須從第二個參數的縮減格式中返回給你的emit函數。因此,在發出你想要第二個參數爲NUMBER(如1),並減少你需要迭代值並添加它們。此外,你應該使用聚合框架,而不是map-reduce,除非你的結果集預計會很大。 – 2013-04-24 13:20:12

+0

其實this.ps_suppkey.s_suppkey是一個MongoDB NumberLong我想如果這是問題。你認爲Asya怎麼樣? – ulima69 2013-04-24 15:39:48

+0

鍵(發出的第一個參數)可以是任何東西,基本類型,文檔等等。第二個參數可以是任何東西,但無論它的類型如何,它必須與reduce函數發出的相同。你是否認爲你的鑰匙的每個組合只出現一次? – 2013-04-24 18:00:21

回答

1

映射函數輸出鍵和值對。

reduce函數的目的是爲同一個鍵合併多個值。這意味着如果特定的鍵值只有一次只有一個值,並且沒有什麼可以減少的話。

這是您必須以減少函數返回的格式完全相同的格式輸出emit語句中的值的原因之一。

地圖輸出:

emit(key1, valueX); 
emit(key1, valueY); 
emit(key2, valueZ); 

減少結合valueX和VALUE年返回新valueXY爲key1的和最終的結果將是:

key1, valueXY 
key, valueZ 

注意降低從未呼籲KEY2。 Reduce函數可能被稱爲零,每個鍵值一次或多次,因此您必須小心地構建map和reduce函數以允許這種可能性。

您的地圖功能不會發出正確的值 - 您想要計數,因此您必須輸出計數。您的減少功能必須循環使用已經積累的計數並將它們相加並返回組合計數。您可能需要查看MongoDB文檔中提供的一些示例。

您可以使用Aggregation Framework更簡單地做到這一點 - 除非您期望輸出大量結果,否則在這裏看不到MapReduce的必要性。

0

我懷疑你叫emit(value,key)而不是emit(key,value)

正如其他人已經指出的那樣,映射值和縮減值必須具有相同的結構。如果你只是想計算一次,映射一個值= 1,在reduce函數中只返回Array.sum(values)