MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

MongoDB पाठ खोज के लिए केवल मेल खाने वाले फ़ील्ड दिखाएं

इस बारे में लंबे समय तक सोचने के बाद, मुझे लगता है कि आप जो चाहते हैं उसे लागू करना संभव है। हालांकि, यह बहुत बड़े डेटाबेस के लिए उपयुक्त नहीं है और मैंने अभी तक एक वृद्धिशील दृष्टिकोण पर काम नहीं किया है। इसमें स्टेमिंग का अभाव है और स्टॉप शब्दों को मैन्युअल रूप से परिभाषित करना पड़ता है।

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

इसलिए हम निम्नलिखित तीन दस्तावेज़ों के साथ काम करेंगे

{
  "name" : "John F. Kennedy",
  "address" : "Kenson Street 1, 12345 Footown, TX, USA",
  "note" : "loves Kendo and Sushi"
}

और

{
  "name" : "Robert F. Kennedy",
  "address" : "High Street 1, 54321 Bartown, FL, USA",
  "note" : "loves Ethel and cigars"
}

और

{
  "name" : "Robert F. Sushi",
  "address" : "Sushi Street 1, 54321 Bartown, FL, USA",
  "note" : "loves Sushi and more Sushi"
}

textsearch . नामक संग्रह में ।

मानचित्र/कम चरण

हम मूल रूप से यह करते हैं कि हम प्रत्येक शब्द को तीन क्षेत्रों में से एक में संसाधित करेंगे, स्टॉप शब्दों और संख्याओं को हटा देंगे और दस्तावेज़ के _id के साथ प्रत्येक शब्द को सहेज लेंगे। और एक मध्यवर्ती तालिका में घटना का क्षेत्र।

एनोटेट कोड:

db.textsearch.mapReduce(
  function() {

    // We need to save this in a local var as per scoping problems
    var document = this;

    // You need to expand this according to your needs
    var stopwords = ["the","this","and","or"];

    // This denotes the fields which should be processed
    var fields = ["name","address","note"];

    // For each field...
    fields.forEach(

      function(field){

        // ... we split the field into single words...
        var words = (document[field]).split(" ");

        words.forEach(

          function(word){
            // ...and remove unwanted characters.
            // Please note that this regex may well need to be enhanced
            var cleaned = word.replace(/[;,.]/g,"")

            // Next we check...
            if(
              // ...wether the current word is in the stopwords list,...
              (stopwords.indexOf(word)>-1) ||

              // ...is either a float or an integer... 
              !(isNaN(parseInt(cleaned))) ||
              !(isNaN(parseFloat(cleaned))) ||

              // or is only one character.
              cleaned.length < 2
            )
            {
              // In any of those cases, we do not want to have the current word in our list.
              return
            }
              // Otherwise, we want to have the current word processed.
              // Note that we have to use a multikey id and a static field in order
              // to overcome one of MongoDB's mapReduce limitations:
              // it can not have multiple values assigned to a key.
              emit({'word':cleaned,'doc':document._id,'field':field},1)

          }
        )
      }
    )
  },
  function(key,values) {

    // We sum up each occurence of each word
    // in each field in every document...
    return Array.sum(values);
  },
    // ..and write the result to a collection
  {out: "searchtst" }
)

इसे चलाने से संग्रह का निर्माण होगा searchtst . यदि यह पहले से मौजूद है, तो इसकी सभी सामग्री बदल दी जाएगी।

यह कुछ इस तरह दिखेगा:

