डेटाबेस पर स्ट्रिंग्स / रिकॉर्ड की एक बहुत बड़ी सूची के माध्यम से जल्दी से खोज कैसे करें


32

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

इसे और अधिक ठोस बनाने के लिए: मेरे आवेदन के जीयूआई में मेरे पास एक टेक्स्ट फ़ील्ड है जहां मैं एक स्ट्रिंग दर्ज कर सकता हूं। पाठ फ़ील्ड के ऊपर मेरे पास (पहली N, उदा 100) रिकॉर्ड प्रदर्शित करने वाली एक तालिका है जो पाठ क्षेत्र में स्ट्रिंग से मेल खाती है। जब मैं टेक्स्ट फ़ील्ड में एक वर्ण को टाइप या डिलीट करता हूं, तो तालिका सामग्री को फ्लाई पर अपडेट किया जाना चाहिए।

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

मुझे लगता है कि मुख्य समस्या यह है कि पैटर्न स्ट्रिंग को देखते हुए मिलान वाले आइटम को जल्दी से कैसे खोजें। क्या मैं कुछ डीबीएमएस सुविधाओं पर भरोसा कर सकता हूं, या क्या मुझे खुद में कुछ इन-मेमोरी इंडेक्स बनाने होंगे? कोई विचार?

संपादित करें

मैंने पहला प्रयोग किया है। मैंने रिकॉर्ड्स को अलग-अलग पाठ फ़ाइलों (प्रति फ़ाइल 200 से अधिक रिकॉर्ड) में विभाजित किया है और फ़ाइलों को अलग-अलग निर्देशिकाओं में डाल दिया है (मैंने निर्देशिका पेड़ का निर्धारण करने के लिए एक डेटा फ़ील्ड की सामग्री का उपयोग किया है)। मैं लगभग 40000 निर्देशिकाओं में लगभग 50000 फाइलों के साथ अंत करता हूं। मैंने फ़ाइलों को अनुक्रमित करने के लिए ल्यूसिन को चलाया है। Lucene डेमो प्रोग्राम के साथ एक स्ट्रिंग के लिए खोज बहुत तेज है। बंटवारे और अनुक्रमण में कुछ मिनट लगे: यह मेरे लिए पूरी तरह स्वीकार्य है क्योंकि यह एक स्थिर डेटा सेट है जिसे मैं क्वेरी करना चाहता हूं।

अगला कदम ल्यूसीन को मुख्य कार्यक्रम में एकीकृत करना है और प्रासंगिक रिकॉर्ड को मुख्य मेमोरी में लोड करने के लिए ल्यूसीन द्वारा लौटाए गए हिट का उपयोग करना है।


2
2 मिलियन रिकॉर्ड * 500 बाइट्स = 1 जीबी डेटा। यह एक है बहुत खोज करने के लिए डेटा की, जो भी तरीका आप इसके बारे में जाना - है एक्स के प्रत्येक मान संभावना अद्वितीय होना, या आप एक्स का एक ही मूल्य के साथ कई रिकॉर्ड करना होगा?

1
यह भी त्वरित पुनर्प्राप्ति के लिए कैश के रूप में मेमोरी में स्टोर करने का प्रयास करने के लिए बहुत अधिक डेटा होगा। यह प्रति उपयोगकर्ता सत्र 1GB से अधिक के बराबर होगा।
maple_shaft

मेरी पिछली टिप्पणी एक वेब एप्लिकेशन मानती है। यह एक वेब अनुप्रयोग है?
maple_shaft

यह एक डेस्कटॉप एप्लिकेशन है। अभिलेखों में मान आवश्यक नहीं है कि वे अद्वितीय हों। इसके अलावा, मैं एक सटीक मैच के लिए नहीं विकल्प के लिए खोज रहा हूँ।
जियोर्जियो

@maple_shaft: मैं केवल उन रिकॉर्ड्स को कैश करूंगा जिन्हें मैंने हाल ही में एक्सेस किया है। यदि मैं क्वेरी स्ट्रिंग और रिकॉर्ड अभी भी मेल खाता हूं, तो यह अभी भी कैश में है।
जियोर्जियो

जवाबों:


20

