2013-07-29 39 views
9

我尋找可以被輸送到一個正則表達式中的蜂巢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,用^\Z\z替換\A,用$代替\A,沒有任何工作。我在output.format.string的%4$s中錯過了什麼嗎?或者我沒有正確使用正則表達式?

正則表達式能做什麼:

它的時間戳第一,其次是日誌類型(DEBUGINFO或其他),那麼ID其後內容是什麼(小寫字母,數字和連字符的組合)相匹配,直到找到下一個時間戳,或者直到找到與最後一個日誌條目匹配的輸入結束爲止。我還嘗試在最後添加/m,在這種情況下,生成的表具有所有NULL值。

+0

你爲什麼不排列那個寶貝? (大聲笑這甚至不是動詞,但stil ...你不能將每個人都設置爲一個數組嗎?那麼第一行將是關鍵0,第二個多行項目將在1,另外兩個在2和3你可以打電話給他們,只要你喜歡) – user1576978

回答

1

似乎你的正則表達式有很多問題。

首先,刪除你的雙方括號。

其次,\A\Z/\z是相匹配的輸入的開頭和結尾,而不是一條線。將\A更改爲^以匹配起始行,但不要更改\z$,因爲您確實希望在此情況下確實匹配輸入的結尾。

三,要匹配(.*?)而不是(.*)?。第一種模式是不明朗的,而第二種模式是貪婪但是可選的。它應該已經將您的整個輸入匹配到最後,因爲您允許它跟隨輸入結束。第三,.與換行符不匹配。您可以使用(\s|\S)替代,或([x]|[^x])等,任何一對免費的比賽。第五,如果它是給你單線匹配與\A\Z/\z然後輸入是單行也當你錨定整個字符串。

我會建議試圖匹配\n,如果沒有匹配,則不包括換行符。

由於正則表達式不包含分隔符,因此不能將/m添加到最後。它會嘗試匹配文字字符/m而不是這是爲什麼你沒有匹配。

如果是去上班,你想會是正則表達式:

"^([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-]*) 

匹配任何數量的數字,小寫字母或-和空間。捕獲除最終空間外的所有內容(消息ID)。

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

匹配任何空白或非空白字符(任何字符),但匹配ungreedy *?。當輸入(\Z)的新記錄或結束時立即停止匹配。在這種情況下,您不想再次匹配行尾,只會在輸出中獲得一行。捕獲除最後的所有內容(消息文本)。 \r?\n將跳過郵件末尾的最後一個換行符,\r?\Z也是如此。你也可以寫\r?\n\z注意:如果有輸入結尾的話,大寫\Z包括最後一個換行符。小寫字母\z僅在輸入結束時匹配,在輸入結束前不匹配換行符。我已經添加了\z?以防萬一您必須處理Windows行結束,但是,我不認爲這是必要的。

但是,我懷疑,除非你可以一次送入整個文件而不是逐行寫入,否則這也不起作用。

另一種簡單的測試,你可以嘗試是:

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

如果成功,它將匹配任何全線接着在下一行行數字(您的時間戳的第一位數字)。

0

我不知道很多關於蜂巢,但下面的正則表達式,或者格式化爲Java字符串的變化,可能的工作:

(\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+)的噠TE和時間(捕獲組1)
  • \[([a-zA-Z_-]+)\]日誌級別(捕獲組2)
  • ([\w-]+)請求ID(捕獲組3)
  • ((?:[^\n\r]+)(?:[\n\r]{1,2}\s[^\n\r]+)*)所述潛在的多行消息(捕獲組4)

前三個捕獲組非常簡單。

最後一個可能有點奇怪,但它正在研究rubular。細目:

(      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):

// 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; 
} 

希望這有助於。

1

以下Java正則表達式可以幫助:

(\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})
  • 第二捕獲組(\[.+?\])
  • 第三捕獲組(.+?)
  • 4捕獲組([\s\S]+?)

(?=\d{4}-\d{1,2}-\d{1,2}|\Z)正預測先行 - 斷言,下面的正則表達式可以matched.1st替代方法:在所述串的端\Z斷言位置:\d{4}-\d{1,2}-\d{1,2} .2nd替代。

參考http://regex101.com/