0

最初は、注文には多くの項目があり、多くの項目にはいつものように 1 つの注文しかないという関係があります。

mongoDB を使用して、次のドキュメントを作成しました。

{
    "_id" : ObjectId("511b7d1b3daee1b1446ecdfe"),
    "l_order" : {
        "_id" : ObjectId("511b7d133daee1b1446eb54d"),
        "o_orderkey" : NumberLong(1),
        "o_totalprice" : 173665.47,
        "o_orderdate" : ISODate("1996-01-02T03:00:00Z"),
        "o_orderpriority" : "5-LOW",
        "o_shippriority" : 0,
    },
    "l_linenumber" : 1,
    "l_shipdate" : ISODate("1996-03-13T03:00:00Z"),
    "l_commitdate" : ISODate("1996-02-12T03:00:00Z"),
    "l_receiptdate" : ISODate("1996-03-22T03:00:00Z"),
}

私の意図は、このSQLクエリを翻訳することです:

select
    o_orderpriority, 
    count(*) as order_count
from 
    orders
where 
    o_orderdate >= date '1993-07-01'
    and o_orderdate < date '1993-07-01' + interval '3' month
    and exists (
        select 
        *
        from 
        lineitem
        where 
        l_orderkey = o_orderkey
        and l_commitdate < l_receiptdate
    )
group by 
    o_orderpriority
order by 
    o_orderpriority;

これには、2 つの mapreduce 関数を使用します。

初め

db.runCommand({
    mapreduce: "lineitem",
    query: {
        "l_order.o_orderdate": {'$gte': new Date("July 01, 1993"), '$lt': new Date("Oct 01, 1993")}
    },
    map:    function Map() {
                if(this.l_commitdate < this.l_receiptdate){
                    emit( this.l_order.o_orderkey, this.l_order.o_orderpriority );
                }   
            },
    out: 'query004a'
});

2番

db.runCommand({
    mapreduce: "query004a",
    map:    function Map() {
                /*Remenbering, the value here will be this.l_order.o_orderpriority from the previous mapreduce function*/
                emit( this.value, 1 );
            },
    reduce: function(key, values) {
                return Array.sum(values);
            },
    out: 'query004b'
});

最初に、日付範囲内にあるドキュメントの断片を分離し、比較を尊重して、重複を避けるために順序キー用にグループ化しました。次に、o_orderpriority と sum をグループ化しました。

驚いたことに、答えは私が予想していたよりも大きかった。しかし、なぜ、どこでこれが起こるのでしょうか?

4

1 に答える 1

0

最初のマップ関数では、キーとして「oderpriority」を使用し、値として「orderkey」を使用する必要があります。これにより、2 番目の mapReduce で必要なキーにセットが削減されます。(reduce 関数を指定する必要があります。指定しないと、mapReduce がエラーを返します)。

したがって、これは次のようになります。

OrderDateMin = new Date("1996-01-01");
OrderDateMax = new Date("1996-04-01");
// first where on oderdate
query = {
    "l_order.o_orderdate": {$gte: OrderDateMin, $lt: OrderDateMax}
}
map1 = function() {
    //second "where" on commitdate < receiptdate
    if ( this.l_commitdate < this.l_receiptdate ) {
        // emit orderpriority as key, "1" as counter
        emit( this.l_order.o_orderpriority, this.l_order.o_orderkey );
    }
};
reduce1 = function(key, values) {
    return 1;
}
db.runCommand({
    mapReduce: "xx",
    query: query,
    map: map1,
    reduce: reduce1,
    out: 'query004a',
})
map2 = function() {
    //_id is ordepriority
    emit( this._id, 1 );
};
reduce2 = function(key, values) {
    // count entries per orderpriority
    count = 0;
    values.forEach( function(value) { count += value; } );
    return count;
}
db.runCommand({
    mapReduce: "query004a",
    map: map2,
    reduce: reduce2,
    out: 'query004b',
})

現在、同じことが 1 つの集約コマンドで実現でき、より高速です (JavaScript ではなく C で実装されています)。

db.xx.aggregate([
    // first "where", this will use an index, if defined
    { $match: { 
        "l_order.o_orderdate": { $gte: OrderDateMin, $lt: OrderDateMax }
    }},
    // reduce to needed fields, create a field for decision of second "where"
    { $project: { 
        "key": "$l_order.o_orderkey",  
        "pri": "$l_order.o_orderpriority",
        okay: { $cond: [ {$lt: ["l_commitdate", "l_receiptdate"]}, 1, 0 ] }
    }},
    // select second where condition matched
    { $match: { "okay": 1 } },
    // group by priority and key
    { $group: { _id: { "pri": "$pri", "key": "$key" } } },
    // group by priority - count entries
    { $group: { _id: "$_id.pri", "count": { $sum: 1 } } },
])

次のようなものが返されます。

{ "result" : [ { "_id" : "5-LOW", "count" : 1 } ], "ok" : 1 }

最後になりましたが、デザインに関する提案:

構造が逆の場合、つまりアイテムの配列として埋め込まれた注文アイテムを持つ「注文」コレクションの方が簡単です。これにより、コレクション全体で注文データが重複することを回避できます。

詳細情報:

http://docs.mongodb.org/manual/reference/command/mapReduce/#mapReduce

http://docs.mongodb.org/manual/reference/aggregation

これは役に立ちますか?

乾杯

ロナルド

于 2013-03-25T04:50:27.190 に答える