2009-11-21 10 views
13

क्या मैं पाठ में मिलान करने वाले शब्दों की खोज करते समय कोर डेटा क्वेरी अनुकूलित कर सकता हूं? (यह प्रश्न एक आईफोन पर कोर एसक्यूएल बनाम कोर डेटा के ज्ञान से संबंधित है।)पूर्ण पाठ खोज के लिए कोर डेटा क्वेरी को अनुकूलित करने के लिए कैसे करें

मैं एक नए (आईफोन) ऐप पर काम कर रहा हूं जो एक वैज्ञानिक डेटाबेस के लिए एक हैंडहेल्ड संदर्भ उपकरण है। मुख्य इंटरफ़ेस एक मानक खोज योग्य तालिका दृश्य है और मैं आपके द्वारा टाइप किए गए प्रतिक्रिया के रूप में उपयोगकर्ता को नए शब्द टाइप करना चाहता हूं। शब्द मिलान पाठ में शब्दों के उपसर्ग होना चाहिए। पाठ 100,000 शब्दों से बना है।

मेरे प्रोटोटाइप में मैंने सीधे एसक्यूएल कोड किया। मैंने मुख्य इकाई के टेक्स्ट फ़ील्ड में प्रत्येक शब्द युक्त एक अलग "शब्द" तालिका बनाई है। मैंने

SELECT id, * FROM textTable 
    JOIN (SELECT DISTINCT textTableId FROM words 
     WHERE word BETWEEN 'foo' AND 'fooz') 
    ON id=textTableId 
LIMIT 50 

की पंक्तियों के साथ शब्दों को सूचीबद्ध किया और प्रदर्शन किया। यह बहुत तेज़ चलता है। एक आईएन का उपयोग करना शायद ही काम करेगा, यानी

SELECT * FROM textTable 
WHERE id IN (SELECT textTableId FROM words 
       WHERE word BETWEEN 'foo' AND 'fooz') 
LIMIT 50 

एलआईटी महत्वपूर्ण है और मुझे परिणाम तुरंत प्रदर्शित करने की अनुमति देता है। मैं उपयोगकर्ता को सूचित करता हूं कि सीमा तक पहुंचने पर प्रदर्शित करने के लिए बहुत सारे लोग हैं। यह kludgy है।

मैंने पिछले कई दिनों में कोर डेटा पर जाने के फायदों पर विचार किया है, लेकिन मुझे स्कीमा, इंडेक्सिंग और एक महत्वपूर्ण क्वेरी के लिए पूछताछ में नियंत्रण की कमी के बारे में चिंता है।

सैद्धांतिक रूप से textField MATCHES '.*\bfoo.*' का एनएसपी्रेडिकेट काम करेगा, लेकिन मुझे यकीन है कि यह धीमा हो जाएगा। इस प्रकार की टेक्स्ट खोज इतनी आम है कि मुझे आश्चर्य है कि सामान्य हमला क्या है? क्या आप ऊपर की तरह एक शब्द इकाई बनायेंगे और "शब्द BEGINSWITH 'foo'" की भविष्यवाणी का उपयोग करेंगे? क्या यह मेरे प्रोटोटाइप के रूप में तेजी से काम करेगा? कोर डेटा स्वचालित रूप से सही इंडेक्स बना देगा? मुझे इंडेक्स के बारे में लगातार स्टोर की सलाह देने का कोई स्पष्ट माध्यम नहीं मिल रहा है।

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

क्या मुझे सावधानी बरतनी चाहिए या आगे बढ़ना चाहिए? ।

उत्तर

10

मैंने एक समाधान समाधान बनाया है। मुझे लगता है कि यह this post जैसा है। मैंने अपने कोर डेटा प्रोजेक्ट में समामेलन स्रोत कोड जोड़ा, फिर एक पूर्ण-पाठ खोज वर्ग बनाया जो प्रबंधित ऑब्जेक्ट सबक्लास नहीं था। एसक्लाइट ढांचे के बजाय एफटीएस कक्षा I #import "sqlite3.h" (स्रोत फ़ाइल) में। एफटीएस वर्ग कोर डेटा लगातार स्टोर की तुलना में एक अलग .sqlite फ़ाइल में सहेजता है।

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

