2013-07-29 37 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/