अपने डेटा को DB के अंदर रखने के बजाय, आप उन्हें अलग-अलग दस्तावेज़ों (पाठ फ़ाइलों) के एक सेट के रूप में रख सकते हैं और लिंक (पथ / यूआरएल आदि) को DB में रख सकते हैं।

यह आवश्यक है क्योंकि, डिज़ाइन द्वारा SQL क्वेरी उप-स्ट्रिंग खोज के साथ-साथ पुनर्प्राप्ति दोनों में बहुत धीमी होगी।

अब, आपकी समस्या के रूप में तैयार की गई है, जिसमें उन पाठ फ़ाइलों को खोजना है जिनमें स्ट्रिंग्स का सेट शामिल है। यहां दो संभावनाएं हैं।

  1. उप-स्ट्रिंग मिलान यदि आपका पाठ एक एकल स्टिंग या शब्द है (बिना किसी श्वेत स्थान के) और आपको इसके भीतर मनमाने उप-स्ट्रिंग की खोज करने की आवश्यकता है। ऐसे मामलों में आपको मेल करने वाली सर्वोत्तम संभावित फ़ाइलों को खोजने के लिए हर फ़ाइल को पार्स करने की आवश्यकता होती है। बॉयर मूर एल्गोरिथम जैसे एल्गोरिदम का उपयोग करता है। देखें इस और इस जानकारी के लिए। यह भी grep के बराबर है - क्योंकि grep अंदर समान सामान का उपयोग करता है। लेकिन आप लौटने से पहले कम से कम 100+ grep (सबसे खराब स्थिति 2 मिलियन) बना सकते हैं।

  2. अनुक्रमित खोज। यहां आप यह मान रहे हैं कि पाठ में शब्दों का सेट है और खोज निश्चित शब्द लंबाई तक सीमित है। इस मामले में, दस्तावेज़ को शब्दों की सभी संभावित घटनाओं पर अनुक्रमित किया जाता है। इसे अक्सर "पूर्ण पाठ खोज" कहा जाता है। ऐसा करने के लिए एल्गोरिदम की संख्या और खुले स्रोत परियोजनाओं की संख्या है जो सीधे उपयोग किए जा सकते हैं। उनमें से कई, नीचे के रूप में वाइल्ड कार्ड खोज, अनुमानित खोज आदि का भी समर्थन करते हैं:
    ए। Apache Lucene: http://lucene.apache.org/java/docs/index.html
    b। OpenFTS: http://openfts.sourceforge.net/
    सी। स्फिंक्स http://sphinxsearch.com/

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


2
यह एक दिलचस्प अवधारणा है, लेकिन ऐसा लगता नहीं है कि एक डेवलपर आसानी से एक डेटाबेस इंजन की तुलना में 1GB पाठ डेटा तेजी से और अधिक कुशलता से खोज सकता है। आप और मैं की तुलना में बहुत अधिक होशियार लोग क्वेरी ऑप्टिमाइज़र पर बस ऐसा करने के लिए तैयार हो गए हैं और यह सोचना थोड़ा भोला है कि आप किसी भी तरह से अधिक कुशलता से कर सकते हैं।
maple_shaft

4
@maple_shaft मैंने जो उदाहरण दिए हैं, वे आरडीबीएमएस डेटाबेस इंजन नहीं हैं। यदि आप इसे कॉल करना चाहते हैं तो वे "खोज इंजन" की तरह हैं। एक सूचकांक (या हैश टेबल) से बाहर सूची लेने के बीच एक बड़ा वैचारिक अंतर है बनाम हर बार 1GB डेटा के माध्यम से खोज करने पर हर बार एक क्वेरी आग। तो मैं जो सुझाव दे रहा हूं, वह मामूली मोड़ नहीं है।
दीपन मेहता

यह एक दिलचस्प विचार है, लेकिन मुझे आश्चर्य है कि यह कैसे काम करेगा। मेरे पास 2 000 000 से अधिक फाइलें होंगी, प्रत्येक का आकार लगभग आधा किलोबाइट होगा। या क्या आप प्रति फ़ाइल एक से अधिक रिकॉर्ड रखने का सुझाव दे रहे हैं? क्या एक डेटाबेस wrt अंतर होगा?
जियोर्जियो

