Самый быстрый метод для фильтрации огромного файла

У меня есть файл системного журнала с 4 ГБ размером каждую минуту, и ниже 2 строки 4,5 миллионов строк в каждую минуту,

и я хочу генерировать новый файл только с немногими столбцами eventtime|srcip|dstip, таким образом, результат будет как следовать

1548531299|X.X.X.X|X.X.X.X

обратите внимание на то, что положение полей случайно.
Я попробовал некоторые фильтры, но все еще потребление больше чем 40 минут для обработки одного файла на мощной машине VM с 4 Ядрами и поршне на 16 ГБ.

Так существует ли метод, чтобы обработать такой большой файл и отфильтровать необходимый столбец в быстром методе?

{Jan 26 22:35:00 172.20.23.148 date=2019-01-26 time=22:34:59 devname="ERB-03" devid="5KDTB18800169" logid="0000000011" type="traffic" subtype="forward" level="warning" vd="Users" eventtime=1548531299 srcip=X.X.X.X srcport=3XXXX srcintf="GGI-cer.405" srcintfrole="undefined" dstip=X.X.X.X dstport=XX dstintf="hh-BB.100" dstintfrole="undefined" sessionid=xxxxxxx proto=6 action="ip" policyid=5 policytype="policy" service="HTTP" appcat="unscanned" crscore=5 craction=xxxxxx crlevel="low"

Jan 26 22:35:00 172.20.23.148 date=2019-01-26 time=22:34:59 devname="XXX-XX-FGT-03" devid="XX-XXXXXXXX" logid="0000000013" type="traffic" subtype="forward" level="notice" vd="Users" eventtime=1548531299 srcip=X.X.X.X srcport=XXXXX srcintf="XXX-Core.123" srcintfrole="undefined" dstip=X.X.X.X dstport=XX dstintf="sXX-CC.100" dstintfrole="undefined" sessionid=1234567 cvdpkt=0 appcat="unscanned" crscore=5 craction=123456 crlevel="low"}
1
задан 28 January 2019 в 13:37

4 ответа

Perl к спасению

Сохраните следующий сценарий как filter.pl и сделайте это исполняемым файлом (chmod +x):

#!/usr/bin/env perl

use strict;
use warnings;

while( <> ) {
    if ( /^(?=.*eventtime=(\S+))(?=.*srcip=(\S+))(?=.*dstip=(\S+)).*$/ ) {
        print "$1|$2|$3\n";
    }
}

Затем выполненный

pduck@ubuntu:~> time ./filter.pl < input.txt > output.txt

real    0m44,984s
user    0m43,965s
sys     0m0,973s

regex использует lookaround шаблон, в этом случае положительное предвидение, для соответствия трем значениям eventtime, srcip, и dstip в любом порядке.

Я копировал Ваши две входных строки, пока я не получил файл с 4 ГБ и приблизительно 9 миллионов строк. Я выполнил код SSD.

2
ответ дан 3 December 2019 в 06:36

Если Вы хотите действительно быстрое решение, я предлагаю инструмент гибкого провода. Flex генерирует C. Следующее способно к обработке примеров как тот, представленный, принимая свободные поля порядка. Поэтому создайте файл, названный f.fl со следующим содержанием:

%option main
%%
  char e[100], s[100], d[100];

eventtime=[^ \n]*   { strcpy(e,yytext+10); }
srcip=[^ \n]*       { strcpy(s,yytext+6);  }
dstip=[^ \n]*       { strcpy(d,yytext+6);  }
\n                  { if (e[0] && s[0] && d[0] )printf("%s|%s|%s\n",e,s,d); 
                      e[0]=s[0]=d[0]=0 ;}
.                   {}
%%

Протестировать попытку:

$ flex -f -o f.c f.fl 
$ cc -O2 -o f f.c
$ ./f < input > output

Вот time сравнение:

$ time ./f < 13.5-milion-lines-3.9G-in-file > out-file
real    0m35.689s
user    0m34.705s
sys     0m0.908s
2
ответ дан 3 December 2019 в 06:36

Я копировал Ваши две 'входных' строки к размеру файла 3867148288 байтов (3,7 гибибайта), и я мог обработать его с grep за 8 минут и 24 секунды (читающий из и пишущий в жесткий диск. Это должно быстрее использовать SSD или ramdrive).

Для уменьшения используемого времени я использовал только стандартные функции grep, и не выполнял последующую обработку его, таким образом, выходной формат не то, что Вы указываете, но могли бы быть полезными так или иначе. Можно протестировать эту команду

time grep -oE -e 'eventtime=[0-9]* ' \
 -e 'srcip=[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]' \
 -e 'dstip=[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]' \
infile > outfile

Вывод от Ваших двух строк:

$ cat outfile
eventtime=1548531298 
srcip=X.X.X.Y
dstip=X.X.X.X
eventtime=1548531299 
srcip=X.X.X.Z
dstip=X.X.X.Y

Выходной файл содержит 25 165 824 строки, соответствующие 8388608 (8,3 миллионов) строки во входном файле.

$ wc -l outfile
25165824 outfile
$ <<< '25165824/3' bc
8388608

