Имеется большой файл по трафику с таким содержимым:
ip1 ip2 packets bytes
ip2 ip3 packets2 bytes2
и т.д
Нужно как-то просуммировать пакеты и байты по совпадающим парам ип.
На awk сделал так:
awk '{k=$0;
sub(/[ \t]+[0-9]+[ \t]+[0-9]+$/,"",k);
if ( NF==4 ){ s1[k]+=$3; s2[k]+=$4;}}
END {for(k in s1){print k,s1[k],s2[k]}}' traffic.dump_wait_agg >> traffic.dumpВ итоге все работает как надо, но на больших файлах awk начинает ругаться - out of memory in array. Файлики могут быть по 1 Гб, оперативки 4 Гб.
Подскажите как сделать иначе или может не на awk даже, чтоб на больших объемах не падало.
awk какой?
может стоит попробовать gawk или mawk?
>awk какой?
>может стоит попробовать gawk или mawk?awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо как-то по другому делать агрегацию строк.
>>awk какой?
>>может стоит попробовать gawk или mawk?
>
>awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех
>молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо
>как-то по другому делать агрегацию строк.просто интересно, если это сделать на perl и как он справится?
>>>awk какой?
>>>может стоит попробовать gawk или mawk?
>>
>>awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех
>>молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо
>>как-то по другому делать агрегацию строк.
>
>просто интересно, если это сделать на perl и как он справится?Буду пробовать, наверно perl также поведет себя.
>Буду пробовать, наверно perl также поведет себя.Это смотря как напишите и насколько много разных пар. Вам понадобится количество памяти равное: (количество разных пар) * (размер в байтах одного элемента хеша). Последнее врядли получится больше 20 байт и в любом случае общее количество сожранной памяти будет меньше исходного размера файла.
Приходилось при помощи перла удалять дублирующиеся строки в 30+ гиговых файлах и проблем не возникло, в процессе работы сжирало около сотни метров памяти.
>>Буду пробовать, наверно perl также поведет себя.
>
>Это смотря как напишите и насколько много разных пар. Вам понадобится количество
>памяти равное: (количество разных пар) * (размер в байтах одного элемента
>хеша). Последнее врядли получится больше 20 байт и в любом случае
>общее количество сожранной памяти будет меньше исходного размера файла.
>Приходилось при помощи перла удалять дублирующиеся строки в 30+ гиговых файлах и
>проблем не возникло, в процессе работы сжирало около сотни метров памяти.
>В perl не силен, это как получится :)
Так бы сразу сказали, я бы еще в прошлом сообщении привел пример
Исходим из того что все значения в строке разделены пробелом. Тогда имеем
#!/usr/bin/perl
use strict;
my %sums; #хеш для суммирования, ключами будут пары ip, значениями ссыслка на массив из двух элементов [сумма пакетов, сумма байт]
while (<>) { #читаем со стандартного ввода или из файлов переданных в виде аргументов
my @vals = split;#разбиваем строку на элементы
my $k="$vals[0] $vals[1]"; #формируем ключ для хеша конкатенацией пары ip
$sums{$k}->[0] += $vals[2]; #суммируем пакеты
$sums{$k}->[1] += $vals[3]; #суммируем байты
}
print "Results:\n";
print "$_: $sums{$_}->[0] $sums{$_}->[1]\n" foreach (keys %sums) #выводим все пары, при желании можно добавить sort перед keysНу и пример выполнения
$ ./a.pl
1.1.1.1 1.1.1.2 10 15
1.1.1.1 1.1.1.3 10 15
1.1.1.1 1.1.1.2 10 15
1.1.1.2 1.1.1.3 20 20
Results:
1.1.1.2 1.1.1.3: 20 20
1.1.1.1 1.1.1.3: 10 15
1.1.1.1 1.1.1.2: 20 30Возможной проблемой может быть переполнение суммы при превышении предела integer. Тогда можно посмотреть в сторону Math::BigInt или аналогов
а так?
awk '{if ( NF==4 ){ s1[$1"-"$2]+=$3;s2[$1"-"$2]+=$4;}} END {for(k in s1){print k,s1[k],s2[k]}}'
ИМХО от NF'а лучше заранее избавится grep'ом
>а так?
>awk '{if ( NF==4 ){ s1[$1"-"$2]+=$3;s2[$1"-"$2]+=$4;}} END {for(k in s1){print k,s1[k],s2[k]}}'
>ИМХО от NF'а лучше заранее избавится grep'омТак я тоже делал, разницы особой нету. По крайней мере, гиг не переварило.
>Так я тоже делал, разницы особой нету. По крайней мере, гиг не
>переварило."ну тогда незнаю" (C) Народная мудрось
Linux XXXX 2.6.22-3-amd64 #1 SMP Tue Feb 12 09:22:35 UTC 2008 x86_64 GNU/Linuxmawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan
compiled limits:
max NF 32767
sprintf buffer 2040ls -lah aaa.log
-rw-r--r-- 1 pavel pavel 2,2G 2008-02-18 14:23 aaa.logtime cat aaa.log | grep -v "Accounting"|grep -v "Source"| awk '{s1[$1"\t"$2]+=$3;s2[$1"\t"$2]+=$4;} END {for(k in s1){print k,s1[k],s2[k]}}'>aaa.done.log
real 2m11.159s
user 2m3.672s
sys 0m14.169sдаже учитавая то, что файлик aaa.log был создан искусственно (слепил десяток) памяти сожрал всего-то 100M
>Подскажите как сделать иначе или может не на awk даже, чтоб на
>больших объемах не падало.Например, суммировать "частями", потом частичные суммы суммировать.
Или скормить твой гигабайт sort-у :) и суммировать awk-ом с _одой_ суммой единовременно.
Или ещё какой хитрый "дизигн"-подход применить... Например, избавиться от гигабайтных логов совсем.
>>Подскажите как сделать иначе или может не на awk даже, чтоб на
>>больших объемах не падало.
>
>Например, суммировать "частями", потом частичные суммы суммировать.
>Или скормить твой гигабайт sort-у :) и суммировать awk-ом с _одой_ суммой
>единовременно.
>Или ещё какой хитрый "дизигн"-подход применить... Например, избавиться от гигабайтных логов совсем.
>Ага, например сливать не аккаунтинг, а NetFlow, и flow-tools'ами анализировать :)
В общем сделал на perl, как angra советовал (готовый совет не хотелось сразу, хотел сам сделать, в итоге к почти такому и пришел :) ).
900 Мб файлик делал минуты 3-4, оперативки занял 1,6 Гб. На выходе файлик получился 180 Мб.
Спасибо большое всем за наставления ;)
Оставлю пока так, если уж будет совсем тяжко, тогда буду либо делить, либо netflow тот же юзать.
Ничего себе пожирание памяти. Не должно такого происходить. Можете привести код, который использовали?
>Ничего себе пожирание памяти. Не должно такого происходить. Можете привести код, который
>использовали?Оставил Ваш вариант как основной.
Файл 900 мег, 16 млн строк.