Удалить дубликаты из большого файла

У меня есть CSV-файл ~ 20 ГБ. Образец файла:

1,[email protected],M
2,[email protected],M
1,[email protected],F
3,[email protected],F

Первичным ключом в этом файле является первый столбец. Мне нужно написать два файла, uniq.csv и дубликаты.csv

uniq.csv должен содержать все неповторяющиеся записи, а duplicas.csv будет содержать все повторяющиеся записи с текущей отметкой времени.

uniq.csv

1,[email protected],M
2,[email protected],M
3,[email protected],F

дубликаты.csv

2012-06-29 01:53:31 PM, 1,[email protected],F

Я использую Unix Sort, чтобы воспользоваться его алгоритмом сортировки слиянием External R-Way.

To identify uniq records
tail -n+2 data.txt | sort -t, -k1 -un > uniq.csv

To identify duplicate records
awk 'x[$1]++' FS="," data.txt | awk '{print d,$1}' "d=$(date +'%F %r')," > duplicates.csv

Мне было интересно, можно ли найти как дубликаты, так и uniq за одно сканирование этого большого файла?


person KarthikRajagopal    schedule 19.06.2012    source источник


Ответы (3)


Ваш awk сценарий почти готов. Чтобы найти уникальные строки, вам просто нужно использовать оператор in, чтобы проверить, находится ли запись в ассоциированном массиве или нет. Это позволяет собирать данные за один проход через файл данных и избежать необходимости вызова sort.

tail -n +2 data.txt | \
awk '
    BEGIN { OFS=FS="," }
    {
        if (!($1 in x)) {
            print $0 > "/dev/fd/3"
        }
        x[$1]++
    }
    END {
        for (t in x) {
            print d, t, x[t]
        }
    }' d="$(date +'%F %r')" 3> uniq.csv > duplicates.csv
person Jules Reid    schedule 01.07.2012

Я получил этот вопрос в интервью, пару рабочих мест назад.

Один из ответов — использовать uniq с опцией «-c» (количество). Запись со значением «1» уникальна и в противном случае не уникальна.

сортировать фу | уникальный -c | awk '{ if ($1 == 1) { запись-в-уникальный} else {запись-в-дубликат}'

Если вы хотите написать программу специального назначения и/или избежать задержки, вызванной сортировкой, я бы использовал Python.

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

Кажется, вам не нужен отсортированный вывод, а только категоризированный вывод, поэтому хеширование должно быть быстрее. Построение хэша - это O (1), а сортировка - O (я забыл, unix sort Nlog (N)?)

person Bill Torcaso    schedule 19.06.2012
comment
Создание хеша будет слишком интенсивно использовать память, не так ли? - person KarthikRajagopal; 20.06.2012

Вот код на perl, который сделает обработку за одно сканирование

#!/usr/bin/perl
open(FI,"sort -t, -k1 < file.txt |");
open(FD,">duplicates.txt");
open(FU,">uniques.txt");
my @prev;
while(<FI>)
{
    my (@cur) = split(',');
    if($prev[0] && $prev[0]==$cur[0])
    {
        print FD localtime()." $_";
    }
    else
    {
        print FU $_;
    }
    @prev=@cur;
}
person amaksr    schedule 19.06.2012