Мой тест указывает на это grep может обработать приблизительно 1 миллион строк в минуту.

Если Ваш компьютер не намного быстрее, чем мой. это не достаточно быстро, и я думаю, что необходимо рассмотреть что-то, что несколько раз быстрее, вероятно, фильтрует прежде, чем записать файл журнала, но было бы лучше полностью избежать вывода того, что не необходимо (и постарайтесь не фильтровать).


Входной файл сделан дублированием, и возможно система 'помнит', что это видело те же строки прежде и делает вещи быстрее, таким образом, я не знаю, как быстро это будет работать с реальным большим файлом со всеми непредсказанными изменениями. Необходимо протестировать его.


Edit1: Я выполнил ту же задачу в Dell M4800 с процессором Intel 4th generation i7 и SSD. Это закончилось через 4 минуты и 36 секунд, почти в удвоенной скорости, 1,82 миллиона строк в минуту.

$ <<< 'scale=2;25165824/3/(4*60+36)*60/10^6' bc
1.82

Все еще слишком медленный.


Edit2: Я упростил grep шаблоны и выполнили его снова в Dell.

time grep -oE -e 'eventtime=[^\ ]*' \
 -e 'srcip=[^\ ]*' \
 -e 'dstip=[^\ ]*' \
infile > out

Это закончилось после 4 минут и 11 секунд, маленького улучшения 2,00 миллионов строк в минуту

$ <<< 'scale=2;25165824/3/(4*60+11)*60/10^6' bc
2.00

Редактирование 3: @JJoao, расширение жемчуга убыстряется grep к 39 секундам, соответствуя 12,90 миллионам строк в минуту в компьютере, где дежурное блюдо grep чтения 1 миллион строк в минуту (читающий из и пишущий в жесткий диск).

$ time grep -oP '\b(eventtime|srcip|dstip)=\K\S+' infile >out-grep-JJoao

real    0m38,699s
user    0m31,466s
sys     0m2,843s

Это расширение жемчуга является experiental согласно info grep но работы в моем Lubuntu 18.04.1 LTS.

‘-P’ ‘-perl-regexp’ Интерпретируют шаблон как Совместимое с Perl регулярное выражение (PCRE). Это экспериментально, особенно в сочетании с ‘-z’ (‘ - пустые данные’), опция, и ‘grep-P’ может предупредить о нереализованных функциях. *Отметьте Другие Опции::.

Я также скомпилировал программу C согласно @JJoao flex метод и это finshed за 53 секунды, соответствуя 9,49 миллионам строк в минуту в компьютере, где дежурное блюдо grep чтения 1 миллион строк в минуту (читающий из и пишущий в жесткий диск). Оба метода быстры, но grep с жемчугом расширение является самым быстрым.

$ time ./filt.jjouo < infile > out-flex-JJoao

real    0m53,440s
user    0m48,789s
sys 0m3,104s

Редактирование 3.1: В Dell M4800 с SSD у меня были следующие результаты,

time ./filt.jjouo < infile > out-flex-JJoao

real    0m25,611s
user    0m24,794s
sys 0m0,592s

time grep -oP '\b(eventtime|srcip|dstip)=\K\S+' infile >out-grep-JJoao

real    0m18,375s
user    0m17,654s
sys 0m0,500s

Это соответствует

  • 19,66 миллионов строк в минуту для flex приложение
  • 27,35 миллионов строк в минуту для grep с расширением жемчуга

Редактирование 3.2: В Dell M4800 с SSD у меня были следующие результаты, когда я использовал опцию -f к препроцессору гибкого провода,

flex -f -o filt.c filt.flex
cc -O2 -o filt.jjoao filt.c

Результат был улучшен, и теперь flex приложение показывает самую высокую скорость

flex -f ...

$ time ./filt.jjoao < infile > out-flex-JJoao

real    0m15,952s
user    0m15,318s
sys 0m0,628s

Это соответствует

  • 31,55 миллиона строк в минуту для flex приложение.
1
ответ дан 3 December 2019 в 06:36

Вот одно возможное решение, на основе этого ответа, предоставленного @PerlDuck только что:

#!/bin/bash
while IFS= read -r LINE
do
    if [[ ! -z ${LINE} ]]
    then
        eval $(echo "$LINE" | sed -e 's/\({\|}\)//g' -e 's/ /\n/g' | sed -ne '/=/p')
        echo "$eventtime|$srcip|$dstip"
    fi
done < "$1"

Я не знаю, как это будет вести себя на таком большом файле, IMO awk решение будет намного быстрее. Вот то, как это работает с обеспеченным входным примером файла:

$ ./script.sh in-file
1548531299|X.X.X.X|X.X.X.X
1548531299|X.X.X.X|X.X.X.X

Вот результат производительности time тест, выполненный на регулярном i7, оборудованном SSD и 16 ГБ RAM:

$ time ./script.sh 160000-lines-in-file > out-file

real    4m49.620s
user    6m15.875s
sys     1m50.254s
0
ответ дан 3 December 2019 в 06:36

Другие вопросы по тегам:

Похожие вопросы: