Поиск больших файлов CSV с несколькими критериями поиска в Unix - PullRequest
2 голосов
/ 24 июля 2011

У меня есть несколько больших CSV-файлов, которые мне нужно искать с 1 по многим параметрам, если я обнаружу попадание, мне нужно сохранить эту строку в другом файле.Ниже приведен пример кода на Perl, который успешно выполняется, но очень медленно работает с файлом 5 ГБ.Будем весьма благодарны за любые предложения по ускорению этого.

#!/usr/bin/env perl
use Text::CSV_XS;

$numArgs = $#ARGV;

#First Parameter is the input file name
$Finput = $ARGV[0];
chomp($Finput);

#Second Parameter is the output file name
$Foutput = $ARGV[1];
chomp($Foutput);

# Open the Control file but quit if it doesn't exist
open(INPUT1, $Finput) or die "The Input File $Finput could not be found.\n";
open(OUTPUT1, ">$Foutput") or die "Cannot open output $Foutout file.\n";


my $csv = Text::CSV_XS->new();
open my $FH, "<", $Finput;

while (<$FH>) {
    $csv->parse($_);
    my @fields = $csv->fields;

    if ($fields[0] == 10000) {
        if ($fields[34] eq 'abcdef') {
            if ($fields[103] == 9999) {
                print OUTPUT1 "$_\n";
            }
        }
    }
}

Ответы [ 3 ]

3 голосов
/ 24 июля 2011

Это код, который работает "успешно"? Мне трудно в это поверить.

if ($fields[0] = 10000) {
    if ($fields[34] = 'abcdef') {
        if ($fields[103] = 9999) {

Это не проверки на равенство, а задания. Все эти if-предложения всегда будут возвращать true. То, что вы, вероятно, хотели здесь, было == и eq, а не =.

Вы также открываете два файловых дескриптора во входном файле и неправильно используете модуль CSV. Я не уверен, что эти незначительные ошибки должны вызывать слишком медленный сценарий, но он будет печатать все записи в этом файле 5 ГБ.

Вот пересмотренная версия вашего сценария.

use strict;
use warnings;
use Text::CSV;
use autodie;

my $Finput = $ARGV[0];
my $Foutput = $ARGV[1];

open my $FH, "<", $Finput;
open my $out, ">", $Foutput;

my $csv = Text::CSV->new();

while (my $row = $csv->getline($FH)) {
    my @fields = @$row;
    if ($fields[0] == 10000) {
        if ($fields[34] eq 'abcdef') {
            if ($fields[103] == 9999) {
                $csv->print($out, $row);
            }
        }
    }
}

Прагма autodie позаботится о проверке возвращаемого значения из open для нас (и других вещей). use strict; use warnings; заставит наш мозг болеть меньше. О, и я использую Text :: CSV , а не версию _XS.

3 голосов
/ 24 июля 2011

Я не знаю ваших данных или ваших критериев.

Но если бы мы могли использовать ваш пример, приведенный выше, то я бы попробовал тривиальные тесты со строками ДО того, как выполнить обработку CSV.

Например (обратите внимание, мой Perl ужасен, это должно быть примером, а не правильно):

if (/.*10000.*abcdef.*9999.*/) {
    $csv->parse($_);
    if ($fields[0] = 10000) {
        ...
    }
}

По сути, вы делаете несколько более простых и быстрых проверок, чтобы быстрее ОТКЛЮЧИТЬ строки перед выполнением дополнительной обработки, необходимой для их квалификации.

Очевидно, что если больше строк совпадают, чем нет, или если проверка простой квалификации не очень практична, то этот метод не сработает.

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

Итак, хорошо, что вам не придется платить цену за его разбор, если, "с первого взгляда", строка все равно не будет совпадать.

1 голос
/ 24 июля 2011

Вы хотите использовать grep "{searchstring}" filename1.csv filename2.csv> savefile.txt в каждом файле. Может быть, вы хотите прочитать файл filename.csv построчно:

#!/bin/bash
exec 3<filename.csv
while read haystack <&3
do
  grep "{needle}" $haystack > result.txt 
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...