एफटीएस करने के लिए, मैं MATCH एफटीएस वर्ग से पूछताछ करता हूं, पंक्तियों का एक सेट लौटाता हूं। मेरी प्रबंधित ऑब्जेक्ट क्लास में, मैं [NSPredicate predicateWithFormat:@"rowid IN %@", rowids] के साथ संबंधित ऑब्जेक्ट्स के लिए क्वेरी करता हूं। मैं इस तरह से कई सारे रिश्तों को पार करने से बचता हूं।

प्रदर्शन सुधार नाटकीय है। मेरा डेटासेट 142287 पंक्तियां है, जिसमें 1 9 4 एमबी (कोर डेटा) और 92 एमबी (स्टॉपवर्ड्स के साथ एफटीएस हटाया गया है) शामिल है। खोज शब्द आवृत्ति के आधार पर, मेरी खोज निरंतर शर्तों (< 100 हिट) के लिए कई सेकंड से 0.1 सेकंड तक और लगातार शर्तों (> 2000 हिट) के लिए 0.2 सेकंड तक जाती है।

मुझे यकीन है कि मेरे दृष्टिकोण (कोड ब्लोट, संभावित नामस्थान टकराव, कुछ कोर डेटा सुविधाओं का नुकसान) के साथ असंख्य समस्याएं हैं, लेकिन ऐसा लगता है कि यह काम कर रहा है।

2

में गोता

