2012-04-16 9 views
5

(1) मैं एक संग्रह में जोड़ा निम्नलिखित हैं:

{ "_id" : 1, "hitsPerOneSecond" : [ 2, 3, 5, 4, 1, 2, 3, 4, 1, 2 ], "startTime" : ISODate("2012-04-07T10:41:33.380Z"), "returnCodeHits" : { "300" : 5, "200" : 12 }, "xxxServer" : "xxx:8100", "statsSummarizedToSeconds" : 10, "pathStats_xxx_api_get_version" : [ 0.2280779683225852, 0.030849283020361273, 0.9947690473370484 ], "pathStats_xxx_api_get_response" : [ 1.2163705612407407, 1.0602539963494662, 1.4853219936411421 ], "type" : "xxxType", "startTimeStr" : "07-04-2012:10AM" } 

{ "_id" : 2, "hitsPerOneSecond" : [ 2, 3, 5, 4, 1, 2, 3, 4, 1, 2 ], "startTime" : ISODate("2012-04-07T10:41:43.380Z"), "returnCodeHits" : { "300" : 5, "200" : 12 }, "xxxServer" : "xxx:8100", "statsSummarizedToSeconds" : 10, "pathStats_xxx_api_get_version" : [ 0.2280779683225852, 0.030849283020361273, 0.9947690473370484 ], "pathStats_xxx_api_get_response" : [ 1.2163705612407407, 1.0602539963494662, 1.4853219936411421 ], "type" : "xxxType", "startTimeStr" : "07-04-2012:10AM" } 

(2) जब निम्नलिखित समूहन प्रदर्शन:

db.newStats.aggregate({$unwind: "$hitsPerOneSecond"},{$group:{_id:"$startTimeStr", totalHits: {$sum: "$hitsPerOneSecond"}, totalHitsCount: {$sum: 1}, avgHit: {$avg: "$hitsPerOneSecond"}, minHit: {$min:"$hitsPerOneSecond"}, maxHit:{$max: "$hitsPerOneSecond"}}}); 

(3) परिणाम बाहर सही ढंग से आते हैं:

{ 
"result" : [ 
    { 
     "_id" : "07-04-2012:10AM", 
     "totalHits" : 54, 
     "totalHitsCount" : 20, 
     "avgHit" : 2.7, 
     "minHit" : 1, 
     "maxHit" : 5 
    } 
], 
"ok" : 1 

}

(4) हालांकि, मुझे उपरोक्त एक ही समेकन में 'pathStats_xxx_api_get_response' (संग्रह से) पर एक अनदेखा करने की आवश्यकता है ताकि मेरे ऊपर कुल परिणाम, कुल रिस्पॉन्स काउंटर, औसत रेसपॉन्स, मिनी रेस्पॉन्स और अधिकतम रिस्पॉन्स आउटपुट हो सकें।

सुनिश्चित नहीं हैं कि वास्तव में अधिक $ जोड़ने का तरीका एक ही एकत्रीकरण में तनाव मुक्त हो के रूप में मैं लगभग वहाँ हूँ

{ 
"result" : [ 
    { 
     "_id" : "07-04-2012:10AM", 
     "totalHits" : 54, 
     "totalHitsCount" : 20, 
     "avgHit" : 2.7, 
     "minHit" : 1, 
     "maxHit" : 5, 
        "totalResponses" : ?? 
        "totalResponsesCount": ?? 
     "avgResponse" : 2.7, 
     "minResponse" : 1, 
     "maxResponse" : 5 
    } 
], 
"ok" : 1 

}: इसलिए, मेरी परिणाम कुछ इस तरह देखना चाहिए!

उत्तर

2

संभावित रूप से सबसे आसान समाधान दो पृथक एकत्रीकरण संचालन के साथ ऐसा करना है और परिणामों को अपने आवेदन में जोड़ना है।

वैकल्पिक रूप से, आप एक मानचित्र के साथ ऐसा कर आपरेशन को कम कर सकता है:

निम्न मानचित्र और कार्यों के परिणाम आप देख रहे हैं प्रदान करना चाहिए को कम:

