11

सार समस्या: मेरे पास लगभग 250,000 नोड्स का ग्राफ है और औसत कनेक्टिविटी लगभग 10 है। नोड के कनेक्शन ढूंढना एक लंबी प्रक्रिया है (10 सेकंड कहें)। डेटाबेस में नोड को सहेजने में लगभग 10 सेकंड लगते हैं। मैं जांच सकता हूं कि डीबी में नोड पहले से ही मौजूद है या नहीं। समेकन की अनुमति, लेकिन एक समय में 10 से अधिक लंबे अनुरोध नहीं होने पर, आप उच्चतम कवरेज को सबसे तेज़ी से प्राप्त करने के लिए ग्राफ को कैसे पार करेंगे।अच्छा ग्राफ ट्रैवर्सल एल्गोरिदम

कंक्रीट समस्या: मैं एक वेबसाइट उपयोगकर्ता पृष्ठों को स्क्रैप करने की कोशिश कर रहा हूं। नए उपयोगकर्ताओं को खोजने के लिए मैं पहले से ज्ञात उपयोगकर्ताओं से मित्र सूची ला रहा हूं। मैंने पहले ही ग्राफ के लगभग 10% आयात किया है, लेकिन मैं चक्रों में फंस रहा हूं या बहुत अधिक नोड्स को याद रखने में बहुत अधिक स्मृति का उपयोग कर रहा हूं।

मेरे वर्तमान कार्यान्वयन:

def run() : 
    import_pool = ThreadPool(10) 
    user_pool = ThreadPool(1) 
    do_user("arcaneCoder", import_pool, user_pool) 

def do_user(user, import_pool, user_pool) : 
    id = user 
    alias = models.Alias.get(id) 

    # if its been updates in the last 7 days 
    if alias and alias.modified + datetime.timedelta(days=7) > datetime.datetime.now() : 
     sys.stderr.write("Skipping: %s\n" % user) 
    else : 
     sys.stderr.write("Importing: %s\n" % user) 
     while import_pool.num_jobs() > 20 : 
      print "Too many queued jobs, sleeping" 
      time.sleep(15) 

     import_pool.add_job(alias_view.import_id, [id], lambda rv : sys.stderr.write("Done Importing %s\n" % user)) 

    sys.stderr.write("Crawling: %s\n" % user) 
    users = crawl(id, 5) 
    if len(users) >= 2 : 
     for user in random.sample(users, 2) : 
      if (user_pool.num_jobs() < 100) : 
       user_pool.add_job(do_user, [user, import_pool, user_pool]) 

def crawl(id, limit=50) : 
    '''returns the first 'limit' friends of a user''' 
    *not relevant* 

वर्तमान कार्यान्वयन की समस्याएं:

  • , क्लिक्स कि मैं पहले से ही आयात किया है में अटक जाती है जिससे समय बर्बाद कर और आयात धागे निष्क्रिय होते हैं।
  • जितना अधिक वे इंगित करेंगे उतना अधिक जोड़ देंगे।

तो, मामूली सुधारों का स्वागत है, साथ ही पूर्ण पुनर्लेखन भी। धन्यवाद!

+1

कई उल्लेखनीय ग्राफ-सैद्धांतिक (!) एल्गोरिदम के खोजकर्ता रॉबर्ट तारजन से कोई संबंध? –

+0

:) अफसोस की बात है, केवल हंगरी में शहर है कि हम दोनों को अपना अंतिम नाम मिला है। लेकिन हम दोनों को कंप्यूटर और गणित का प्यार है। –

+0

प्रश्न से संबंधित नहीं है, लेकिन ध्यान दें कि sys.stderr.write ("... \ n") को प्रिंट >> sys.stderr द्वारा प्रतिस्थापित किया जा सकता है, "..." ("\ n" की आवश्यकता नहीं है, और उपयोग अधिक सामान्य प्रिंट स्टेटमेंट के)। – EOL

उत्तर

7

उन आप पहले ही देख चुके की आईडी याद करने के लिए आपको 250,000 पूर्णांकों की लंबाई का एक नक्शा की जरूरत है। यह "बहुत ज्यादा" से बहुत दूर है। बस इस तरह के एक मानचित्र को बनाए रखें और केवल किनारों के माध्यम से घूमते हैं जो पहले से अनदेखा उपयोगकर्ताओं को ले जाते हैं, जिससे उन्हें इस तरह के किनारे खोजने के बिंदु पर उस मानचित्र में जोड़ दिया जाता है।

जहाँ तक मैं देख सकता हूं, आप ब्रेडथ-पहली खोज (बीएफएस) को लागू करने के करीब हैं। इस एल्गोरिदम के विवरण के बारे में Google की जांच करें। और, ज़ाहिर है, म्यूटेक्स के बारे में मत भूलना - आपको उनकी आवश्यकता होगी।

+0

उपयोगकर्ता वास्तव में औसत लंबाई 15 के चरित्र तार हैं। मैंने {username1: True, username2: True} के साथ एक निर्देश रखने की कोशिश की लेकिन वह जल्दी से 100% यादगार और मशीन लॉक हो गया। शायद यह एक जादू का उपयोग करने के लिए अजगर में अक्षम है? –

+0

एक संभावित समाधान केवल उपयोगकर्ता नाम – cobbal

+0

के हैंश स्टोर करने के लिए होगा, एक सेट – cobbal

2

मैं वास्तव में उलझन में हूं कि डीबी में नोड जोड़ने में 10 सेकंड लगते हैं। यह एक समस्या की तरह लगता है। आप किस डेटाबेस का उपयोग कर रहे हैं? क्या आपके पास गंभीर मंच प्रतिबंध हैं?

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

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

आपके विवरण से, मुझे पूरा यकीन नहीं है कि आप कैसे फंस रहे हैं।

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

