2013-07-29 5 views
9

मैं एक regex कि एक को खिलाया जा सकता रहा हूँहाइव RegexSerDe बहुपंक्ति लॉग मिलान

"input.regex"="the regex goes here" 

हालत के रूप में हाइव QL के बयान "बाहरी तालिका बनाने के" है कि फाइलों में लॉग RegexSerDe पढ़ने होना चाहिए निम्न रूप में कर रहे हैं:

2013-02-12 12:03:22,323 [DEBUG] 2636hd3e-432g-dfg3-dwq3-y4dsfq3ew91b Some message that can contain any special character, including linebreaks. This one does not have a linebreak. It just has spaces on the same line. 
2013-02-12 12:03:24,527 [DEBUG] 265y7d3e-432g-dfg3-dwq3-y4dsfq3ew91b Some other message that can contain any special character, including linebreaks. This one does not have one either. It just has spaces on the same line. 
2013-02-12 12:03:24,946 [ERROR] 261rtd3e-432g-dfg3-dwq3-y4dsfq3ew91b Some message that can contain any special character, including linebreaks. 
This is a special one. 
This has a message that is multi-lined. 
This is line number 4 of the same log. 
Line 5. 
2013-02-12 12:03:24,988 [INFO] 2632323e-432g-dfg3-dwq3-y4dsfq3ew91b Another 1-line log 
2013-02-12 12:03:25,121 [DEBUG] 263tgd3e-432g-dfg3-dwq3-y4dsfq3ew91b Yet another one line log. 

मैं निम्नलिखित बनाने के बाहरी तालिका कोड का उपयोग कर रहा:

CREATE EXTERNAL TABLE applogs (logdatetime STRING, logtype STRING, requestid STRING, verbosedata STRING) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe' 
WITH SERDEPROPERTIES 
(
"input.regex" = "(\\A[[0-9:-] ]{19},[0-9]{3}) (\\[[A-Z]*\\]) ([0-9a-z-]*) (.*)?(?=(?:\\A[[0-9:-] ]{19},[0-9]|\\z))", 
"output.format.string" = "%1$s \\[%2$s\\] %3$s %4$s" 
) 
STORED AS TEXTFILE 
LOCATION 'hdfs:///logs-application'; 

यहां बात है:

यह प्रत्येक लॉग की सभी पहली पंक्तियों को खींचने में सक्षम है। लेकिन लॉग की अन्य पंक्तियां जिनमें एक से अधिक पंक्तियां नहीं हैं। मैंने सभी लिंकों की कोशिश की, \z को \Z के साथ \A^ और \Z या \z$ के साथ प्रतिस्थापित किया, कुछ भी काम नहीं किया। क्या मुझे output.format.string के %4$s में कुछ याद आ रहा है? या मैं regex ठीक से उपयोग नहीं कर रहा हूँ?

क्या regex करता है:

यह टाइमस्टैम्प पहले लॉग प्रकार (DEBUG या INFO या जो कुछ भी) के द्वारा पीछा किया, तो ID किसी से भी पीछा (लोअर केस अक्षर, संख्या और हाइफ़न का मिश्रण) से मेल खाता है, जब तक अगला टाइमस्टैम्प नहीं मिलता है, या इनपुट के अंत तक अंतिम लॉग प्रविष्टि से मेल खाने के लिए मिलता है। मैंने अंत में /m जोड़ने का भी प्रयास किया, इस मामले में, उत्पन्न तालिका में सभी नल मान हैं।

+0

आप उस बच्चे को क्यों सरणी नहीं देते? (lol यह एक क्रिया भी नहीं है, लेकिन stil ... आप उनमें से प्रत्येक को सरणी में सेट नहीं कर सका? तो पहली पंक्ति कुंजी 0 होगी, दूसरा मल्टीलाइन आइटम 1 में होगा, दूसरा दो 2 और 3 में होगा और आप उन्हें अपनी पसंद के अनुसार कॉल कर सकते हैं) – user1576978

उत्तर

1

आपके रेगेक्स के साथ कई समस्याएं प्रतीत होती हैं।

