1

我已将以下 sql 语句翻译为 map reduce:

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
}

怎么了?

4

2 回答 2

1

map 函数输出键值对。

reduce 函数的目的是为同一个键组合多个值。这意味着如果特定键值仅在它只有一个值时才发出,并且没有什么可以减少的。

这是您必须以与 reduce 函数将返回的格式完全相同的格式在 emit 语句中输出值的原因之一。

地图输出:

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

Reduce 结合 valueX 和 valueY 为 key1 返回新的 valueXY ,最终结果将是:

key1, valueXY
key, valueZ

请注意,reduce 从未在 key2 上调用过。对于每个键值,Reduce 函数可能会被调用零次、一次或多次,因此您必须小心地构造 map 和 reduce 函数以允许这种可能性。

您的 map 函数没有发出正确的值 - 您想要进行计数,因此您必须输出一个count。您的 reduce 函数必须遍历已经累积的计数并将它们相加并返回组合计数。您可能想查看 MongoDB 文档中提供的一些示例。

您可能可以使用聚合框架更简单地执行此操作 - 我认为此处不需要 MapReduce,除非您期望输出大量结果。

于 2013-04-25T03:45:33.200 回答
0

我怀疑你打电话emit(value,key)而不是emit(key,value).

正如其他人已经说过的,映射值和缩减值必须具有相同的结构。如果您只想进行计数,请映射 value=1 并在 reduce 函数中 return Array.sum(values)

于 2014-06-23T19:19:37.137 回答