var map = function() { 
    var totalHits = this.hitsPerOneSecond.map(function(a,b){return a+b;}); 
    var totalHitsCount = this.hitsPerOneSecond.length; 
    var avgHit = totalHits/totalHitsCount; 
    var minHit = Math.min.apply(Math, this.hitsPerOneSecond); 
    var maxHit = Math.max.apply(Math, this.hitsPerOneSecond); 
    var totalResponses = pathStats_xxx_api_get_response.map(function(a,b){return a+b;}); 
    var totalResponsesCount = this.pathStats_xxx_api_get_response.length; 
    var avgResponse = totalResponses/totalResponsesCount; 
    var minResponse = Math.min.apply(Math, this.pathStats_xxx_api_get_response); 
    var maxResponse = Math.max.apply(Math, this.pathStats_xxx_api_get_response); 
    emit(this.startTimeStr, { 
    "totalHits": totalHits, 
    "totalHitsCount": totalHitsCount, 
    "avgHit": avgHit, 
    "minHit": minHit, 
    "maxHit": maxHit, 
    "totalResponses": totalResponses, 
    "totalResponsesCount": totalResponsesCount, 
    "avgResponse": avgResponse, 
    "maxResponse": maxResponse, 
    "minResponse": minResponse 
    }) 
} 

var reduce = function(key, values) { 
    var output = { 
    "totalHits": 0, 
    "totalHitsCount": 0, 
    "avgHit": 0, 
    "minHit": null, 
    "maxHit": null, 
    "totalResponses": 0, 
    "totalResponsesCount": 0, 
    "avgResponse": 0, 
    "maxResponse": null, 
    "minResponse": null 
    }; 
    values.forEach(function(v) { 
    output.totalHits += v.totalHits; 
    output.totalHitsCount += v.totalHitsCount; 
    output.avgHit = output.totalHits/output.totalHitsCount; 
    if (output.minHit == null) { 
     output.minHit = v.minHit; 
    } else { 
     if (v.minHit < output.minHit) { 
     output.minHit = v.minHit 
     } 
    } 
    if (output.maxHit == null) { 
     output.maxHit = v.maxHit; 
    } else { 
     if (v.maxHit > output.maxHit) { 
     output.maxHit = v.maxHit 
     } 
    } 

    output.totalResponses += v.totalResponses; 
    output.totalResponsesCount += v.totalResponsesCount; 
    output.avgResponse = output.totalResponses/output.totalResponsesCount; 
    if (output.minResponse == null) { 
     output.minResponse = v.minResponse; 
    } else { 
     if (v.minResponse < output.minResponse) { 
     output.minResponse = v.minResponse 
     } 
    } 
    if (output.maxResponse == null) { 
     output.maxResponse = v.maxResponse; 
    } else { 
     if (v.maxResponse > output.maxResponse) { 
     output.maxResponse = v.maxResponse 
     } 
    } 
    }); 
    return output; 
} 

> db.newStats.mapReduce(map, reduce, {out:{inline:1}}) 
{ 
    "results" : [ 
     { 
      "_id" : "07-04-2012:10AM", 
      "value" : { 
       "totalHits" : 54, 
       "totalHitsCount" : 20, 
       "avgHit" : 2.7, 
       "minHit" : 1, 
       "maxHit" : 5, 
       "totalResponses" : 7.523893102462698, 
       "totalResponsesCount" : 6, 
       "avgResponse" : 1.253982183743783, 
       "maxResponse" : 1.4853219936411421, 
       "minResponse" : 1.0602539963494662 
      } 
     } 
    ], 
    "timeMillis" : 0, 
    "counts" : { 
     "input" : 2, 
     "emit" : 2, 
     "reduce" : 1, 
     "output" : 1 
    }, 
    "ok" : 1, 
} 
> 

आप के साथ मानचित्र को कम अपरिचित हैं, प्रलेखन यहां पाया जा सकता है: http://www.mongodb.org/display/DOCS/MapReduce

इसके अतिरिक्त, कुछ अच्छी मानचित्र MongoDB कुकबुक में उदाहरण कम कर रहे हैं: http://cookbook.mongodb.org/

कुकबुक आलेख "" वर्जन किए गए दस्तावेज़ों के साथ अधिकतम और न्यूनतम मान ढूँढना "के" अतिरिक्त "अनुभाग" http://cookbook.mongodb.org/patterns/finding_max_and_min/ में मैप कम करने के ऑपरेशन की एक अच्छी चरण-दर-चरण walkthrough शामिल है, यह बताते हुए कि कार्य कैसे निष्पादित किए जाते हैं।

उम्मीद है कि इससे आपको वांछित परिणाम प्राप्त करने में मदद मिलेगी। यदि आप एकल एकाग्रता संचालन के साथ ऐसा करने का कोई तरीका समझने में सक्षम हैं, तो कृपया अपना समाधान साझा करें, ताकि समुदाय आपके अनुभव का लाभ प्राप्त कर सके। धन्यवाद।