यहाँ इसके बारे में जाने के लिए एक ही रास्ता है: एक कोर डाटा लगातार दुकान

  • उपयोग NSFetchedResultsController में अपने रिकॉर्ड रखो एक परिणाम के अपने Word संस्थाओं पर सेट का प्रबंधन करने के

    1. (कोर एसक्यूएल के साथ डाटा बराबर "शब्द" तालिका)
    2. उपयोग UISearchDisplayController परिणाम वास्तविक समय में सेट पर एक NSPredicate लागू करने के लिए

    एक बार जब आप NSFetchedResultsController के माध्यम से परिणाम सेट कर लेते हैं, तो यह भविष्यवाणी लागू करना काफी आसान है। मेरे अनुभव में यह भी उत्तरदायी होगा।उदाहरण के लिए:

    if ([self.searchBar.text length]) { 
        _predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"(word contains[cd] '%@')", self.searchBar.text]]; 
        [self.fetchedResultsController.fetchRequest setPredicate:_predicate]; 
    } 
    
    NSError *error; 
    if (![self.fetchedResultsController performFetch:&error]) { 
        // handle error... 
    } 
    NSLog(@"filtered results: %@", [self.fetchedResultsController fetchedObjects]); 
    

    परिणाम फिल्टर करेगा मक्खी पर [self.fetchedResultsController fetchedObjects] निर्धारित करते हैं, word पर एक केस-संवेदी खोज कर रही।

  • +0

    आपके उत्तर के लिए धन्यवाद। मैं सिर्फ एक xcdatamodel compliant डीबी में लोड प्रारंभिक sqlite डेटा प्राप्त करने के लिए कमांड लाइन उपकरण लिख रहा हूँ। पर्याप्त श्रम शामिल है। मैं अपने अनुभव पर वापस रिपोर्ट करूंगा। –

    +0

    आपके उदाहरण पर अनुवर्ती करने के लिए, मुझे लगता है कि समस्या यह है कि एक fetch अनुरोध Word इकाई पर नहीं होगा, लेकिन टेक्स्टटेबल इकाई पर। (मान लें कि टेक्स्टटेबल में ईमेल संदेश हैं और वर्ड में सभी ईमेल फ़ील्ड्स में सभी शब्द शामिल हैं।) मुझे लगता है कि यह इस मामले को महत्वपूर्ण रूप से जटिल करता है क्योंकि fetchResultsController को टेक्स्ट रखने योग्य इकाइयां रखना चाहिए जो भविष्यवाणी के माध्यम से फ़िल्टर किए जाते हैं - और ऐसी कोई भी या सबक्विरी भविष्यवाणी है धीमी गति से। शायद "विपरीत" दिशा में ऐसा करने का एक तरीका है: डब्ल्यू/वर्ड मैचों को शुरू करके, व्यस्त रिश्ते के बाद, और पाठ को विशिष्ट बनाना। हममम। –

    +0

    यदि आपकी भविष्यवाणी का पहला भाग जितना संभव हो सके खोज स्थान को कम कर देता है, तो शेष का अनुमान तेजी से प्रदर्शन करेगा, कुल मिलाकर, कम जगह के साथ इसे खोजना होगा। यहां कोर डेटा गाइड के प्रदर्शन अनुभाग पर एक नज़र डालें: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CoreData/Articles/cdPerformance.html#//apple_ref/doc/uid/ टीपी 40003468 –

    3

    इस प्रश्न का पालन करने के लिए, मैंने पाया है कि पूछताछ कोर डेटा का उपयोग कर कुत्ते धीमी है। मैंने इस पर अपने सिर को कई घंटों तक खरोंच कर दिया है।

    मेरे प्रश्न में एसक्यूएल उदाहरण के रूप में, दो इकाइयां हैं: टेक्स्टटेबल और शब्द जहां शब्दों में प्रत्येक शब्द होता है, यह अनुक्रमित होता है, और टेक्स्टटेबल और शब्दों के बीच कई से अधिक संबंध हैं। मैंने डेटाबेस को केवल 4000 शब्दों और 360 टेक्स्टटेबल ऑब्जेक्ट्स के साथ पॉप्युलेट किया। textTable संबंध मान लीजिए करने के लिए शब्द पर आपत्ति searchWords कहा जाता है, तो मैं textTable इकाई की तरह

    predicate = [NSPredicate predicateWithFormat:@"ANY searchWords.word BEGINSWITH %@", query]; 
    

    लग रहा है कि पर एक विधेय उपयोग कर सकते हैं (मैं कई प्रश्न के शब्द के लिए इस विधेय के संयोजक जोड़ सकते हैं।)

    आईफोन पर इस क्वेरी में कई सेकंड लगते हैं। एक बड़े परीक्षण सेट का उपयोग कर मेरे हाथ से कोडित एसक्यूएल के लिए प्रतिक्रिया तत्काल थी।

    लेकिन यह इसका अंत भी नहीं है। NSPredicate की सीमाएं हैं जो सरल प्रश्नों को धीमा और जटिल बनाती हैं। उदाहरण के लिए, उपरोक्त उदाहरण में कल्पना करें कि आप एक स्कोप बटन का उपयोग करके फ़िल्टर करना चाहते हैं। मान लें कि शब्द इकाई में सभी टेक्स्ट फ़ील्ड में सभी शब्द होते हैं, लेकिन दायरा इसे विशिष्ट फ़ील्ड के शब्दों तक सीमित कर देगा। इस प्रकार, शब्दों में "स्रोत" विशेषता हो सकती है (उदा। ईमेल का हेडर और संदेश निकाय)।

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

    ANY searchWords.word BEGINSWITH "foo" AND ANY searchWords.source = 3 
    

    क्योंकि संस्थाओं है कि दो भाव लिए सही हैं अलग हो सकता है।

    SUBQUERY(searchWords, $x, $x.word BEGINSWITH "foo" AND $x.source = 3)[email protected] > 0 
    

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

    इस बिंदु पर मैं बहुत उत्सुक हूं कि कोको प्रोग्रामर पूरी तरह से टेक्स्ट टेक्स्ट के लिए कोर डेटा का उपयोग कैसे करते हैं क्योंकि मैं अनुमानित मूल्यांकन और एनएसपीडिकेटिक की अभिव्यक्ति की गति दोनों से निराश हूं। मैं एक दीवार के खिलाफ भाग गया है।

    +1

    यहां प्रदर्शन अनुभाग पर नज़र डालने पर विचार करें: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CoreData/Articles/cdPerformance.html#//apple_ref/doc/uid/TP40003468 –

    +0

    उस लिंक के लिए धन्यवाद। वहां से मैंने पाया कि निष्पादन योग्य तर्क "-com.apple.CoreData.SQLDebug 1" stderr पर sqlite डीबग भेज देगा। उस डंप से मैंने क्वेरी देखी। क्वेरी के साथ वास्तव में कुछ भी गलत नहीं था, लेकिन क्योंकि <=> शब्दटेबल रिश्ते कई लोगों से जुड़ने के लिए एक रिलेशनशिप टेबल है। इस प्रकार, क्वेरी 3 टेबल में शामिल होना चाहिए। जब मैंने उलटा हटा दिया तो क्वेरी अब आईफोन हार्डवेयर पर बहुत तेजी से चलती है! हां, नई स्कीमा में वर्ड टेबल में विदेशी कुंजी है, इस प्रकार प्रत्येक घटना के लिए शब्द स्वयं और मेटाडेटा दोहराया जाता है। अंतरिक्ष बर्बाद हो गया। –

    +0

    आप गति प्राप्त कर सकते हैं, लेकिन ऐप्पल डेटा अखंडता को बनाए रखने के लिए व्यस्त संबंधों को बनाए रखने की सिफारिश करता है। "आपको आम तौर पर दोनों दिशाओं में संबंधों का मॉडल करना चाहिए, और विपरीत रिवर्स को उचित रूप से निर्दिष्ट करना चाहिए। कोर डेटा इस जानकारी का उपयोग ऑब्जेक्ट ग्राफ़ की स्थिरता सुनिश्चित करने के लिए करता है यदि कोई परिवर्तन किया जाता है (देखें" रिश्तों और ऑब्जेक्ट ग्राफ इंटीग्रटी में हेरफेर करना ")।" अधिक जानकारी के लिए यहां एक नज़र डालें: http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html –

    2

    इसी मुद्दे के साथ संघर्ष करने के बाद, मैं उन पदों की एक श्रृंखला में भाग गया जहां लेखक की एक ही समस्या थी और this solution के साथ आया। उन्होंने 6-7 सेकेंड सर्च टाइम से 0.13 और 0.05 सेकेंड के बीच सुधार की रिपोर्ट की।

    एफटीएस के लिए उनका डेटासेट 7 9 दस्तावेज (फ़ाइल आकार 175k, 3600 असतत टोकन, 10000 संदर्भ) था। मैंने अभी तक अपने समाधान की कोशिश नहीं की है, लेकिन सोचा कि मैं ASAP पोस्ट करूंगा। डेटा के दस्तावेज़ीकरण के लिए समस्या के दस्तावेज़ीकरण और Part 1 के लिए अपनी पोस्ट के Part 2 को भी देखें।

    +0

    इस समाधान के साथ मेरी समस्या यह है कि क्वेरी और कीवर्ड एक सटीक मिलान होना चाहिए। वास्तविक समय परिणामों के लिए आप क्वेरी से मेल खाने के लिए कोई भी कीवर्ड उपसर्ग चाहते हैं।उस स्थिति में भविष्य में स्ट्रिंग के बजाय ऑब्जेक्ट का उपयोग करना संभव नहीं है। –

    +0

    इसे स्वयं लागू करने का प्रयास किया और कोई सुधार नहीं हुआ, शायद क्योंकि मैं उपयोग कर रहा था [सीडी]। मैंने छोड़ दिया और sqlite3 fts के साथ शुरू किया। पीटर, अतिरिक्त लिंक के लिए धन्यवाद। मैं केवल एक तक ही सीमित था। – jluckyiv

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