सबसे पहले, अपने डबल स्क्वायर ब्रैकेट को हटा दें।

दूसरा, \A और \Z/\z शुरुआत और इनपुट के अंत ही नहीं, एक लाइन से मिलान करने के हैं। \A से ^ स्टार्ट-ऑफ-लाइन से मिलान करने के लिए \z से $ बदलें क्योंकि आप वास्तव में इस मामले में अंत-इनपुट इनपुट करना चाहते हैं।

तीसरा, आप (.*?) से मिलान करना चाहते हैं, (.*)? नहीं। पहला पैटर्न असभ्य है, जबकि दूसरा पैटर्न लालची लेकिन वैकल्पिक है। यह आपके पूरे इनपुट को अंत तक मेल खाना चाहिए था क्योंकि आपने इसे अंत-इनपुट के बाद अनुमत किया था।

चौथा, . न्यूलाइन से मेल नहीं खाता है। आप इसके बजाय (\s|\S) का उपयोग कर सकते हैं, या ([x]|[^x]), आदि, मानार्थ मैचों की किसी भी जोड़ी का उपयोग कर सकते हैं।

पांचवां, अगर यह आपको एक लाइन दे रहा था से मेल खाता है साथ \A और \Z/\z तो इनपुट एकल लाइनों भी आप पूरी स्ट्रिंग प्रस्तोता थे के रूप में किया गया था।

मैं केवल \n से मिलान करने का प्रयास करने का सुझाव दूंगा, अगर कुछ भी मेल नहीं खाता तो न्यूलाइन शामिल नहीं हैं।

आप /m को अंत में जोड़ नहीं सकते क्योंकि रेगेक्स में डिलीमीटर शामिल नहीं हैं।यह शाब्दिक पात्रों /m से मेल खाने का प्रयास करेगा, यही कारण है कि आपको कोई मिलान नहीं मिला।

यह regex आप होगा चाहते हैं काम करने के लिए जा रहा था, तो:

"^([0-9:- ]{19},[0-9]{3}) (\\[[A-Z]*\\]) ([0-9a-z-]*) ([\\s\\S]*?)(?=\\r?\\n([0-9:-]){19},[0-9]|\\r?\\z)" 

ब्रेकडाउन: न्यू लाइन की

^([0-9:- ]{19},[0-9]{3}) 

मैच शुरू होने से, और 19 अक्षर हैं जो अंक होते हैं, :, - या प्लस एक अल्पविराम, तीन अंक और एक स्थान। अंतिम स्थान (टाइमस्टैम्प) के अलावा सभी को कैप्चर करें।

(\\[[A-Z]*\\]) 

मैच एक शाब्दिक [, बड़े अक्षरों के किसी भी संख्या, यहां तक ​​कि कोई नहीं, एक शाब्दिक ] और एक अंतरिक्ष। अंतिम स्थान (त्रुटि स्तर) के अलावा सभी को कैप्चर करें।

([0-9a-z-]*) 

मैच अंक, छोटे अक्षरों या - और एक अंतरिक्ष के किसी भी संख्या। अंतिम स्थान (संदेश आईडी) के अलावा सभी को कैप्चर करें।

([\\s\\S]*?)(?=\\r?\\n([0-9:-]){19},[0-9]|\\r?\\Z) 

मैच किसी भी खाली स्थान या गैर-सफ़ेद चरित्र (किसी भी चरित्र), लेकिन ungreedy *? मेल खाते हैं। जब कोई नया रिकॉर्ड या इनपुट (\Z) के अंत से मेल खाता है तो तुरंत बंद करें। इस मामले में आप एक बार फिर से लाइन के अंत से मेल नहीं करना चाहते हैं, आपको केवल अपने आउटपुट में एक पंक्ति मिल जाएगी। सभी को अंतिम (संदेश पाठ) कैप्चर करें। \r?\n आपके संदेश के अंत में अंतिम नई लाइन को छोड़ना है, जैसा कि \r?\Z है। आप \r?\n\z भी लिख सकते हैं नोट: पूंजी \Z में इनपुट के अंत में अंतिम नई लाइन शामिल है यदि कोई है। लोअरकेस \z केवल इनपुट के अंत में मेल खाता है, इनपुट के अंत से पहले नई लाइन नहीं। मैंने \z? को जोड़ा है यदि आपको विंडोज लाइन के अंतराल से निपटना है, हालांकि, मुझे विश्वास नहीं है कि यह आवश्यक होना चाहिए।

