Большой объем запросов в большом файле CSV - PullRequest
0 голосов
/ 03 июля 2019

Я пытаюсь запросить большой файл CSV (100 ГБ, + - 1,1 миллиарда записей) для частичных совпадений в столбце URL CSV. Я стремлюсь запросить около 23000 возможных совпадений.

Пример ввода:

url,answer,rrClass,rrType,tlp,firstSeenTimestamp,lastSeenTimestamp,minimumTTLSec,maximumTTLSec,count
maps.google.com.,173.194.112.106,in,a,white,1442011301000,1442011334000,300,300,2
drive.google.com.,173.194.112.107,in,a,white,1442011301000,1442011334000,300,300,2
nokiantires.com.,185.53.179.22,in,a,white,1529534626596,1529534626596,600,600,1
woodpapersilk.,138.201.32.142,in,a,white,1546339972354,1553285334535,3886,14399,2
xn--c1yn36f.cn.,167.160.174.76,in,a,white,1501685257255,1515592226520,14400,14400,38
maps.google.com.malwaredomain.com.,118.193.165.236,in,a,white,1442148766000,1442148766000,600,600,1
whois.ducmates.blogspot.com.,216.58.194.193,in,a,white,1535969280784,1535969280784,44,44,1

Запросы имеют следующий шаблон: /^.*[someurl].*$/ каждый из этих [someurls] поступает из другого файла и может быть принят как массив размером 23000.

Соответствующих запросов:

awk -F, '$1 ~ /^.*google\.com\.$/' > file1.out awk -F, '$1 ~ /^.*nokiantires\.com\.$/' > file2.out awk -F, '$1 ~ /^.*woodpapersilk\.com\.$/' > file3.out awk -F, '$1 ~ /^.*xn--.*$/' > file4.out

Запросы, которые ничего не соответствуют:

awk -F, '$1 ~ /^.*seasonvintage\.com\.$/' > file5.out awk -F, '$1 ~ /^.*java2s\.com\.$/' > file6.out

file1.out:

maps.google.com.,173.194.112.106,in,a,white,1442011301000,1442011334000,300,300,2
drive.google.com.,173.194.112.107,in,a,white,1442011301000,1442011334000,300,300,2

file2.out:

nokiantires.com.,185.53.179.22,in,a,white,1529534626596,1529534626596,600,600,1

file3.out:

woodpapersilk.,138.201.32.142,in,a,white,1546339972354,1553285334535,3886,14399,2

file4.out:

xn--c1yn36f.cn.,167.160.174.76,in,a,white,1501685257255,1515592226520,14400,14400,38

file 5.out и file6.out оба пусты, так как ничего не совпадает Я также загрузил эти входы и выходы как gist .

По сути, каждый запрос извлекает частичное совпадение в столбце url.

В настоящее время я использую следующий код с awk для поиска возможных совпадений:

awk -F, '$1 ~ /^.*xn--.*$/' file.out > filter.csv

Это решение возвращает действительный ответ, но запрос одного примера занимает 14 минут. К сожалению, я ищу запрос на 23000 возможных совпадений.

Поэтому я ищу более работоспособное и эффективное решение.

Я подумал / попробовал следующее

  1. Могу ли я включить все теги в огромное регулярное выражение или это увеличивает неэффективность?
  2. Я пытался использовать MongoDB, но он плохо работает только с одной машиной.
  3. У меня есть ваучер AWS, на котором осталось около 30 долларов. Есть ли какое-то конкретное решение AWS, которое могло бы помочь здесь?

Что было бы более приемлемым решением для обработки этих запросов в указанном CSV-файле?

Большое спасибо

1 Ответ

1 голос
/ 04 июля 2019

Учитывая то, что мы знаем до сих пор и догадываясь об ответах на пару вопросов, я подхожу к этому, разделяя запросы на «запросы, которые могут быть сопоставлены поиском по хешу» (то есть все, кроме 1 запроса). в вашем опубликованном примере) и «запросы, для сравнения которых требуется сравнение регулярных выражений» (просто xn--.*$ в вашем примере), а затем оценивают их как таковые при чтении ваших записей, чтобы любой 1 доллар, который может быть сопоставлен почти мгновенным поиском хеша с все хеш-запросы будут выполняться так, и только те немногие, которым необходимо соответствие регулярному выражению, будут обрабатываться последовательно в цикле:

