2013-07-29 31 views
9

Tôi đang tìm kiếm một regex mà có thể được làm thức ăn cho một "tạo bảng bên ngoài" tuyên bố của Hive QL theo hình thứcHive RegexSerDe Multiline Log phù hợp với

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

Điều kiện là các bản ghi trong các tập tin đó các RegexSerDe phải đọc có dạng sau:

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. 

tôi đang sử dụng tạo mã bảng bên ngoài sau:

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'; 

Đây là điều:

Nó có thể kéo tất cả các LẦN ĐẦU TIÊN của mỗi nhật ký. Nhưng không phải các dòng nhật ký khác có nhiều hơn một dòng. Tôi đã thử tất cả các liên kết, thay thế \z bằng \Z ở cuối, thay thế \A bằng ^\Z hoặc \z với $, không có tác dụng. Tôi có thiếu một cái gì đó trong output.format.string của %4$s? hoặc tôi không sử dụng regex đúng cách?

gì regex làm:

Nó phù hợp với dấu thời gian đầu tiên, tiếp theo là các loại log (DEBUG hoặc INFO hoặc bất cứ điều gì), thì ID (hỗn hợp của trường hợp bảng chữ cái thấp hơn, con số và dấu gạch nối) tiếp theo là bất cứ điều gì, cho đến khi dấu thời gian tiếp theo được tìm thấy, hoặc cho đến khi kết thúc đầu vào được tìm thấy để khớp với mục nhập nhật ký cuối cùng. Tôi cũng đã thử thêm /m vào cuối, trong trường hợp đó, bảng được tạo có tất cả các giá trị NULL.

+0

tại sao bạn không tạo mảng cho em bé? (lol này không phải là ngay cả một động từ, nhưng stil ... bạn không thể đặt mỗi người vào một mảng? sau đó dòng đầu tiên sẽ là chìa khóa 0, thứ hai đa mục sẽ là 1, hai khác trong 2 và 3 và bạn có thể gọi chúng theo ý muốn) – user1576978

Trả lời

1

Dường như có một số vấn đề với regex của bạn.

Trước tiên, hãy xóa các dấu ngoặc vuông kép của bạn.

Thứ hai, \A\Z/\z là để phù hợp với đầu và kết thúc của đầu vào, không chỉ là một đường thẳng. Thay đổi \A thành ^ để khớp với dòng đầu tiên nhưng không thay đổi \z thành $ vì bạn thực sự muốn khớp với đầu vào cuối trong trường hợp này.

Thứ ba, bạn muốn đối sánh (.*?), không phải (.*)?. Mẫu đầu tiên là không phù hợp, trong khi mẫu thứ hai là tham lam nhưng không bắt buộc. Nó phải khớp với toàn bộ đầu vào của bạn đến cuối khi bạn cho phép nó được theo sau bởi đầu vào cuối.

Thứ tư, . không khớp với dòng mới. Thay vào đó, bạn có thể sử dụng (\s|\S) hoặc ([x]|[^x]), v.v., bất kỳ cặp đối sánh miễn phí nào.

Thứ năm, nếu nó cho bạn kết quả phù hợp với \A\Z/\z thì đầu vào cũng là một dòng khi bạn đang neo toàn bộ chuỗi.

Tôi khuyên bạn chỉ nên kết hợp chỉ \n, nếu không có gì phù hợp thì không bao gồm dòng mới.

Bạn không thể thêm /m vào cuối khi regex không bao gồm dấu phân cách.Nó sẽ cố gắng để phù hợp với các ký tự chữ số /m thay vì đó là lý do tại sao bạn không có kết quả phù hợp.

Nếu nó được đi làm việc regex bạn muốn sẽ là:

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

Breakdown: bắt đầu

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

trận đấu của newline, và 19 ký tự là chữ số, :, - hoặc cộng với dấu phẩy, ba chữ số và dấu cách. Chụp tất cả trừ không gian cuối cùng (dấu thời gian).

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

trận đấu một chữ [, bất kỳ số lượng chữ hoa, thậm chí không có, một chữ ] và một không gian. Chụp tất cả trừ không gian cuối cùng (mức lỗi).

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

Khớp bất kỳ số nào, chữ thường hoặc - và khoảng trắng. Chụp tất cả trừ không gian cuối cùng (id tin nhắn).

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

Khớp bất kỳ khoảng trắng hoặc ký tự khoảng trống nào (bất kỳ ký tự nào) nhưng phù hợp với không phù hợp *?. Dừng kết hợp khi một bản ghi mới hoặc kết thúc đầu vào (\Z) là ngay phía trước. Trong trường hợp này bạn không muốn kết thúc dòng kết thúc như một lần nữa, bạn sẽ chỉ nhận được một dòng trong đầu ra của bạn. Chụp tất cả trừ cuối cùng (văn bản tin nhắn). \r?\n là bỏ qua dòng mới cuối cùng ở cuối thư của bạn, như là \r?\Z. Bạn cũng có thể viết \r?\n\z Lưu ý: số vốn \Z bao gồm dòng mới cuối cùng ở cuối đầu vào nếu có. Chữ thường \z đối sánh ở cuối đầu vào, chứ không phải dòng mới trước khi kết thúc đầu vào. Tôi đã thêm \z? chỉ trong trường hợp bạn phải đối phó với kết thúc dòng Windows, tuy nhiên, tôi không tin rằng điều này cần thiết.

Tuy nhiên, tôi nghi ngờ rằng trừ khi bạn có thể nạp toàn bộ tệp trong cùng một lúc thay vì từng dòng một, điều này sẽ không hoạt động.

Một thử nghiệm đơn giản bạn có thể thử là:

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

Nếu nó hoạt động nó sẽ phù hợp với bất kỳ dòng đầy đủ theo sau là một dòng chữ số trên dòng tiếp theo (chữ số đầu tiên của timestamp của bạn).

0

Tôi không biết nhiều về Hive, nhưng regex sau, hoặc một biến thể định dạng cho các chuỗi Java, có thể làm việc:

(\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]+)*) 

Điều này có thể được nhìn thấy phù hợp với dữ liệu mẫu của bạn ở đây:

http://rubular.com/r/tQp9iBp4JI

Một sự cố:

  • (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d+) Các da te và thời gian (nhóm chụp 1)
  • \[([a-zA-Z_-]+)\] Mức log (chụp nhóm 2)
  • ([\w-]+) Yêu cầu id (chụp nhóm 3)
  • ((?:[^\n\r]+)(?:[\n\r]{1,2}\s[^\n\r]+)*) Thông điệp có khả năng đa dòng (chụp nhóm 4)

Ba nhóm chụp đầu tiên khá đơn giản.

Điều cuối cùng có thể hơi lạ, nhưng nó hoạt động trên rubular. Một sự cố:

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

tôi đã sử dụng [^\n\r] thay vì . vì nó trông giống như RegexSerDe cho phép người . trận đấu dòng mới (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; 
} 

Hope this helps.

1

Sau Java regex có thể giúp:

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

Breakdown:

  • 1st chụp nhóm (\d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},\d{1,3})
  • chụp 2 nhóm (\[.+?\])
  • chụp 3 nhóm (.+?)
  • nhóm chụp 4 ([\s\S]+?).

(?=\d{4}-\d{1,2}-\d{1,2}|\Z) Positive lookahead - Khẳng định rằng regex dưới đây có thể được matched.1st Alternative: \d{4}-\d{1,2}-\d{1,2} .2nd Alternative: \Z vị trí khẳng định ở cuối của chuỗi.

Tham chiếu http://regex101.com/