MongoDB एक अनुक्रमित कॉलम पर गिनती (अलग x) का चयन करें - बड़े डेटा सेट के लिए अद्वितीय परिणाम गिनें


82

मैं कई लेखों और उदाहरणों से गुज़रा हूँ, और अभी तक MongoDB में इस SQL ​​क्वेरी को करने के लिए एक कुशल तरीका खोजना है (जहाँ लाखों लोग हैं पंक्तियों दस्तावेज)

पहली कोशिश

(इस लगभग डुप्लिकेट प्रश्न से - एसक्यूएल की चयन सूची के मानगो बराबर? )

db.myCollection.distinct("myIndexedNonUniqueField").length

जाहिर है मुझे यह त्रुटि मिली क्योंकि मेरा डेटासेट बहुत बड़ा है

Thu Aug 02 12:55:24 uncaught exception: distinct failed: {
        "errmsg" : "exception: distinct too big, 16mb cap",
        "code" : 10044,
        "ok" : 0
}

दूसरा प्रयास

मैंने एक समूह बनाने की कोशिश की

db.myCollection.group({key: {myIndexedNonUniqueField: 1},
                initial: {count: 0}, 
                 reduce: function (obj, prev) { prev.count++;} } );

लेकिन मुझे इसके बजाय यह त्रुटि संदेश मिला:

exception: group() can't handle more than 20000 unique keys

तीसरा प्रयास

मैंने अभी तक कोशिश नहीं की है लेकिन इसमें कई सुझाव हैं mapReduce

जैसे

भी

ऐसा लगता है कि GitHub पर एक पुल अनुरोध है, जिसका .distinctउल्लेख करने के लिए विधि को ठीक करना चाहिए केवल एक गिनती वापस करनी चाहिए, लेकिन यह अभी भी खुला है: https://github.com/mongodb/mongo/pull/34

लेकिन इस बिंदु पर मैंने सोचा कि यह यहाँ पूछने लायक है, इस विषय पर नवीनतम क्या है? क्या मुझे अलग-अलग काउंट के लिए SQL या किसी अन्य NoSQL DB में जाना चाहिए? या एक कुशल तरीका है?

अपडेट करें:

MongoDB आधिकारिक डॉक्स पर यह टिप्पणी उत्साहजनक नहीं है, क्या यह सटीक है?

http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808

Update2:

लगता है कि नई एग्रीगेशन फ्रेमवर्क उपरोक्त टिप्पणी का उत्तर देती है ... (मोंगोडो 2.1 / 2.2 और ऊपर, विकास पूर्वावलोकन उपलब्ध है, उत्पादन के लिए नहीं)

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


मुझे लगता है कि आपको बार-बार ऐसा करने की ज़रूरत है या प्रदर्शन इतना मायने नहीं रखेगा। उस मामले में मैं एक अलग संग्रह में अलग-अलग मूल्यों को संग्रहीत करूँगा जो उस समय अपडेट किए जाते हैं जब आप एक बड़े संग्रह में एक अलग करने की कोशिश करने के बजाय एक नया दस्तावेज़ सम्मिलित करते हैं। या तो मैं या मोंगोदब के अपने उपयोग का पुनर्मूल्यांकन करूंगा और संभवत: कुछ और करूंगा। जैसा कि आपने पाया, MongoDb वर्तमान में आप क्या करने की कोशिश कर रहे हैं पर अच्छा नहीं है।
टिम गॉटिएर

@TimGautier धन्यवाद, मुझे डर था, इसलिए उन सभी मूल्यों को सम्मिलित करने में घंटों लग गए, और मुझे इससे पहले सोचना चाहिए था :) मुझे लगता है कि मैं अब उन आंकड़ों के लिए MySQL में सम्मिलित करने के लिए समय
बिताऊंगा

आप एक वृद्धिशील एमआर भी कर सकते हैं जो मूल रूप से कुल डेटा के डेल्टा इंडेक्सिंग का अनुकरण करता है। मेरा मतलब है कि यह इस बात पर निर्भर करता है कि आपको परिणामों का क्या उपयोग करना है। मैं सोच सकता हूं कि MySQL को बहुत अधिक आईओ मिलेगा और ऐसा करने से क्या नहीं (मैं एक इंडेक्स पर सिर्फ 100k डॉक्स इनलाइन को अलग करने के साथ एक छोटे सर्वर को मार सकता हूं) लेकिन मुझे लगता है कि यह इस तरह के सामान के लिए क्वेरी करने में अधिक लचीला है ।
शामेय अगे

मैं इस बात से असहमत हूं कि इस तरह की बात मोंगो को अच्छी नहीं लगती। इस तरह अगर बात यह है कि क्या मोंगो excels पर।
Superluminary

1
दुर्भाग्य से मॉडरेटर ने मेरा उत्तर हटा दिया कि मैंने डुप्लिकेट प्रश्न पर भी पोस्ट किया है। मैं इसे वहां नहीं हटा सकता हूं और इस प्रकार यहां पर लिंक कर सकता हूं: stackoverflow.com/a/33418582/226895
विशेषज्ञ

जवाबों:


75

1) ऐसा करने का सबसे आसान तरीका एकत्रीकरण ढांचे के माध्यम से है। यह दो "$ समूह" कमांड लेता है: अलग-अलग मूल्यों द्वारा पहला एक समूह, दूसरा वाला सभी अलग-अलग मूल्यों को गिनता है

