2013-07-30 11 views
11

में रेगेक्स स्ट्रिंग खोज को गति दें मैं एक प्राकृतिक भाषा शब्दकोश को लागू करने के लिए मोंगोडीबी का उपयोग करने की कोशिश कर रहा हूं। मेरे पास लेक्सम का संग्रह है, जिनमें से प्रत्येक में उप-दस्तावेज के रूप में कई शब्दफॉर्म हैं। इस तरह क्या एक भी शब्दिम लग रहा है:मोंगोडीबी

{ 
    "_id" : ObjectId("51ecff7ee36f2317c9000000"), 
    "pos" : "N", 
    "lemma" : "skrun", 
    "gloss" : "screw", 
    "wordforms" : [ 
     { 
      "number" : "sg", 
      "surface_form" : "skrun", 
      "phonetic" : "ˈskruːn", 
      "gender" : "m" 
     }, 
     { 
      "number" : "pl", 
      "surface_form" : "skrejjen", 
      "phonetic" : "'skrɛjjɛn", 
      "pattern" : "CCCVCCVC" 
     } 
    ], 
    "source" : "Mayer2013" 
} 

वर्तमान में मैं कुछ 4000 शब्दिम का एक संग्रह है, और इनमें से प्रत्येक औसतन कुछ 1000 wordforms की एक सूची है (करने के लिए विरोध के रूप में बस ऊपर 2)। इसका मतलब है कि संग्रह में मेरे पास 4,000,000 अद्वितीय शब्द रूप हैं, और मुझे उचित समय में उनके माध्यम से खोज करने में सक्षम होना चाहिए।

एक सामान्य क्वेरी इस प्रकार दिखाई देगा:

db.lexemes.find({"wordforms.surface_form":"skrejjen"}) 

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

db.lexemes.find({"wordforms.surface_form":/skrej/}) 

में 5 मिनट से अधिक समय लगता है (जिस बिंदु पर मैंने प्रतीक्षा छोड़ दी)। जैसा कि in this question का उल्लेख किया गया है, इंडेक्स पर रेगेक्स-सर्च खराब माना जाता है। मुझे पता है कि regex खोजों में एंकर को helps a lot जोड़ना है, लेकिन यह मेरी खोज क्षमताओं को भी गंभीर रूप से सीमित करता है। यहां तक ​​कि अगर मैं उस बलिदान को तैयार करने के इच्छुक हूं, तो मैंने देखा है कि प्रतिक्रिया समय अभी भी रेगेक्स के आधार पर बहुत भिन्न हो सकता है। क्वेरी

db.lexemes.find({"wordforms.surface_form":/^s/}) 

पूरा करने के लिए 35s लेता है।

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

db.lexemes.find({"wordforms.surface_form":/skrej/}).hint('_id_') 

को पूरा करने के लिए लगभग 3s लगते हैं।

मेरा सवाल है, क्या मैं इन खोज परिणामों को बेहतर बनाने के लिए कुछ और कर सकता हूं? जैसा कि वे हैं, वे अभी भी थोड़ी धीमी हैं और मैं पहले से ही प्रदर्शन प्राप्त करने की उम्मीद में MySQL में माइग्रेट करने पर विचार कर रहा हूं। लेकिन मैं वास्तव में मोंगो की लचीलापन रखना और आरडीबीएमएस में सभी कठिन सामान्यीकरण से बचना चाहूंगा। कोई सुझाव? क्या आपको लगता है कि डीबी इंजन के बावजूद मैं कुछ धीमेपन में भाग जाऊंगा, इस डेटा डेटा की मात्रा के साथ?

मुझे मोंगो की नई text search सुविधा के बारे में पता है लेकिन इस मामले (टोकनिसेशन और स्टेमिंग) के फायदे मेरे मामले में प्रासंगिक नहीं हैं (मेरी भाषा का उल्लेख नहीं है)। यह स्पष्ट नहीं है कि टेक्स्ट खोज वास्तव में तेजी से रेगेक्स के किसी भी प्रकार का उपयोग करने से अधिक है।

उत्तर

7

जैसा कि डेरिक द्वारा सुझाया गया है, मैंने अपने डेटाबेस में डेटा को दोबारा प्रतिक्रिया दी है कि मेरे पास "लेक्समेस" के तहत उप-दस्तावेज़ों के बजाय संग्रह के रूप में "वर्डफॉर्म" है। परिणाम वास्तव में बेहतर थे! यहां कुछ गति तुलना हैं। hint का उपयोग करने वाला अंतिम उदाहरण जानबूझकर surface_form पर इंडेक्स को बाईपास कर रहा है, जो पुराने स्कीमा में वास्तव में तेज़ था।

पुरानी स्कीमा (original question देख)

Query                Avg. Time 
db.lexemes.find({"wordforms.surface_form":"skrun"})    0s 
db.lexemes.find({"wordforms.surface_form":/^skr/})     1.0s 
db.lexemes.find({"wordforms.surface_form":/skru/})     > 3mins ! 
db.lexemes.find({"wordforms.surface_form":/skru/}).hint('_id_') 2.8s 

नई स्कीमा (Derick's answer देख)

Query                Avg. Time 
db.wordforms.find({"surface_form":"skrun"})      0s 
db.wordforms.find({"surface_form":/^skr/})       0.001s 
db.wordforms.find({"surface_form":/skru/})       1.4s 
db.wordforms.find({"surface_form":/skru/}).hint('_id_')   3.0s 

मेरे लिए यह बहुत अच्छा सबूत है कि एक रिफैक्टर्ड स्कीमा तेज़ी से खोजने होगा है, और अनावश्यक डेटा (या अतिरिक्त अतिरिक्त आवश्यक) के लायक है।

9

एक संभावना उन सभी प्रकारों को स्टोर करना होगा जो आप सोच रहे हैं कि एक सरणी तत्व के रूप में उपयोगी हो सकता है - यह सुनिश्चित नहीं है कि यह संभव हो सकता है या नहीं!

{ 
     "number" : "pl", 
     "surface_form" : "skrejjen", 
     "surface_forms: [ "skrej", "skre" ], 
     "phonetic" : "'skrɛjjɛn", 
     "pattern" : "CCCVCCVC" 
    } 

मैं शायद प्रत्येक शब्द के साथ 1000 शब्द रूपों को स्टोर न करने का सुझाव दूंगा, लेकिन इसे छोटे दस्तावेज़ों के लिए चालू कर दूंगा।छोटे अपने दस्तावेज़ों कर रहे हैं, कम MongoDB प्रत्येक खोज के लिए स्मृति में पढ़ने के लिए होता है (जब तक खोज की स्थिति निश्चित रूप से एक पूर्ण स्कैन की आवश्यकता नहीं है):

{ 
    "word": { 
     "pos" : "N", 
     "lemma" : "skrun", 
     "gloss" : "screw", 
    }, 
    "form" : { 
     "number" : "sg", 
     "surface_form" : "skrun", 
     "phonetic" : "ˈskruːn", 
     "gender" : "m" 
    }, 
    "source" : "Mayer2013" 
} 

{ 
    "word": { 
     "pos" : "N", 
     "lemma" : "skrun", 
     "gloss" : "screw", 
    }, 
    "form" : { 
     "number" : "pl", 
     "surface_form" : "skrejjen", 
     "phonetic" : "'skrɛjjɛn", 
     "pattern" : "CCCVCCVC" 
    }, 
    "source" : "Mayer2013" 
} 

मैं भी शक है कि MySQL होगा यादृच्छिक शब्द रूपों के लिए खोजों के साथ बेहतर प्रदर्शन करना क्योंकि इसे पूर्ण टेबल स्कैन करना होगा जैसे कि मोंगोडीबी होगा। एकमात्र चीज जो मदद कर सकती है वह एक क्वेरी कैश है - लेकिन यह ऐसा कुछ है जिसे आप अपने खोज यूआई/एपीआई में आसानी से अपने आवेदन में बना सकते हैं।

+0

सुझाव के लिए धन्यवाद! यह निश्चित रूप से बहुत सारी अनावश्यक जानकारी प्रस्तुत करता है और समग्र संग्रह को बड़ा कर देगा, हालांकि यदि यह खोज प्रतिक्रिया समय बढ़ाता है तो मैं इसे मान सकता हूं। मैं यह देखने के लिए कुछ परीक्षण चलाऊंगा कि यह मामला है और यहां एक अपडेट पोस्ट करें। –