मुझे विश्वास नहीं हो रहा है कि यह एसक्यूएल फुलटेक्स इंडेक्स की तुलना में आवश्यक रूप से बेहतर प्रदर्शन करेगा।
कर्क ब्रॉडहर्स्ट

@ जियोर्जियो - हाँ है कि पूर्ण पाठ खोज इंजन कैसे काम करेगा। यहां मुख्य अंतर एक पूर्व-अनुक्रमित पृष्ठ बनाम मेमोरी सर्च में है (फिर हर बार जब कोई क्वेरी आती है)।
दीपन मेहता

21

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


1
मेरी राय में किसी भी आरडीबीएमएस में फुलटेक्स्ट ऑप्शंस एक वर्कअराउंड है, इसे ऐसा करने के लिए जिसे इसके लिए डिज़ाइन नहीं किया गया है: "असंरचित असंबंधित डेटा के कुछ ढेर में खोज"। यदि आप एक खोज का निर्माण कर रहे हैं, तो आप बस एक RDBMS का उपयोग नहीं करते हैं। यह छोटे डेटासेट के लिए काम कर सकता है लेकिन किसी भी प्रकार के स्केलिंग को कम करता है। असंरचित डेटा के ढेर के माध्यम से खोज करना एक कील नहीं है, इसलिए एक हथौड़ा का उपयोग न करें। इस काम के लिए सही उपकरण का उपयोग करें।
पीटर बी

8

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


1
हाँ! मैं एक पेड़ की संरचना के बारे में सोच रहा था और मुझे याद आया कि ऐसा ही कुछ था जो मुझे सूट कर सकता था, लेकिन मुझे ट्राइ का याद नहीं था क्योंकि मैंने कभी उनका इस्तेमाल नहीं किया। भंडारण की आवश्यकता के बारे में: याद रखें कि मुझे केवल पहली एन प्रविष्टियाँ प्राप्त करने की आवश्यकता है (जैसे एन = 100) क्योंकि यह 20000 हिट वाली तालिका को आबाद करने का कोई मतलब नहीं है। इसलिए तीनों का प्रत्येक नोड अधिकांश एन प्रविष्टियों पर इंगित करेगा। इसके अलावा, मैं यह उल्लेख करना भूल गया कि मुझे तेज़ पहुँच की आवश्यकता है लेकिन मुझे तेज़ अद्यतन की आवश्यकता नहीं है, क्योंकि डेटा केवल एक बार लोड किया गया है। एक अनुमत सूचकांक पर तीनों विचार वास्तव में काम कर सकते हैं!
जियोर्जियो

1
अच्छा जवाब लेकिन जैसा कि आप ध्यान दें, आपके शब्दों की शुरुआत के मिलान के लिए एक ट्राइ बहुत बढ़िया है लेकिन किसी भी विकल्प से मेल खाने पर जल्दी जटिल और बहुत बड़ा हो जाएगा ...
Kirk Broadhurst

पहले प्रयोग के रूप में, मैंने उन सभी उप-स्ट्रिंग्स के सेट का निर्माण करने की कोशिश की है जो मुझे उन स्ट्रिंग्स में दिखाई देते हैं जिन्हें मुझे खोजना होगा, अगर मैं सही तरीके से समझता हूं, तो ट्राइ के रास्तों के अनुरूप है। मुझे लंबाई 6. के उप-स्ट्रिंग्स में मेमोरी आउट ऑफ (जेवीएम के लिए 256 मीटर के साथ) एक अपवाद मिला। इसलिए मुझे डर है कि यह समाधान संभव नहीं है, जब तक कि मैं कुछ गलत नहीं कर रहा हूं।
जियोर्जियो

5

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

एक विकल्प इन अभिलेखों के विशिष्ट पहचानकर्ताओं को इकट्ठा करना है जिन्हें आप विशिष्ट रूप से क्वेरी से पुनर्प्राप्त नहीं करना चाहते हैं और उन्हें शामिल करना चाहते हैं, संभवतः एक NOT INया एक में NOT EXISTS

हालाँकि, सावधानी का शब्द सस्ता NOT INया NOT EXISTSसस्ता नहीं है और आपके डेटाबेस के उपयोग के आधार पर आपके क्वेरी प्रदर्शन या क्वेरी योजना को नकारात्मक रूप से प्रभावित करता है। अपनी अंतिम क्वेरी पर एक व्याख्या योजना चलाएं ताकि यह सुनिश्चित हो सके कि प्रभावित कॉलम पर आपके सभी अनुक्रमित उपयोग किए जा रहे हैं।

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