हालांकि, मुझे संदेह है कि जब तक आप पूरी फ़ाइल को लाइन-लाइन के बजाय एक बार में फ़ीड नहीं कर सकते हैं कि यह या तो काम नहीं करेगा।

एक और साधारण परीक्षण तुम कोशिश कर सकते है:

"^([\\s\\S]+)^\\d" 

यह काम करता है, तो यह किसी भी पूरी लाइन अगली पंक्ति पर एक पंक्ति अंक की (अपने टाइमस्टैम्प के पहले अंक) से मेल खाएगी।

0

मैं हाइव के बारे में ज्यादा है, लेकिन निम्नलिखित regex, या एक बदलाव जावा तार के लिए स्वरूपित पता नहीं है, काम हो सकता है:

(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d+) \[([a-zA-Z_-]+)\] ([\w-]+) ((?:[^\n\r]+)(?:[\n\r]{1,2}\s[^\n\r]+)*) 

यह यहाँ नमूना डेटा मिलान देखा जा सकता है:

http://rubular.com/r/tQp9iBp4JI

एक टूटने:

  • (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d+) दा ते और समय (कैप्चर समूह 1)
  • \[([a-zA-Z_-]+)\] लॉग स्तर (कैप्चर समूह 2)
  • ([\w-]+) अनुरोध आईडी (कैप्चर समूह 3)
  • ((?:[^\n\r]+)(?:[\n\r]{1,2}\s[^\n\r]+)*) संभावित बहु लाइन संदेश (कैप्चर समूह 4)

पहले तीन कैप्चर समूह बहुत ही सरल हैं।

आखिरी वाला थोड़ा अजीब हो सकता है, लेकिन यह रूबलर पर काम कर रहा है। एक टूटने:

// Excerpt from https://github.com/apache/hive/blob/trunk/contrib/src/java/org/apache/hadoop/hive/contrib/serde2/RegexSerDe.java#L101 
if (inputRegex != null) { 
    inputPattern = Pattern.compile(inputRegex, Pattern.DOTALL 
     + (inputRegexIgnoreCase ? Pattern.CASE_INSENSITIVE : 0)); 
} else { 
    inputPattern = null; 
} 

आशा इस मदद करता है:

(      Capture it as one group 
    (?:[^\n\r]+)  Match to the end of the line, dont capture 
    (?:     Match line by line, after the first, but dont capture 
     [\n\r]{1,2}  Match the new-line 
     \s    Only lines starting with a space (this prevents new log-entries from matching) 
     [^\n\r]+  Match to the end of the line    
    )*     Match zero or more of these extra lines 
) 

मैं . के बजाय [^\n\r] इस्तेमाल किया RegexSerDe की तरह लग रहा है, क्योंकि यह . मैच नई लाइनों (link) की सुविधा देता है।

1

के बाद जावा regex मदद मिल सकती है:

(\d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},\d{1,3})\s+(\[.+?\])\s+(.+?)\s+([\s\S\s]+?)(?=\d{4}-\d{1,2}-\d{1,2}|\Z) 

ब्रेकडाउन:

  • 1 कैप्चर समूह (\d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},\d{1,3})
  • 2 कैप्चर समूह (\[.+?\])
  • 3 कैप्चर समूह (.+?)
  • 4 कैप्चर समूह ([\s\S]+?)

(?=\d{4}-\d{1,2}-\d{1,2}|\Z) सकारात्मक अग्रावलोकन - का दावा है कि नीचे regex matched.1st किया जा सकता है वैकल्पिक: स्ट्रिंग के अंत में \Z ज़ोर स्थिति: \d{4}-\d{1,2}-\d{1,2} .2nd वैकल्पिक।

संदर्भ http://regex101.com/