$ cat ../queries
google.com.$
nokiantires.com.$
woodpapersilk.com.$
xn--.*$
seasonvintage.com.$
java2s.com.$

$ cat ../records
url,answer,rrClass,rrType,tlp,firstSeenTimestamp,lastSeenTimestamp,minimumTTLSec,maximumTTLSec,count
maps.google.com.,173.194.112.106,in,a,white,1442011301000,1442011334000,300,300,2
drive.google.com.,173.194.112.107,in,a,white,1442011301000,1442011334000,300,300,2
nokiantires.com.,185.53.179.22,in,a,white,1529534626596,1529534626596,600,600,1
woodpapersilk.,138.201.32.142,in,a,white,1546339972354,1553285334535,3886,14399,2
xn--c1yn36f.cn.,167.160.174.76,in,a,white,1501685257255,1515592226520,14400,14400,38
maps.google.com.malwaredomain.com.,118.193.165.236,in,a,white,1442148766000,1442148766000,600,600,1
whois.ducmates.blogspot.com.,216.58.194.193,in,a,white,1535969280784,1535969280784,44,44,1

.

$ cat ../tst.awk
BEGIN { FS="," }
NR==FNR {
    query = $0
    outFile = "file" ++numQueries ".out"
    printf "" > outFile; close(outFile)
    if ( query ~ /^[^.]+[.][^.]+[.][$]$/ ) {
        # simple end of field string, can be hash matched
        queriesHash[query] = outFile
    }
    else {
        # not a simple end of field string, must be regexp matched
        queriesRes[query] = outFile
    }
    next
}
FNR>1 {
    matchQuery = ""
    if ( match($1,/[^.]+[.][^.]+[.]$/) ) {
        fldKey = substr($1,RSTART,RLENGTH) "$"
        if ( fldKey in queriesHash ) {
            matchType  = "hash"
            matchQuery = fldKey
            outFile    = queriesHash[matchQuery]
        }
    }
    if ( matchQuery == "" ) {
        for ( query in queriesRes ) {
            if ( $1 ~ query ) {
                matchType  = "regexp"
                matchQuery = query
                outFile    = queriesRes[matchQuery]
                break
            }
        }
    }
    if ( matchQuery != "" ) {
        print "matched:", matchType, matchQuery, $0, ">>", outFile | "cat>&2"
        print >> outFile; close(outFile)
    }
}

.

$ ls
$
$ tail -n +1 *
tail: cannot open '*' for reading: No such file or directory

.

$ awk -f ../tst.awk ../queries ../records
matched: hash google.com.$ maps.google.com.,173.194.112.106,in,a,white,1442011301000,1442011334000,300,300,2 >> file1.out
matched: hash google.com.$ drive.google.com.,173.194.112.107,in,a,white,1442011301000,1442011334000,300,300,2 >> file1.out
matched: hash nokiantires.com.$ nokiantires.com.,185.53.179.22,in,a,white,1529534626596,1529534626596,600,600,1 >> file2.out
matched: regexp xn--.*$ xn--c1yn36f.cn.,167.160.174.76,in,a,white,1501685257255,1515592226520,14400,14400,38 >> file4.out

.

$ ls
file1.out  file2.out  file3.out  file4.out  file5.out  file6.out
$
$ tail -n +1 *
==> file1.out <==
maps.google.com.,173.194.112.106,in,a,white,1442011301000,1442011334000,300,300,2
drive.google.com.,173.194.112.107,in,a,white,1442011301000,1442011334000,300,300,2

==> file2.out <==
nokiantires.com.,185.53.179.22,in,a,white,1529534626596,1529534626596,600,600,1

==> file3.out <==

==> file4.out <==
xn--c1yn36f.cn.,167.160.174.76,in,a,white,1501685257255,1515592226520,14400,14400,38

==> file5.out <==

==> file6.out <==
$

Первоначальный printf "" > outFile; close(outFile) предназначен только для того, чтобы обеспечить получение выходного файла для каждого запроса, даже если этот запрос не совпадает, как вы и просили в своем примере.

Если вы используете GNU awk, тогда он может управлять несколькими открытыми выходными файлами для вас, а затем вы можете внести следующие изменения:

  1. printf "" > outFile; close(outFile) -> printf "" > outFile
  2. print >> outFile; close(outFile) -> print > outFile

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

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