Domainnamen aus Zone File parsen

2010-11-27 - kostaki 2 Kommentare »

Seit ein paar Tagen habe ich Zugriff auf die Versign Zone Files und versuche mich im parsen der Domainnamen direkt auf der Command Line. Ich möchte nur die Domainnamen, unique und sortiert haben um sie im Anschluss weiter auswerten zu können. Die Zone Files werden 1x am Tag aktualisiert und per Script herunter geladen. Im ersten Schritt werden alle unnützen Zeichen/Zeilen entfernt, dann wird die Liste sortiert und unique gemacht. Im zweiten Schritt soll eine Liste mit neu dazu gekommenen und entfernt gewordenen Domains erstellt werden. Das ganze soll automatisch laufen und die Resultate sollen direkt in eine MySQL Datenbank geschrieben werden. Hier nun mein Vorgehen um dies zu erreichen.

Teil 1: Vorbereiten der Daten

Als erstes wird das Zone File ein bisschen entschlackt und von unnützen Daten befreit.

$ cat net.zone | wc -l
31.588.624
$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
sed '$d' | \
sort -u > netdomains

real    2m26.329s
user    2m39.694s
sys     0m4.188s

Das funktioniert soweit auch ganz gut, aber um so größer die Datei, umso länger dauert es. Das .net Zone File hat in diesem Fall "gerade mal" 31.588.624 Zeilen. Das .com Zone File schlägt schon mit mehr als 210 Millionen Zeilen zu Buche und die Ausführung dauert hier 19 Minuten. Nun war recht schnell klar was das ganze so langsam macht und das ist das sort -u. Lässt man es weg, läuft das .net Zone File in 30 Sekunden durch und das .com Zone File in unter 6 Minuten. Also habe ich versucht diesen Teil zu optimieren. Um den Overhead zu minimieren, habe ich zum Testen das Resultat ohne sort -u gespeichert und dann weiter bearbeitet. In netdomains2 sind alle Domains unsortiert und nicht unique enthalten. Die Aufgabe ist nun die Namen unique zu bekommen und die Datei zu sortieren. Zu erste der Ausgangspunkt mit sort -u.

$ time cat netdomains2 | sort -u > test1

real    1m53.885s
user    1m52.583s
sys     0m1.156s

$ cat test1 | wc -l
13.502.688

Dann habe ich uniq getestet. Das läuft super schnell wie man sehen kann.

$ time cat netdomains2 | uniq > test2

real    0m4.209s
user    0m3.752s
sys     0m0.548s

$ cat test2 | wc -l
13.503.144

Fügt man nun noch sort an, hat man fast 1 Minute gespart und das gewünschte Ergebnis.

$ time cat netdomains2 | uniq | sort > test3

real    1m3.065s
user    1m2.100s
sys     0m1.252s

cat test3 | wc -l
13.503.144

Es hat nur einen Hacken. Die Zeilen sind nicht wirklich unique, was man an der Anzahl an Zeilen im Result sehen kann. Ich habe leider nicht finden können warum das so ist. Die doppelten Zeilen sehen für mich gleich aus und hätten erkannt werden müssen...
Die Beste Lösung die ich finden konnte ist erst das etwas unsaubere aber schnelle uniq, gefolgt von einem sort -u.

$ time cat netdomains2 | uniq | sort -u > test4

real    1m16.216s
user    1m15.137s
sys     0m1.284s

$ cat test4 | wc -l
13.502.688

Dies läuft immer noch schneller als ein reines sort -u und liefert die gewünschte Anzahl an Zeilen. Hier nochmal alles zusammen und immerhin 41 Sekunden schneller. Beim .com Zone File spart das zusätzliche uniq 5 Minuten 50 Sekunden ein.

$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
uniq | sed '$d' | \
sort -u > netdomains

real    1m45.617s
user    2m4.732s
sys     0m3.944s

*Update*: Uniq und sort zusammen zu verwenden ist leider doch nicht die beste Lösung. Irgend wie werden Zeilen "verschluckt"... Sort -u macht auch was es will und sortiert die Listen nichts immer gleich. Das wiederum gefällt dem diff aber nicht und macht es unbenutzbar. Die Lösung war dann ganz einfach. Vor dem sort Aufruf setzt man die Locale neu, was die Ausführungszeit verringert und das Gewünschte Ergebnis liefert (denke ich jedenfalls, die letzten 4 Tage funktioniert alles wie es soll).

$ export LC_ALL=C
$ time cat netdomains2 | sort -u > test5

real    0m32.880s
user    0m30.830s
sys     0m1.012s

und nochmal alles zusammen:

$ export LC_ALL=C
$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
sed '$d' | \
sort -u > netdomains

real    1m44.563s
user    1m39.434s
sys     0m9.677s

Teil 2: Neue und gelöschte Domains finden

In netdomains hat man nun alle Domainnamen unique und sortiert und man kann sie mit der Datei vom gestriegen Tage vergleichen. Zur Verdeutlichung heißen die Dateien jetzt gestern und heute.

$ time diff gestern heute | grep '^[<>]' > change

real    0m5.597s
user    0m5.068s
sys     0m0.528s

$ cat change | wc -l
42.045

Das Resultat ist schon sehr gut (< fehlt in heute, ist also gelöscht worden, > fehlt in gestern, ist also neu). Jetzt muss man es nur noch in neu und entfernt teilen.

$ cat change | grep '^<' | awk 'split($2, x, / /) {print x[1]}' > entfernt
$ cat entfernt | wc -l
19.241
$ cat change | grep '^>' | awk 'split($2, x, / /) {print x[1]}' > neu
$ cat neu | wc -l
22.804

Teil 3: Resultate in MySQL importieren

Abschließend möchte ich die Daten noch in eine MySQL Datenbank schreiben. Dafür bietet sich LOAD DATA INFILE an, da es sehr schnell ist. Als Beispiel benutze ich die unique und sortierte Liste mit immerhin 13 Millionen Einträgen.

# die Tabelle net in tmp hat nur 1 Feld und keine Keys
$ time mysql -e "LOAD DATA LOCAL INFILE './heute' INTO TABLE net" tmp

real    0m4.551s
user    0m0.032s
sys     0m0.076s

Hat man einen Key auf der Tabelle, dann kann sich ein REPAIR TABLE lohnen, da dieser danach sehr viel kleiner wird.

Fazit

Wenn man die Befehle nun alle in ein Script Packt, erreicht man das gewünschte Ergebnis.

Ähnliche Artikel

  1. 2 Kommentare

  2. Christian
    schrieb am 05.07.2011 um 22:42 Uhr

    Hast du zufällig ein Script fertig, welches den Downloadprozess und evtl. auch schon das parsen automatisch durchführt?

    Ich scheitere irgendwie gerade daran die Dateien automatisch herunterzuladen, weil er immer die Verbindung abbricht. Hab es schon mit wget und curlftpfs + rsync versucht und drehe langsam echt durch weil es nicht funktioniert ;-)

  3. kostaki
    schrieb am 06.07.2011 um 07:54 Uhr

    Ja die Probleme habe ich auch… Immer bei info und org, alles andere funktioniert normal.

    Ich benutze ncftpget, setze hier einen Timeout von 45 Sekunden und rufe es einfach mehrmals auf mit einem sleep dazwischen. Ist die Datei nicht vollständig, lädt er weiter. Ist die Datei komplett, überspringt er den Download. Läuft seit gut 6 Tagen problemlos.

Kommentar schreiben

*

*