pipeline = [ 
    { $group: { _id: "$myIndexedNonUniqueField"}  },
    { $group: { _id: 1, count: { $sum: 1 } } }
];

//
// Run the aggregation command
//
R = db.runCommand( 
    {
    "aggregate": "myCollection" , 
    "pipeline": pipeline
    }
);
printjson(R);

2) यदि आप मानचित्र के साथ ऐसा करना चाहते हैं / कम कर सकते हैं। यह भी दो-चरण की प्रक्रिया है: पहले चरण में हम कुंजी के लिए हर अलग मूल्य की एक सूची के साथ एक नया संग्रह बनाते हैं। दूसरे में हम नए संग्रह पर एक गिनती () करते हैं।

var SOURCE = db.myCollection;
var DEST = db.distinct
DEST.drop();


map = function() {
  emit( this.myIndexedNonUniqueField , {count: 1});
}

reduce = function(key, values) {
  var count = 0;

  values.forEach(function(v) {
    count += v['count'];        // count each distinct value for lagniappe
  });

  return {count: count};
};

//
// run map/reduce
//
res = SOURCE.mapReduce( map, reduce, 
    { out: 'distinct', 
     verbose: true
    }
    );

print( "distinct count= " + res.counts.output );
print( "distinct count=", DEST.count() );

ध्यान दें कि आप नक्शे के परिणाम को वापस नहीं कर सकते हैं / इनलाइन को कम कर सकते हैं, क्योंकि यह संभावित रूप से 16MB दस्तावेज़ आकार सीमा को पार कर जाएगा। आप एक संग्रह में गणना को सहेज सकते हैं और फिर संग्रह के आकार () को गिन सकते हैं, या आप mapReduce के रिटर्न मान से परिणाम की संख्या प्राप्त कर सकते हैं ()।


5
मैंने Mongo 2.2 RC0 डाउनलोड किया, और आपके 1 सुझाव का उपयोग किया, और यह काम करता है! और तेज! शुक्रिया (अच्छी तरह से किया गया 10gen ...) यहाँ एक जिस्ट बनाया गया (शॉर्टकट एग्रीगेट कमांड का इस्तेमाल किया और इसे एक लाइन में रखा) gist.github.com/3241616
Eran Medan

@EranMedan मुझे आपको चेतावनी देनी चाहिए, हालांकि, मैंने एकत्रीकरण की रूपरेखा का सुझाव नहीं दिया क्योंकि 2.2 rc0 अभी भी पूर्ण तैनाती के लिए वास्तव में तैयार नहीं है, बस कुछ को ध्यान में रखने के लिए, मैं एकत्रीकरण की तैनाती की सिफारिश करने से पहले 2.2 की पूर्ण रिलीज तक इंतजार करूंगा। ढांचा।
शामेय

@Sammaye हाँ, धन्यवाद मैं इसके बारे में जानता हूँ, अभी तक उत्पादन में नहीं जाऊँगा, मुझे आंतरिक आँकड़ों के लिए इसकी आवश्यकता है और यदि संभव हो तो एसक्यूएल के लिए डेटा से बचना चाहता था (और मेरी जिज्ञासा को शांत करना)
एरन मेडन

मानगो क्यों स्वीकार नहीं करेगा: यह .plugins.X-Powered-By.string? मैं इससे कैसे बचूंगा?
अर्लीपोस्टर

मैं सोच रहा हूँ कि क्या यह जवाब एक तेज वातावरण के लिए विश्वसनीय है। जैसा कि मैं इसे समझता हूं, शार्क प्रत्येक अपना एकत्रीकरण करेगी और फिर परिणाम लौटाएगी जहां परिणाम फिर से एकत्र किए जाएंगे। तो इस परिदृश्य में, क्या हमें डुप्लिकेट के लिए मौजूद होने का अवसर नहीं मिलेगा क्योंकि अलग-अलग मूल्य दूसरे $groupस्टेटमेंट में खो गए हैं इससे पहले कि मोंगोस को पारित किया जाए?
वेरन

37
db.myCollection.aggregate( 
   {$group : {_id : "$myIndexedNonUniqueField"} }, 
   {$group: {_id:1, count: {$sum : 1 }}});

परिणाम के लिए सीधे:

db.myCollection.aggregate( 
   {$group : {_id : "$myIndexedNonUniqueField"} }, 
   {$group: {_id:1, count: {$sum : 1 }}})
   .result[0].count;

1
सही है, यह बेहतर है। लेकिन क्या यह वही जवाब नहीं है जो विलियम ने पहले ही प्रदान किया था?
जॉनीएचके

2
इसी तरह, लेकिन मुझे यह पसंद है कि यह एक पंक्ति में है। हालांकि मुझे एक त्रुटि मिली: "अपरिभाषित की संपत्ति '0' को नहीं पढ़ा जा सकता है" अंतिम पंक्ति को हटा दें और यह खूबसूरती से काम करता है।
निको

और अगर हम वास्तव में विशाल डेटाबेस के बारे में बात करते हैं, तो {allowDiskUse: true} को न भूलें, db.myCollection.aggregate ([{$ group ..}, {$ group:}], {allowDiskUse, true}) का परिणाम देखें। 0] .count;
hi_artem

3

निम्नलिखित समाधान ने मेरे लिए काम किया

db.test.distinct ( 'उपयोगकर्ता'); ["एलेक्स", "इंग्लैंड", "फ्रांस", "ऑस्ट्रेलिया"]

db.countries.distinct ('देश')। लंबाई 4

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.