Более быстрый способ создания файла от конца до начала? - PullRequest
0 голосов
/ 14 мая 2018

Я хочу получить результаты, начиная с конца файла и продвигаясь до самого начала. Я попытался использовать tac и передать это в мою команду awk, но это очень медленно (15 секунд для файла 2 ГБ). По сравнению с обычным поиском (3 секунды для одного и того же файла). Я также добавляю команду awk в tail -n +1 | head -n 50 для остановки после 50 результатов.

Есть ли более быстрый способ tac файла? или хотя бы начать поиск снизу вверх?

Общая картина заключается в создании сценария Python, который принимает аргументы (дата начала, дата окончания, условия поиска) и использует их для поиска в файле журнала, организованном по дате. Возврат 50 результатов за раз.

Мне нужно читать от начала к началу, если пользователь хочет искать в порядке убывания (от самой новой даты к самой старой дате).

Пример команды для возрастания результатов («от самого старого до самого нового»): (я использую find, потому что это заданный пользователем аргумент, он может ссылаться на все файлы (* .txt))

  • Дата начала: 2018-03-04T03: 45
  • Дата окончания: 2018-03-05T16: 24
  • Термин поиска: картофель

find '/home/logs/' -type f -name 'log_file.txt' -exec cat {} \+ 2>&1| LANC=C fgrep 'Potato' | LC_ALL=C IGNORECASE=1 awk -v start="2018-03-04T03:45:00" -v stop="2018-03-05T16:24:59" 'BEGIN{IGNORECASE=1;} {line=$0; xz=" "; for(i=4;i<=NF;i++){xz=xz" "$i};} ($1>=start&&$1<=stop) && (tolower(xz) ~ /Potato/) {print line}' | tail -n +1 | head -n 50

tail -n +1 | head -n 50 - вернуть первые 50 совпадений.

Эта команда занимает около 3-4 секунд, чтобы найти результаты, однако, если я сдам в TAC, это займет около 20 секунд.

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Все немного зависит от имеющегося у вас кода awk, но на ум приходят следующие решения:

  • , если вы печатаете каждую строку:

    tac <file> | awk '(NR > 50){exit}{do-your-stuff}'
    
  • , если вы печатаете только несколько строк с awk

    tac <file> | awk '(c > 50){exit} 
                      { do-part-of stuff;
                        print foobar; c++;
                        do-remaining part}'
    

Оба решения заканчиваются awk после первых 50 напечатанных строк.Таким образом, вам не нужно обрабатывать полный файл 2 ГБ.Окончание после 50 напечатанных строк имитирует tail -n +1 | head -n 50

0 голосов
/ 14 мая 2018

Гораздо быстрее, чтобы открыть файл, и искать до некоторой суммы до конца файла. Perl удобен здесь:

perl -Mautodie -se '
    $size = -s $file;
    $blocksize = 64000;
    open $fh, "<", $file;
    seek $fh, $size - $blocksize, 0;
    read $fh, $data, $blocksize;
    @lines = split "\n", $data;
    # last 50 lines
    print join "\n", reverse @lines[-51..-1];
' -- -file="filename"

Мы можем запустить цикл таким образом, чтобы после чтения последнего блока он мог искать до конца минус 2 блока и читать блок и т. Д.

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

0 голосов
/ 14 мая 2018

Что ж, если у вас есть память, хешируйте записи и обрабатывайте их в обратном порядке в секции END:

$ for i in {a..e} ; do echo $i ; done |   
  awk '{ a[NR]=$0 }       # hash to a, NR as key
  END {                   # in the end
      for(i=NR;i>=1;i--)  # process a in descending order
          c++             # process
      print c
}'
5

Обновление : я тестировал выше с файлом 1 ГБ (36М записей).Он хэшировался и считал за 1 минуту и ​​занимал около 4,5 ГБ памяти.

...