Fast, zeilenweise "grep -n" entspricht der Unix-Verzeichnisstruktur

8

Ich versuche eine Webschnittstelle zu erstellen, um eine große Anzahl von riesigen Konfigurationsdateien zu durchsuchen (ca. 60000 Dateien, jede mit einer Größe zwischen 20 KByte und 50 MByte). Diese Dateien werden auch häufig aktualisiert (~ 3 mal / Tag).

Anforderungen:

  • Parallelität
  • Muss die Zeilennummern für jede übereinstimmende Zeile identifizieren
  • Gute Update-Leistung

Was ich untersucht habe:

  • Lucene : Um eine Zeilennummer zu identifizieren, muss jede Zeile in einem separaten Lucene-Dokument gespeichert werden, das jeweils zwei Felder enthält (die Zeilennummer und die Zeile). Dies macht Updates schwer / langsam.
  • SOLR und Sphinx : Beide basieren auf Lucene und haben das gleiche Problem und erlauben keine Identifizierung der Zeilennummer.
  • SQL-Tabelle mit einem Volltextindex : Auch hier gibt es keine Möglichkeit, die Zeilennummer anzuzeigen.
  • SQL-Tabelle mit jeder Zeile in einer separaten Zeile : Getestet mit SQLite oder MySQL, und Update-Leistung war die schlechteste aller Optionen. Die Aktualisierung eines 50 MB-Dokuments dauerte mehr als eine Stunde.
  • eXist-db : Wir haben jede Textdatei wie folgt in XML konvertiert: <xml><line number="1">test</line>...</xml> . Updates dauern ~ 5 Minuten, was etwas funktioniert, aber wir sind immer noch nicht zufrieden damit.
  • Whoosh für Python: So ähnlich wie Lucene. Ich habe einen Prototyp implementiert, der so funktioniert, dass alle Zeilen einer Datei gelöscht oder neu importiert werden. Die Aktualisierung eines 50-MB-Dokuments dauert mit dieser Methode ca. 2-3 Minuten.
  • GNU id utils : Vorgeschlagen von sarnold, das ist blitzschnell (50MB Dokument wird in weniger als 10 Sekunden auf meinem Testgerät aktualisiert) und wäre perfekt, wenn es Seitenumbruch und eine API hätte.

Wie würden Sie eine Alternative implementieren?

    
knipknap 14.11.2011, 11:50
quelle

2 Antworten

5

Vielleicht möchten Sie das GNU idutils Toolkit untersuchen. Auf einer lokalen Kopie der Linux-Kernel-Quellen kann eine Ausgabe wie folgt ausgegeben werden:

%Vor%

Der Index von einem Cold Cache wird relativ schnell wiederhergestellt:

%Vor%

Der Index von einem warmen Cache wird viel schneller neu erstellt:

%Vor%

Der Index benötigt nur 46 Megabyte für meine 2,1 Gigs an Daten - das ist zwar winzig im Vergleich zu Ihnen, aber das Verhältnis ist gut.

Das Finden von 399 Vorkommen von foo dauerte nur 0.039 Sekunden:

%Vor%

Aktualisieren

Larsmans war neugierig auf die Leistung von git grep auf den Kernel-Quellen - das ist eine hervorragende Möglichkeit, um zu zeigen, wie viel Leistungssteigerung gid(1) bietet.

In einem kalten Cache git grep foo (der 1656 Einträge zurückgab, weit mehr als idutils):

%Vor%

Sobald der Cache warm war, läuft git grep foo viel schneller:

%Vor%

Da mein Dataset vollständig in den Arbeitsspeicher passt, sobald der Cache warm ist, ist git grep ziemlich erstaunlich: Es ist nur sieben Mal langsamer als das Dienstprogramm gid(1) und sicherlich wäre es mehr als schnell genug für die interaktive Nutzung. Wenn der fragliche Datensatz nicht vollständig zwischengespeichert werden kann (was wahrscheinlich daran liegt, dass die Dinge tatsächlich interessant werden), ist der Leistungsvorteil des Index unverkennbar.

Die zwei Beschwerden über idutils:

  1. Keine Seitennummerierung. Dies ist definitiv ein Nachteil, obwohl es meiner Erfahrung nach schnell genug läuft, um die Ergebnisse der Suche einfach an anderer Stelle zu speichern. Wenn die Suche einen nennenswerten Prozentsatz des ursprünglichen Datensatzes zurückgibt, wird die Speicherung von Teilergebnissen definitiv störend sein.

  2. Keine API: Echt genug, es gibt keine API. Aber die Quelle ist verfügbar; src/lid.c function report_grep() verwendet eine verknüpfte Liste von Dateien, die mit der Ausgabe übereinstimmen. Ein wenig hantieren mit dieser Funktion sollte sogar Paginierung bieten. (Es würde etwas tun.) Am Ende des Tages, Sie hätten eine C-API, die immer noch nicht ideal sein könnte. Aber das Customizing sieht nicht schlecht aus.

Die wahrscheinlich schwächste Schwäche ist jedoch das Fehlen einer inkrementellen Datenbankaktualisierung. Wenn alle Dateien dreimal am Tag aktualisiert werden, ist das keine große Sache. Wenn einige -Dateien dreimal am Tag aktualisiert werden, wird unnötige Arbeit verrichtet. Wenn eine Handvoll Dateien dreimal am Tag aktualisiert werden, muss eine bessere Lösung gefunden werden.

    
sarnold 14.11.2011 11:59
quelle
1

Falls jemand es braucht, habe ich Whooshstore erstellt, was im Wesentlichen ein Whoosh-basierter, reiner Python-Klon von GNU id utils ist Dies bietet inkrementelle Updates, Paginierung und eine Python-API.

Der Befehlszeilenclient funktioniert folgendermaßen:

%Vor%

( -b dient zur Stapelaktualisierung, die zwar schneller ist, aber mehr Speicher benötigt. Für die vollständige CLI-Syntax verwenden Sie --help .)

Es kommt der Geschwindigkeit von GNU id utils nicht nahe, aber durch Aktualisierung des Indexes mit mehreren inkrementellen Batch (In-Memory) Updates ist es schnell genug für uns.

    
knipknap 15.11.2011 11:37
quelle