Поиск в больших файлах CSV - PullRequest
0 голосов
/ 29 мая 2018

Проблема

У меня есть тысячи CSV-файлов в папке.Каждый файл имеет 128 000 записей с четырьмя столбцами в каждой строке.Время от времени (два раза в день) мне нужно сравнивать список (10 000 записей) со всеми CSV-файлами.Если одна из записей совпадает с третьим или четвертым столбцом одного из файлов CSV, мне нужно записать всю строку CSV в дополнительный файл.

Возможные решения

Grep

#!/bin/bash
getArray() {
    array=()
    while IFS= read -r line
    do
        array+=("$line")
    done < "$1"
}

getArray "entries.log"
for e in "${array[@]}"
do
    echo "$e"
    /bin/grep $e ./csv/* >> found
done

Кажется, это работает, но это длится вечно.После почти 48 часов скрипт проверил только 48 записей из примерно 10 000.

MySQL

Следующая попытка состояла в том, чтобы импортировать все файлы csv в базу данных mysql.Но там у меня были проблемы с моей таблицей на 50 000 000 записей.Поэтому я написал скрипт, который создал новую таблицу после 49 000 000 записей, и я смог импортировать все CSV-файлы.Я пытался создать индекс для второго столбца, но он всегда терпел неудачу (тайм-аут).Создать индекс до процесса импорта тоже было невозможно.Это замедлило импорт до нескольких дней вместо нескольких часов.Выбранное заявление было ужасно, но оно сработало.Гораздо быстрее, чем решение "grep", но все еще медленно.

Мой вопрос

Что еще я могу попытаться найти в файлах csv?Чтобы ускорить процесс, я скопировал все CSV-файлы в SSD.Но я надеюсь, что есть и другие способы.

Ответы [ 3 ]

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

Вы можете создать файл шаблонов, а затем использовать xargs и grep -Ef для поиска всех шаблонов в пакетах CSV-файлов, а не по одному шаблону за раз, как в текущем решении:

# prepare patterns file
while read -r line; do
  printf '%s\n' "^[^,]+,[^,]+,$line,[^,]+$"       # find value in third column
  printf '%s\n' "^[^,]+,[^,]+,[^,]+,$line$"       # find value in fourth column
done < entries.log > patterns.dat

find /path/to/csv -type f -name '*.csv' -print0 | xargs -0 grep -hEf patterns.dat > found.dat
  • find ... - выдает список всех найденных CSV-файлов, разделенных NUL
  • xargs -0 ... - передает список файлов в grep, в пакетном режиме
0 голосов
/ 29 мая 2018

В awk при условии изменения всех файлов csv, в противном случае было бы целесообразно отслеживать уже проверенные файлы.Но сначала несколько тестовых материалов:

$ mkdir test        # the csvs go here
$ cat > test/file1  # has a match in 3rd
not not this not
$ cat > test/file2  # no match
not not not not
$ cat > test/file3  # has a match in 4th
not not not that
$ cat > list        # these we look for
this
that

Затем скрипт:

$ awk 'NR==FNR{a[$1];next} ($3 in a) || ($4 in a){print >> "out"}' list test/*
$ cat out
not not this not
not not not that

Объяснил:

$ awk '                   # awk
NR==FNR {                 # process the list file
    a[$1]                 # hash list entries to a
    next                  # next list item
} 
($3 in a) || ($4 in a) {  # if 3rd or 4th field entry in hash
    print >> "out"        # append whole record to file "out"
}' list test/*            # first list then the rest of the files

Скрипт хэширует все записи списка в aи читает через csv-файлы, ища записи 3-го и 4-го полей в хэше, выводя их при совпадении.

Если вы проверите его, дайте мне знать, как долго он работал.

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

Это вряд ли даст вам ощутимые преимущества, но некоторые улучшения в вашем скрипте

  1. используют встроенный mapfile для преобразования файла в массив:

    mapfile -t array < entries.log
    
  2. использовать grep с файлом шаблонов и соответствующими флагами.

    Я предполагаю, что вы хотите сопоставлять элементы в entry.log как фиксированные строки, а не как шаблоны регулярных выражений.
    Я также предполагаю, что вы хотите сопоставить целые слова.

    grep -Fwf entries.log ./csv/*
    

    Это означает, что вам не нужно выполнять поиск 1000 файлов csv 1000 раз (один раз для каждого элемента в entry.log).На самом деле, одно это должно дать вам реальное значимое улучшение производительности.

    Это также устраняет необходимость считывать entry.log в массив вообще.

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