यहाँ मानचित्र पर कुछ नोट कम करने, अपनी टिप्पणी के जवाब में कर रहे हैं:

MapReduce सर्वर पर जावास्क्रिप्ट निष्पादित करता है। नतीजतन, आप पाते हैं कि प्रदर्शन अन्य परिचालनों के लिए पीड़ित है। नक्शा कम करना एक बार में एक-दूसरे के लिए अच्छा होता है जो एक समय में किया जा सकता है जब सर्वर अपने चरम यातायात पर नहीं होता है। आप पाते हैं कि बड़े संग्रह से ऑन-द-फ्लाई आंकड़ों के लिए मानचित्र कम करने का उपयोग इष्टतम नहीं है।

दूसरी ओर, समेकन ढांचा देशी कोड पर निर्भर करता है और सर्वर की तरफ जावास्क्रिप्ट निष्पादित नहीं करता है, जिससे इसे मानचित्र कम करने से तेज़ बना दिया जाता है।

यदि संभव हो, तो सबसे अच्छा विकल्प प्रत्येक दस्तावेज़ में फ़ील्ड जोड़ने के लिए है जिस पर पूछताछ की जा सकती है।यह प्रत्येक डालने या अपडेट करने के लिए थोड़ा अतिरिक्त ओवरहेड जोड़ता है, लेकिन यदि नक्शा कम करने के ऑपरेशन से बचा जा सकता है तो परिणाम अधिक तेज़ी से वापस आ जाएंगे। दुर्भाग्य से, यह अधिकतम और न्यूनतम मूल्यों और औसत के साथ मुश्किल है।

यदि नक्शा कम करना ऑपरेशन एकमात्र विकल्प है, तो सर्वर पर इसके प्रभाव को कम करने के लिए कुछ चीजें की जा सकती हैं। सबसे पहले, SlaveOk के साथ एक माध्यमिक पर एक नक्शा कम करना संभव है। हालांकि, क्योंकि डेटा को माध्यमिक को नहीं लिखा जा सकता है, इसलिए आउटपुट को इनलाइन वापस कर दिया जाना चाहिए, और इसलिए 16 एमबी तक सीमित है। कुछ उपयोगकर्ता प्रतिलिपि सेट से एक माध्यमिक ले लेंगे, इसे स्टैंड-अलोन मोंगोड प्रक्रिया के रूप में पुनरारंभ करें, उस पर नक्शा-कमांड ऑपरेशन चलाएं, जहां भी इसे जाना है, आउटपुट संग्रह की प्रतिलिपि बनाएँ, और द्वितीयक को रिपिका सेट में फिर से जुड़ें।

एक अंतिम बात पर विचार करना है वृद्धिशील मानचित्र कम करें: http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-IncrementalMapreduce आप मानचित्र के लिए एक क्वेरी आदेश है कि केवल दस्तावेजों कि चूंकि पिछले नक्शे को कम संशोधित किया गया है से मेल खाएगी को कम पारित कर सकते हैं, और नक्शे को चलाने के साथ आपरेशन को कम आउटपुट विकल्प को कम करें।

उम्मीद है कि उपर्युक्त आपको अपने आंकड़ों की गणना करने के सर्वोत्तम तरीके से संबंधित विचार के लिए कुछ भोजन देगा। दस्तावेजों में वांछित जानकारी सहित, बेहतर है, लेकिन यदि यह संभव नहीं है, तो एग्रीगेशन फ्रेमवर्क का उपयोग करके मानचित्र कम करने से अधिक कुशल होगा।

एकत्रीकरण ढांचे डेटाबेस वस्तु की कमान विधि के साथ pymongo में इस्तेमाल किया जा सकता है:

यहाँ दूसरी टिप्पणी के जवाब में, एकत्रीकरण की रूपरेखा और pymongo पर एक नोट है।
आदेश पद्धति पर प्रलेखन यहां पाया जा सकता है: http://api.mongodb.org/python/current/api/pymongo/database.html#pymongo.database.Database.command

एक एकत्रीकरण कार्रवाई करने के लिए, दो कुंजी के साथ आदेश विधि के लिए कोई दस्तावेज़ पारित; "कुल" और "पाइपलाइन"। "कुल" का मान उस संग्रह का नाम है जिस पर ऑपरेशन किया जाएगा, और "पाइपलाइन" का मान निष्पादन संचालन की एक सरणी होगी। पाइपलाइन "एकत्रीकरण की रूपरेखा" दस्तावेज में समझाया गया है:

In [1]: import pymongo 

In [2]: conn = pymongo.Connection() 

In [3]: db = conn.test 

In [4]: result = db.command({"aggregate":"newStats", "pipeline": 
          [{"$unwind": "$hitsPerOneSecond"}, 
          {"$group": {"_id":"$startTimeStr", 
              "totalHits": {"$sum": 
              "$hitsPerOneSecond"}, 
           "totalHitsCount": {"$sum": 1}, 
           "avgHit": {"$avg": "$hitsPerOneSecond"}, 
           "minHit": {"$min":"$hitsPerOneSecond"}, 
           "maxHit":{"$max": "$hitsPerOneSecond"}}}]}) 

In [5]: result 
Out[5]: 
{u'ok': 1.0, 
u'result': [{u'_id': u'07-04-2012:10AM', 
    u'avgHit': 2.7, 
    u'maxHit': 5.0, 
    u'minHit': 1.0, 
    u'totalHits': 54.0, 
    u'totalHitsCount': 20}]} 
+0

यह एक शानदार उदाहरण है। इसके लिए बहुत धन्यवाद। इसके अलावा, दस्तावेजों के लिंक की बहुत सराहना की जाती है।एकत्रीकरण के मामले में - उद्देश्य डैशबोर्ड और पिमोंगो के माध्यम से फ्लाई आंकड़ों पर एकत्र करना था, लेकिन मुझे लगता है कि $ समूह के साथ मानचित्र/कमी और समेकन दोनों अपेक्षाकृत धीमी हो सकती है? मैं एक पाइथन स्क्रिप्ट से 10 सेकंड डेटा आंकड़ों के 60,080 (1 सप्ताह के लायक) को जोड़ना चाहता हूं जो इसे पहले से ही अपाचे लॉग फ़ाइलों से 10 सेकंड आंकड़ों में जोड़ता है। – sam0673

+0

मदद करने में खुशी! मैंने मानचित्र पर कम से कम कुछ नोट्स के साथ अपना उत्तर अपडेट किया है। – Marc

+0

हालांकि एक महत्वपूर्ण सवाल .. आप pbongo के माध्यम से db.newStats.aggregate ({$ unwind: "$ hitsPerOneSecond"} .. आदि कैसे करेंगे, क्योंकि मुझे इसके लिए कोई दस्तावेज नहीं मिल रहा है? – sam0673

13

कैसे करें $unwind एक से अधिक सरणी: http://www.mongodb.org/display/DOCS/Aggregation+Framework#AggregationFramework-Pipelines

का तरीका यहां बताया pymongo में $ खोलना आपरेशन प्रदर्शन कर सकते हैं का एक उदाहरण है? क्या आपने $unwinding कई बार कोशिश की है? :)

db.newStats.aggregate([ 
    {$unwind: "$hitsPerOneSecond"}, 
    {$unwind: "$pathStats_xxx_api_get_response"}, 

    {$group:{ 
     _id:"$startTimeStr", 
     totalHits: {$sum: "$hitsPerOneSecond"}, 
     totalHitsCount: {$sum: 1}, 
     avgHit: {$avg: "$hitsPerOneSecond"}, 
     minHit: {$min:"$hitsPerOneSecond"}, 
     maxHit:{$max: "$hitsPerOneSecond"}, 

     totalResponses: {$sum: "$pathStats_xxx_api_get_response"}, 
     . . . 
    }} 
]); 

याद रखें कि कुल ढांचा एक इनपुट के रूप एक सरणी लेता है (ध्यान दें कि मैं [, ] जोड़ा)। सरणी में आप पाइपलाइन में जितना चाहें उतने कुल कार्यों को जोड़ सकते हैं (उद्धरण वांछित) और किसी भी चरण का आउटपुट अगले इनपुट का इनपुट होगा!

नोट:

मत भूलना कि आप एक मौजूदा नहीं कुंजी पर या एक खाली सरणी आप सभी में कोई दस्तावेज़ के साथ अंत पर $unwind करने की कोशिश करता है, तो! यह 0 द्वारा गुणा करने जैसा है, मुझे लगता है ... तो कई (संभवतः कई) $unwind के साथ, भूतों से निपटने की संभावना बढ़ जाती है: यदि इनमें से कोई भी शामिल सरणी खाली है, तो पूरा दस्तावेज़ खो जाता है और आपको अपने $group में से किसी के लिए कुछ भी नहीं मिलता है एकत्रीकरण ...

संबंधित मुद्दे