एक बड़ी फ़ाइल पर समानांतर awk कमांड चलाएं, कोई अतिरिक्त फ़ाइल स्थान नहीं


2

मैं एक काफी बड़े टैब-अलग फ़ाइल (~ 30 जीबी) को संसाधित करने की कोशिश कर रहा हूं। मैं कॉलम को पुनर्व्यवस्थित करने के लिए awk चला सकता हूं, लेकिन यह केवल मेरे 8 कोर मशीन के एक कोर का उपयोग करता है। मैं सभी कोर का उपयोग कैसे कर सकता हूं? (और नाटकीय रूप से मेरे प्रसंस्करण समय को कम करें) भौतिक रूप से फ़ाइल को विभाजित करने और अधिक डिस्क स्थान का उपयोग किए बिना?

cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged.tsv

मैं ऐसा कुछ करना चाहूंगा, लेकिन अधिक डिस्क स्थान का उपयोग किए बिना:

split -l 50000 original.tsv sp
for i in $(dir sp*); do ./process_file.sh $i & done;

जहाँ process_file.sh अनिवार्य रूप से ऊपर का कट / awk स्टेटमेंट है।

फिर, यहाँ मुख्य समस्या यह है कि इस प्रक्रिया को किसी अन्य 30GB का उपयोग किए बिना किया जाए! कोई सुझाव?


1
क्या आपको यकीन है कि सीपीयू अड़चन है, आईओ नहीं?
मार्को

1
आपको cutकमांड की आवश्यकता नहीं है बस $ 4, $ 3, $ 5, $ 6 प्रिंट करें (और OFS से टैब पर सेट करें)
RedGrittyBrick

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

मैं इसके बारे में ज्यादा नहीं जानता awk(और इसलिए इसके बारे में ज्यादा कुछ नहीं कह सकता) लेकिन मुझे लगा कि अगर मैंने इसे आपकी चर्चा में फेंक दिया तो यह आपकी चर्चा को चमत्कृत कर सकता है ।
wulxz

जवाबों:


1

चूंकि आप अपनी फ़ाइलों को लाइनों की संख्या से अलग करने के लिए "स्प्लिट" का उपयोग कर रहे हैं, तो उन्हें अलग-अलग फ़ाइलों में आउटपुट करने के लिए अलग-अलग प्रोसेस करें (मुझे लगता है), आप कई "awk" कर सकते हैं प्रत्येक प्रोसेसिंग लाइन नंबर के आधार पर आपकी फ़ाइल के केवल एक हिस्से को संसाधित करती है:

$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; (NR < 50000){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 50000) && (NR < 100000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 100000) && (NR < 150000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

NR, "awk" का एक आंतरिक चर है जिसमें वर्तमान लाइन संख्या होती है। प्रत्येक कमांड अपनी सीमा में केवल लाइनों को प्रोसेस करेगा। लेकिन , वे सभी अन्य लाइनों के माध्यम से भी जाएंगे, क्योंकि उन्हें उन्हें गिनने की जरूरत है। मुझे पूरा यकीन है कि यह आपकी मदद नहीं करेगा, क्योंकि आप सबसे अधिक शायद आईओ की अड़चन में पड़ेंगे। लेकिन आपके पास कई प्रक्रियाएँ होंगी, जिससे आप कई सीपीयू का उपयोग कर सकते हैं, यदि आप यही चाहते हैं। ;-)

अब, यदि आपके पास बाइट्स में समान लंबाई वाली सभी लाइनें हैं, तो आप निश्चित रूप से एक वास्तविक समानांतरकरण कर सकते हैं। इस स्थिति में, आप प्रत्येक "awk" प्रक्रिया के लिए सटीक भाग निकालने के लिए "dd" का उपयोग करेंगे। आप कुछ ऐसा ही करेंगे:

dd if=original.tsv bs=30 count=50000 skip=0 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv

dd if=original.tsv bs=30 count=50000 skip=50000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv

dd if=original.tsv bs=30 count=50000 skip=100000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

जहां प्रत्येक पंक्ति में 30 बाइट्स की संख्या है। यदि आपकी लाइनें बाइट्स (जो सबसे अधिक संभावित है) में सभी समान आकार नहीं हैं, लेकिन आप सटीक बाइट को जानते हैं जहां आपकी पंक्तियों का ब्लॉक शुरू और समाप्त होता है, तब भी आप इसे dd का उपयोग करके कर सकते हैं। इसके मापदंडों का अध्ययन करें। अंत में, यदि आप नहीं जानते हैं कि ब्लॉक कहाँ से शुरू होते हैं और समाप्त होते हैं, तो आप उन्हें एक अतिरिक्त awk कमांड के साथ खोज सकते हैं। लेकिन यह आपकी फ़ाइल में एक अतिरिक्त पूर्ण रीड जोड़ता है। जब तक आप अपनी ओरिजिनल .tsv फाइल को कई बार अलग-अलग तरीकों से प्रोसेस नहीं करेंगे, आप निश्चित रूप से ज्यादा समय प्री-प्रोसेसिंग (बाइट्स की गणना करते हुए जहां लाइन ब्लॉक शुरू और खत्म होते हैं) खर्च करेंगे और फिर प्रोसेसिंग (जिसका संभवत: एक छोटा लाभ होगा क्योंकि आप निश्चित रूप से होंगे। यदि आपके द्वारा पहले से ही ज्ञात समाधान का उपयोग किया जाता है, तो IO की अड़चन है)।

किसी भी मामले में, अब आपके पास जानकारी और विकल्प हैं। ;-) सौभाग्य! (Y)


0

Fwiw, splitकमांड में एक विकल्प होता है --filter=./myscript.shजो आउटपुट फाइल (ओं) में लिखे जाने से पहले डेटा को प्रोसेस करता है। इसलिए आपके पास एक पूर्व-प्रसंस्करण स्क्रिप्ट हो सकती है जिसे ./myscript.shआपका परिवर्तन कहा जाता है , जैसे,

cut ... | awk '...' > $FILE

$FILEआउटपुट फाइल कहाँ से उत्पन्न होती है split(उदाहरण के लिए xaa, ...)। या, सभी अस्थायी फ़ाइलों से बचने के लिए, बस एक फ़ाइल के लिए संक्षिप्त करें,

cut ... | awk '...' >> abridged.tsv

splitहालाँकि, यह विश्वास करने का कोई कारण नहीं है कि इसका उपयोग न करने की तुलना में कोई तेज़ होगा , हालांकि।

यह देखते हुए कि आप "बड़ा डेटा" प्रसंस्करण कर रहे हैं (और मूल रूप से यह सवाल पूछे जाने के बाद कि यह कितने साल है), यह भी शायद इस 30GB फ़ाइल को hdfs (या, बल्कि, डेटा को रखना और रखना है) को कॉपी करना जितना आसान है मूल रूप से) और अपाचे हाइव का उपयोग वांछित डेटा का चयन / प्रारूप करने के लिए करें।

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