याकूब

+0

उपयोगकर्ता पर जानकारी के कुछ पृष्ठों को स्क्रैप करने से 10 सेकंड आता है और फिर इसे मेरे डेटाबेस प्रारूप में बदल देता है। इसमें से अधिकांश नेटवर्क समय है। –

+0

नए उपयोगकर्ताओं की पसंद के लिए, बहुत ही रोचक।मैं उपयोगकर्ताओं के लिए इनलिंक की गिनती करने की कोशिश करूंगा और केवल कम इनलिंक किए गए उपयोगकर्ताओं से ही छेड़छाड़ करूँगा। –

+0

इतने कम धागे क्यों? क्या आप चिंतित हैं कि वे आपको अवरुद्ध करेंगे? मैं प्रत्येक नोड (एला पावेल) के लिए हैश का सुझाव देने जा रहा था। एक चीज जो आप कर सकते हैं वह एक वृद्धिशील आईडी बना रही है और उन्हें संदर्भित करने के लिए एक सरल मैपिंग टेबल का उपयोग करें। – TheJacobTaylor

2

कोई विशेष एल्गोरिदम नहीं है जो आपको स्क्रैच से ग्राफ के निर्माण को अनुकूलित करने में मदद करेगा। एक तरफ या दूसरा, आपको कम से कम एक बार प्रत्येक नोड पर जाना होगा। चाहे आप यह depth first या breadth first एक गति परिप्रेक्ष्य से अप्रासंगिक हैं। Theran पहले एक टिप्पणी में सही ढंग से इंगित करता है कि पहले नजदीक नोड्स की खोज करके चौड़ाई-पहली खोज, आपको पूरे ग्राफ को पूरा करने से पहले, एक और अधिक उपयोगी ग्राफ दे सकती है; यह आपके लिए चिंता का विषय हो सकता है या नहीं। उन्होंने यह भी नोट किया कि गहराई की पहली खोज का सबसे पहला संस्करण रिकर्सन का उपयोग करके लागू किया गया है, जो संभावित रूप से आपके लिए एक समस्या हो सकती है। ध्यान दें कि रिकर्सन की आवश्यकता नहीं है, हालांकि; आप एक स्टैक पर अपूर्ण रूप से खोज नोड्स जोड़ सकते हैं और यदि आप चाहें तो उन्हें रैखिक रूप से संसाधित कर सकते हैं।

यदि आप एक साधारण अस्तित्व को नए नोड्स (ओ (1) के लिए जांचते हैं तो यदि आप लुकअप के लिए हैश का उपयोग करते हैं), तो चक्र बिल्कुल समस्या नहीं होगी। यदि आप पूर्ण ग्राफ को स्टोर नहीं करते हैं तो चक्र केवल चिंता का विषय हैं। आप ग्राफ के माध्यम से खोज अनुकूलित कर सकते हैं, लेकिन निर्माण चरण हमेशा रैखिक समय लेगा।

मैं अन्य पोस्टरों से सहमत हूं कि आपके ग्राफ का आकार कोई समस्या नहीं होनी चाहिए। 250,000 बहुत बड़ा नहीं है!

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

+1

बीएफएस बेहतर हो सकता है क्योंकि यह शुरुआती पहले के नजदीकी नोड्स को देखेगा, जो जल्द ही एक उपयोगी सबसेट देने की संभावना है। बीएफएस 250,000 स्तरों के गहरे रिकर्सन के जोखिम से भी बचाता है और अंतिम क्यू (आरडीबीएमएस मानते हुए) के रूप में उसी कतार में अपनी कतार रख सकता है। – Theran

+1

आप निश्चित रूप से गहरे स्टैक ट्रेस की समस्या के बिना डीएफएस बना सकते हैं: डीएफएस और बीएफएस के बीच एकमात्र असली अंतर बीएफएस में है जो आप कतार में नोड्स जोड़ते हैं; डीएफएस में, एक ढेर। वही एल्गोरिदम, विभिन्न डेटा संरचना-और इस प्रकार, विभिन्न अर्थशास्त्र। –

+0

@ तेरान, माइकल: +1 धन्यवाद - इस स्पष्टीकरण को समायोजित करने के लिए समायोजित उत्तर। –

0

यद्यपि आप का कहना है कि एक दोस्त सूची प्राप्त करने में बहुत समय (10 सेकंड या उससे अधिक) लेता है, अच्छा पुराने डिज्कस्ट्रा एल्गोरिथ्म का एक प्रकार सिर्फ काम कर सकते हैं:

  1. किसी भी नोड प्राप्त करें।
  2. आपके द्वारा पहले से लोड किए गए किसी भी नोड से कनेक्शन प्राप्त करें।
  3. यदि दूसरा अंत अभी तक लोड नहीं हुआ है, तो ग्राफ़ में नोड जोड़ें।
  4. जाओ कदम 2.

चाल कनेक्शन आप एक स्मार्ट तरीके से चरण 2 में लोड चयन करने के लिए है। इसके बारे में कुछ छोटी टिप्पणियां:

  • आपको किसी भी तरह से एक ही कनेक्शन को दो बार या अधिक बार लोड करने से रोकना चाहिए। एक यादृच्छिक कनेक्शन का चयन करना और अगर इसे लोड किया गया है तो इसे छोड़ दें यदि आप सभी कनेक्शन के बाद हैं तो पहले से ही बहुत अक्षम है।
  • यदि आप अंततः सभी कनेक्शन लोड करना चाहते हैं, तो एक ही समय में नोड के सभी कनेक्शन लोड करें।

वास्तव में दक्षता के बारे में कुछ कहने के लिए, कृपया डेटास्ट्रक्चर के बारे में अधिक जानकारी प्रदान करें।

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