{ "_id" : { "word" : "Bartown", "doc" : ObjectId("544b9811fd9270c1492f5835"), "field" : "address" }, "value" : 1 }
{ "_id" : { "word" : "Bartown", "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "address" }, "value" : 1 }
{ "_id" : { "word" : "Ethel", "doc" : ObjectId("544b9811fd9270c1492f5835"), "field" : "note" }, "value" : 1 }
{ "_id" : { "word" : "FL", "doc" : ObjectId("544b9811fd9270c1492f5835"), "field" : "address" }, "value" : 1 }
{ "_id" : { "word" : "FL", "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "address" }, "value" : 1 }
{ "_id" : { "word" : "Footown", "doc" : ObjectId("544b7e44fd9270c1492f5834"), "field" : "address" }, "value" : 1 }
[...]
{ "_id" : { "word" : "Sushi", "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "name" }, "value" : 1 }
{ "_id" : { "word" : "Sushi", "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "note" }, "value" : 2 }
[...]

यहाँ कुछ बातें ध्यान देने योग्य हैं। सबसे पहले, एक शब्द में कई आवृत्तियाँ हो सकती हैं, उदाहरण के लिए "FL" के साथ। हालाँकि, यह विभिन्न दस्तावेजों में हो सकता है, जैसा कि यहाँ है। दूसरी ओर, किसी एक दस्तावेज़ के एक ही क्षेत्र में एक शब्द में कई आवृत्तियाँ भी हो सकती हैं। हम इसे बाद में अपने लाभ के लिए उपयोग करेंगे।

दूसरा, हमारे पास सभी क्षेत्र हैं, विशेष रूप से word _id . के लिए मिश्रित अनुक्रमणिका में फ़ील्ड , जो आने वाले प्रश्नों को बहुत तेज़ बनाना चाहिए। हालांकि, इसका मतलब यह भी है कि सूचकांक काफी बड़ा होगा और - जैसा कि सभी सूचकांकों के लिए है - रैम को खा जाता है।

एकत्रीकरण चरण

इसलिए हमने शब्दों की सूची कम कर दी है। अब हम एक (उप) स्ट्रिंग के लिए क्वेरी करते हैं। हमें जो करना है वह स्ट्रिंग से शुरू होने वाले सभी शब्दों को ढूंढना है जो उपयोगकर्ता ने अब तक टाइप किया है, उस स्ट्रिंग से मेल खाने वाले शब्दों की एक सूची लौटा रहा है। ऐसा करने में सक्षम होने के लिए और हमारे लिए उपयुक्त रूप में परिणाम प्राप्त करने के लिए, हम एकत्रीकरण का उपयोग करते हैं।

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

जब उपयोगकर्ता ने S अक्षर टाइप किया हो, तो उस मामले के लिए एनोटेट एकत्रीकरण यहां दिया गया है :

db.searchtst.aggregate(
  // We match case insensitive ("i") as we want to prevent
  // typos to reduce our search results
  { $match:{"_id.word":/^S/i} },
  { $group:{
      // Here is where the magic happens:
      // we create a list of distinct words...
      _id:"$_id.word",
      occurrences:{
        // ...add each occurrence to an array...
        $push:{
          doc:"$_id.doc",
          field:"$_id.field"
        } 
      },
      // ...and add up all occurrences to a score
      // Note that this is optional and might be skipped
      // to speed up things, as we should have a covered query
      // when not accessing $value, though I am not too sure about that
      score:{$sum:"$value"}
    }
  },
  {
    // Optional. See above
    $sort:{_id:-1,score:1}
  }
)

इस क्वेरी का परिणाम कुछ इस तरह दिखता है और यह बहुत ही आत्म-व्याख्यात्मक होना चाहिए:

{
  "_id" : "Sushi",
  "occurences" : [
    { "doc" : ObjectId("544b7e44fd9270c1492f5834"), "field" : "note" },
    { "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "address" },
    { "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "name" },
    { "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "note" }
  ],
  "score" : 5
}
{
  "_id" : "Street",
  "occurences" : [
    { "doc" : ObjectId("544b7e44fd9270c1492f5834"), "field" : "address" },
    { "doc" : ObjectId("544b9811fd9270c1492f5835"), "field" : "address" },
    { "doc" : ObjectId("544bb320fd9270c1492f583c"), "field" : "address" }
  ],
  "score" : 3
}

सुशी के लिए 5 का स्कोर इस तथ्य से आता है कि सुशी शब्द किसी एक दस्तावेज़ के नोट फ़ील्ड में दो बार आता है। यह इरादा व्यवहार है।

हालांकि यह एक गरीब आदमी का समाधान हो सकता है, इसे असंख्य उपयोग के मामलों के लिए अनुकूलित करने की आवश्यकता है और उत्पादन वातावरण में आधे-अधूरे उपयोगी होने के लिए एक वृद्धिशील मानचित्र को लागू करने की आवश्यकता होगी, यह अपेक्षा के अनुरूप काम करता है। एचटीएच।

संपादित करें

बेशक, कोई $match को छोड़ सकता है चरण और एक $out जोड़ें परिणामों को पूर्व-संसाधित करने के लिए एकत्रीकरण चरण में चरण:

db.searchtst.aggregate(
  {
    $group:{
      _id:"$_id.word",
      occurences:{ $push:{doc:"$_id.doc",field:"$_id.field"}},
      score:{$sum:"$value"}
     }
   },{
     $out:"search"
   })

अब, हम परिणामी search . को क्वेरी कर सकते हैं चीजों को गति देने के लिए संग्रह। मूल रूप से आप गति के लिए वास्तविक समय के परिणामों का व्यापार करते हैं।

2 संपादित करें :यदि प्रीप्रोसेसिंग दृष्टिकोण अपनाया जाता है, तो searchtst डिस्क स्थान और - अधिक महत्वपूर्ण - कीमती रैम दोनों को बचाने के लिए एकत्रीकरण समाप्त होने के बाद उदाहरण के संग्रह को हटा दिया जाना चाहिए।




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. नोडज पेजिनेशन

  2. नेवला अलग और दस्तावेजों के साथ आबाद

  3. Mongodb का उपयोग करके गैर-संबंधपरक डेटाबेस के साथ शुरुआत करना

  4. MongoDB दिनांक () विधि

  5. मोंगोडीबी गिनती कमांड