Perl: «проблема с шумными журналами» Создание массива запросов регулярных выражений из нескольких массивов / хэшей - PullRequest
0 голосов
/ 12 ноября 2010

Проблема: Мне нужно получить данные из журналов авторизации в течение ок. 30 локаций. Журналы в формате CSV. Чтобы анализ был полезным, записи в журнале должны соответствовать часам работы мест. Данные хранятся в каталогах, названных для периода времени, который охватывает данные: например, data / june1-june30 /. Файлы CSV просто названы с кодом местоположения например, LOC1.csv, LOC2.csv. Вот пример типичного журнала:

2010-06-01, 08:30:00 , 0
2010-06-01, 09:30:00 , 1
2010-06-01, 10:30:00 , 10
2010-06-01, 11:30:00 , 7
2010-06-01, 12:30:00 , 8
2010-06-01, 13:30:00 , 6
2010-06-01, 14:30:00 , 3
2010-06-01, 15:30:00 , 8
2010-06-01, 16:30:00 , 11

Записи показывают количество успешных аутентифицированных сеансов за период времени, указанный в 3-м поле. Журналы представляют данные за 24 часа, которые бесполезны для анализа, поскольку часы работы отличаются от места к месту. Теперь проблема заключается в том, как получить только те данные, которые соответствуют часам работы. Анализ должен показать активность за часы работы, чтобы быть полезными.

Настройка - пока что Я решил создать файл конфигурации, используя YAML с массивами / хэшами для каждого местоположения.

напр.,

- branch: headquarters
  abbrev: HQ
  months: [04, 06]
  DOW: [M, T, W, Th]
  hours:
      M:                [12, 13, 14, 15, 16, 17, 18]
      T:                [12, 13, 14, 15, 16, 17, 18]
      W:        [09, 10, 11, 12, 13, 14, 15, 
                         16, 17, 18]
      Th:       [12, 13, 14, 15, 16, 17, 18,
                         19, 20]

Обозначение месяцев показывает самые загруженные месяцы, так как это все, что нас волнует.

Где я нахожусь Код найдет соответствующие каталоги с помощью массива месяцев, а затем извлечет правильные файлы CSV с помощью массива abbrev. Итак, у меня есть файлы, которые мне нужны, хранящиеся в массиве @files. Мой вопрос сводится к дизайну. Результаты должны соответствовать соответствующим датам каждого месяца. Понедельник, вторник ... и т. Д. Создаю ли я месячные массивы, хранящие даты для каждого дня недели? Я застрял и не уверен, куда идти отсюда.

уточнить: код уже тянет правильный файлы и загружает их в массив (используя globbing и Find :: File) для каждой ветви. Теперь вопрос об итерации массива @files для каждой ветви и извлечении информации.

EDIT: согласно запросу: я поставлю код. Это товары для хранения этих файлов по месяцам, указанным в хеше. Это легкая часть.

foreach my $branch (@$config) {
        my $name = $branch->{'branch'};
        my $months = $branch->{'months'};
        my $abbrev = $branch->{'abbrev'};

        # find directories for busy months, load in @dirs
        my @dirs;       
        foreach my $month (@$months) {
                my $regex2 = qr(stats_2010-$month.*);
                map { push(@dirs, $_) if $_ =~ $regex2 } @stats_dir;
        }

        # find csv files within directories, load in @files
        my @files;
        find(\&wanted, @dirs);
        sub wanted {
                push(@files, $_) if $_ =~ /$abbrev\.csv/;
        }

Выход: Вывод, который я надеюсь получить: Строки из каждого файла, представляющие часы работы для этой ветви. Я думаю, что они могут быть выведены в отдельный файл для простоты. И в том же формате. Что затрудняет то, что вы должны соответствовать понедельникам, вторникам .. и т. Д. с датами как-то. Это связано с разными часами работы в разные дни.

Я делаю проблему сложнее, чем нужно? Я сидел с этим слишком долго, и я надеюсь, что свежий взгляд поможет мне выпрямиться. Мой Perl в порядке, но мне нужна помощь в отделе дизайна / алгоритма. Думаю, я могу понять, как это сделать. Но не стесняйтесь размещать Perl. Я люблю читать хорошие Perl!

Со временем я буду усреднять активность по понедельникам, вторникам и т. Д. каждого месяца.

Спасибо ~

Bubnoff

Ответы [ 3 ]

1 голос
/ 13 ноября 2010

Я использую решение от dlamblin (еще раз спасибо за вашу помощь !!).

Вот настроенная конфигурация YAML:

- branch: Headquarters
  abbrev: HQ
  months: [04, 06]
  DOW:
      1:    {12: 1, 13: 1, 14: 1, 15: 1,
            16: 1, 17: 1, 18: 1}
      2:    {12: 2, 13: 2, 14: 2, 15: 2,
            16: 2, 17: 2, 18: 2}
      3:    {09: 3, 10: 3, 11: 3, 12: 3,
            13: 3, 14: 3, 15: 3, 16: 3, 17: 3, 18: 3}
      4:    {12: 4, 13: 4, 14: 4, 15: 4, 16: 4,
            17: 4, 18: 4, 19: 4, 20: 4}

Вот Perl:

foreach my $dir (@dirs) {
    my $file = qq($dir/$abbrev.csv);
    open(F, $file);
    my @data=<F>;
    foreach my $line (@data) {
        chomp($line);
        unless ($line =~ m/^(\d+)-(\d+)-(\d+), (\d+):(\d+):(\d+) , (\d+)/){next;}
        my $dt = DateTime->new( year    => $1,
                                month  => $2,
                                day    => $3,
                                hour   => $4,
                                minute => $5,
                                second => $6,
                                );
         my $count = $7;
         if (exists $DOW{$dt->day_of_week} && exists $DOW{$dt->day_of_week}{$dt->hour}) {
             print $line . "\n";
         }
     }
     close(F);
}
0 голосов
/ 12 ноября 2010

Преобразуйте день недели в число, когда понедельник равен 1, а воскресенье - 7. Затем создайте хэш, который выглядит как 1=>{12=>1,13=>1,14=>1,15=>1,16=>1,17=>1,18=>1},2=>{12=>1,13=>1,14=>1,15=>1,16=>1,17=>1,18=>1},... (обратите внимание, что DOW в вашем YAML избыточен).

пока:

use DateTime;
foreach $file (@files) {
  open F "<$file";
  foreach $line (<F>) {
    $line =~ m/^(\d+)-(\d+)-(\d+), (\d+):(\d+):(\d+) , (\d+)/;
    $dt = DateTime->new( year   => $1,
                         month  => $2,
                         day    => $3,
                         hour   => $4,
                         minute => $5,
                         second => $6,
                       );
    $count = $7; #Possibly redundant; Use it if you're aggregating.
    if (exits $selection{$dt->day_of_week}
     && exists $selection{$dt->day_of_week}{$dt->hour}) {
      print $line;
    }
  }
}
0 голосов
/ 12 ноября 2010

Существуют модули, которые сообщат вам дату и время, но если они слишком тяжелые, вы можете use Time::Local. Проанализируйте дату - в любом случае, я думаю, вы должны будете это сделать - в каждой строке и введите ее через timelocal, а затем через localtime, что даст вам индекс Доу. Вам нужно будет помассировать $ mon и $ year соответственно.

$dow = ( localtime( timelocal( 0, 0, 0, $mday, $mon, $year ) ) )[6];

Как только вы поймете, что делать с этим, вы будете знать, что с ним делать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...