Maple_shaft और @Wyatt Barnett: सुझावों के लिए बहुत बहुत धन्यवाद। मुझे कुछ पढ़ना होगा और अलग-अलग समाधान आज़माने होंगे। सभी डेटाबेस पूर्ण अनुक्रमण का समर्थन नहीं करते हैं, MySQL (जो मैं वर्तमान में उपयोग कर रहा हूं) करता है ( dev.mysql.com/doc/refman/5.5/en/fulltext-search.html )। मैं कुछ परीक्षण करने की कोशिश करूंगा और फिर यहां रिपोर्ट करूंगा।
जियोर्जियो

2

यदि आपसे छुट गया। यदि आप इन-डीबी समर्थित टेक्स्ट खोज के बजाय अपने डेटाबेस के लिए ल्यूसिन का उपयोग करते हैं, तो आपको अपने डीबी में संशोधन करते समय बेहद सावधानी बरतनी होगी। जब आप DB और बाहरी संसाधनों (Lucene) दोनों में बदलाव करना चाहते हैं, तो आप यह कैसे सुनिश्चित कर सकते हैं कि आपके पास परमाणु हो सकता है? हां यह किया जा सकता है, लेकिन बहुत काम होगा।

यदि आप अपने डेटा स्कीमा में ल्यूसीन डालते हैं, तो संक्षेप में, आप DB लेन-देन का समर्थन खो रहे हैं।


1
जैसा कि कहा गया है कि समस्या किसी भी तरह एक RDMS के लिए एक अच्छा फिट नहीं है।
पीटर बी

1

क्या आपने स्फिंक्स को माना है? http://sphinxsearch.com यदि आप एक 3 पार्टी टूल का उपयोग कर सकते हैं तो यह आदर्श होगा कि आप क्या हासिल करने की कोशिश कर रहे हैं, किसी भी RDBMS की तुलना में पूर्ण पाठ खोज में यह अधिक कुशल है जो मैंने व्यक्तिगत रूप से उपयोग किया है।


3
और नीचे वोट के लिए है?
टहनी

1

यह कुछ हद तक अजीब है कि कोई भी उत्तर "उल्टे सूचकांक" शब्द को प्रस्तुत नहीं करता है , तकनीक अपाचे ल्यूसिन और अन्य के समान सभी समाधानों को अंतर्निहित करती है।

उल्टे सूचकांक शब्दों से दस्तावेज़ों ("रिकॉर्ड-स्तर उल्टे सूचकांक") या दस्तावेज़ के भीतर सटीक शब्द स्थानों ("शब्द-स्तर उल्टे सूचकांक") के लिए एक मानचित्रण है।

लागू करने के लिए और या तार्किक संचालन तुच्छ हैं। यदि आपके पास सटीक शब्द स्थान हैं, तो आसन्न शब्दों की तलाश करना संभव है, इस प्रकार वाक्यांश खोज संभव है।

तो, एक इंडेक्स युक्त (शब्द, फ़ाइल, स्थान) ट्यूपल्स के बारे में सोचें। जब आप उदाहरण के लिए ("उलटा", "foo.txt", 123) तो आप बस यह जांचें कि क्या ("सूचकांक", "foo.txt", 124) पूर्ण वाक्यांश "उल्टे सूचकांक" की खोज करने के लिए सूचकांक का हिस्सा है " ।

जबकि मैं आपको स्क्रैच से पूर्ण-पाठ खोज इंजन को फिर से लागू करने की अनुशंसा नहीं कर रहा हूं, यह जानना उपयोगी है कि अपाचे ल्यूसिन जैसी तकनीकें कैसे काम करती हैं।

इसलिए, मेरी सिफारिश यह सीखने की है कि कैसे उल्टे सूचकांक काम करते हैं और अपाचे ल्यूसिन जैसी तकनीक का उपयोग करके उन्हें चुनते हैं। तब आपको कम से कम इस बात की ठोस समझ होनी चाहिए कि क्या किया जा सकता है और क्या नहीं किया जा सकता है।

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