Schnellster grep

80

Ich würde gerne wissen, ob es einen Tipp gibt, den man grepso schnell wie möglich machen kann. Ich habe eine ziemlich große Basis an Textdateien, um so schnell wie möglich zu suchen. Ich habe sie alle in Kleinbuchstaben geschrieben, damit ich die -iOption loswerden kann . Dies macht die Suche viel schneller.

Außerdem habe ich herausgefunden, dass -Fund -PModi schneller sind als der Standardmodus. Ich verwende den ersteren, wenn die Suchzeichenfolge kein regulärer Ausdruck ist (nur einfacher Text), den letzteren, wenn es sich um einen regulären Ausdruck handelt.

Hat jemand Erfahrung im Beschleunigen grep? Vielleicht kompilieren Sie es von Grund auf mit einem bestimmten Flag (ich bin unter Linux CentOS), organisieren die Dateien auf eine bestimmte Weise oder machen die Suche auf irgendeine Weise parallel?

Pistacchio
quelle
1
Ist das immer der gleiche Satz von Dateien? Wenn Sie feststellen, dass Sie denselben (großen) Satz von Dateien durchsuchen grep, ist es möglicherweise an der Zeit, nach einer Lösung zu suchen, um sie ordnungsgemäß zu indizieren (die "beste" Lösung hängt davon ab, um welche Art von Dateien es sich handelt).
FatalError
Ja, es ist der gleiche Satz von Dateien. Glauben Sie, dass eine Volltextlösung wie Lucene die Leistung verbessern würde? Im Allgemeinen dauert es ungefähr 30/40 Sekunden, um 2500 Dateien (jeweils ein literarisches Buch) nach einer Gesamtwortzahl von ungefähr 250 Millionen Wörtern zu durchsuchen.
Pistacchio
1
"...or maybe make the search parallel in some way?"Ich würde mich sehr freuen, davon zu hören. grepsollte in der Lage sein, parallel zu arbeiten, aber ich vermute, dass die Suche immer noch E / A-gebunden ist.
Conrad.Dean
2
Haben Sie versucht, zu verwenden ack-grep?
Meder Omuraliev
2
Verwenden Sie ack-grepoder besser Ag! geoff.greer.fm/2011/12/27/the-silver-searcher-better-than-ack
Nicholas Wilson

Antworten:

104

Versuchen Sie es mit GNU parallel , das ein Beispiel für die Verwendung enthält mitgrep :

grep -rgreift rekursiv durch Verzeichnisse. Auf Multicore-CPUs parallelkann GNU dies häufig beschleunigen.

find . -type f | parallel -k -j150% -n 1000 -m grep -H -n STRING {}

Dadurch werden 1,5 Jobs pro Kern ausgeführt und 1000 Argumente angegeben grep.

Bei großen Dateien kann die Eingabe mit den Argumenten --pipeund in mehrere Teile aufgeteilt werden --block:

 parallel --pipe --block 2M grep foo < bigfile

Sie können es auch über SSH auf mehreren verschiedenen Computern ausführen (SSH-Agent erforderlich, um Kennwörter zu vermeiden):

parallel --pipe --sshlogin server.example.com,server2.example.net grep foo < bigfile
Chewie
quelle
5
Verwenden --color=alwaysSie diese Option, um die Grep-Farbe beizubehalten (dies gilt auch dann, wenn Sie Grep auch in einer Pipe verwenden)
Jim
2
Wenn finddas -print0Prädikat hat (die meisten tun es), wäre es vorzuziehen, es zu verwenden find . -type f -print0 | parallel -0 -k …. Meine Instanz man(1) parallelsagt das tatsächlich. Ich vermute auch, dass globstarSie dies noch schneller machen können, wenn Sie nach einem bestimmten shopt -s globstar; parallel -k -j150% -n 1000 -m fgrep -H -n STRING ::: **/*.c
Dateimuster suchen
3
@ WilliamPursell ist eine nützliche Verwendung, catwenn Sie sudozugreifen möchtenbigfile
Jayen
2
Warum setzen Sie 1,5 Jobs pro Kern? Warum nicht 1 Job pro Kern?
JohnGalt
2
@JohnGalt Oft blockiert die Festplatten-E / A einen der Prozesse. Wenn Sie ein paar mehr starten, als es Kerne gibt, bleibt für alle Kerne noch etwas zu tun - auch wenn einige Jobs auf Daten warten. Passen Sie die 150% an, um zu sehen, was auf Ihrem System am besten funktioniert.
Ole Tange
70

Wenn Sie sehr große Dateien durchsuchen, kann das Festlegen Ihres Gebietsschemas wirklich hilfreich sein.

GNU grep geht im C-Gebietsschema viel schneller als mit UTF-8.

export LC_ALL=C
Daveb
quelle
1
Beeindruckend, sieht aus wie diese einzelne Linie 2X Geschwindigkeit gibt.
Fedir RYKHTIK
Kann jemand erklären, warum das so ist?
Robert E Mealey
5
"Einfacher Byte-Vergleich gegen Mehrbyte-Zeichen-Vergleich" <sagt mein Chef ... richtig richtig richtig
Robert E Mealey
7
Dies ist also nicht gerade sicher, insbesondere wenn Sie einen Mustervergleich durchführen (im Gegensatz zum reinen Stringvergleich) oder wenn der Inhalt Ihrer Datei nicht ASCII ist. In einigen Fällen lohnt es sich immer noch, dies zu tun, aber seien Sie vorsichtig.
Robert E Mealey
@ RobertEMealey Hat er "Single" statt "Simple" gesagt?
Elijah Lynn
12

Ripgrep behauptet, jetzt der Schnellste zu sein.

https://github.com/BurntSushi/ripgrep

Enthält standardmäßig auch Parallelität

 -j, --threads ARG
              The number of threads to use.  Defaults to the number of logical CPUs (capped at 6).  [default: 0]

Aus der README

Es basiert auf Rusts Regex-Motor. Die Regex-Engine von Rust verwendet endliche Automaten, SIMD und aggressive Literaloptimierungen, um die Suche sehr schnell zu machen.

Rado
quelle
Das geht unglaublich schnell!
Beat
4

Keine reine Codeverbesserung, aber etwas, das ich hilfreich fand, nachdem ich grep für mehr als 2 Millionen Dateien ausgeführt hatte.

Ich habe den Vorgang auf ein billiges SSD-Laufwerk (120 GB) verschoben. Bei etwa 100 US-Dollar ist dies eine erschwingliche Option, wenn Sie regelmäßig viele Dateien verarbeiten.

der Wanderer
quelle
3

Wenn Sie sich nicht darum kümmern, welche Dateien die Zeichenfolge enthalten, möchten Sie möglicherweise das Lesen und Greifen in zwei Jobs unterteilen, da das grepmehrfache Laichen möglicherweise kostspielig ist - einmal für jede kleine Datei.

  1. Wenn Sie eine sehr große Datei haben:

    parallel -j100% --pipepart --block 100M -a <very large SEEKABLE file> grep <...>

  2. Viele kleine komprimierte Dateien (sortiert nach Inode)

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j80% --group "gzcat {}" | parallel -j50% --pipe --round-robin -u -N1000 grep <..>

Normalerweise komprimiere ich meine Dateien mit lz4 für maximalen Durchsatz.

  1. Wenn Sie nur den Dateinamen mit der Übereinstimmung möchten:

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j100% --group "gzcat {} | grep -lq <..> && echo {}

Alex V.
quelle
2

Aufbauend auf der Antwort von Sandro habe ich mir die Referenz angesehen, die er hier zur Verfügung gestellt hat, und mit BSD grep vs. GNU grep herumgespielt. Meine schnellen Benchmark-Ergebnisse zeigten: GNU grep ist viel, viel schneller.

Also meine Empfehlung zur ursprünglichen Frage "schnellstmögliches grep": Stellen Sie sicher, dass Sie GNU grep anstelle von BSD grep verwenden (was beispielsweise unter MacOS die Standardeinstellung ist).

Chris
quelle
Ich zeige BSD Grep auf meinem 13 "MacBook Pro schneller als auf einem 8 GB, 6-Kern-Linode, während ich eine 250 MB .sql-Dump-Datei durchsuche. 6 s vs 25 s
AnthumChris
2

Ich persönlich benutze die ag (Silbersucher) anstelle von grep und sie ist viel schneller. Sie können sie auch mit Parallel- und Pipe-Block kombinieren.

https://github.com/ggreer/the_silver_searcher

Update: Ich verwende jetzt https://github.com/BurntSushi/ripgrep, das je nach Anwendungsfall schneller als ag ist.

Jinxmcg
quelle
Ich habe einen Fehler darin gefunden. Manchmal geht es nicht tief in den Baum und ich habe Fälle, in denen grep das Ergebnis zeigt, ag jedoch nicht. Bei der Geschwindigkeit kann ich keine Kompromisse eingehen.
Benutzername_4567
1
Sie sollten ein Problem in ihrem Github-Konto eröffnen und melden (ich würde das tun, aber ich kann es nicht replizieren), da ich bis jetzt keine Ungenauigkeiten festgestellt habe. Sicher werden sie das klären und ja, Sie haben Recht, ich stimme vollkommen zu: Genauigkeit zuerst.
Jinxmcg
1

Eine Sache, die ich schneller gefunden habe, um grep zum Suchen (insbesondere zum Ändern von Mustern) in einer einzelnen großen Datei zu verwenden, ist die Verwendung von split + grep + xargs mit dem parallelen Flag. Zum Beispiel:

Eine Datei mit IDs, nach denen Sie suchen möchten, in einer großen Datei namens my_ids.txt Name der großen Datei bigfile.txt

Verwenden Sie split, um die Datei in Teile zu teilen:

# Use split to split the file into x number of files, consider your big file
# size and try to stay under 26 split files to keep the filenames 
# easy from split (xa[a-z]), in my example I have 10 million rows in bigfile
split -l 1000000 bigfile.txt
# Produces output files named xa[a-t]

# Now use split files + xargs to iterate and launch parallel greps with output
for id in $(cat my_ids.txt) ; do ls xa* | xargs -n 1 -P 20 grep $id >> matches.txt ; done
# Here you can tune your parallel greps with -P, in my case I am being greedy
# Also be aware that there's no point in allocating more greps than x files

In meinem Fall wurde dadurch ein 17-Stunden-Job in einen 1-Stunden-20-Minuten-Job umgewandelt. Ich bin mir sicher, dass es hier eine Art Glockenkurve in Bezug auf die Effizienz gibt, und natürlich hilft es Ihnen nicht, die verfügbaren Kerne zu überprüfen, aber dies war eine viel bessere Lösung als die oben genannten Kommentare für meine Anforderungen, wie oben angegeben. Dies hat einen zusätzlichen Vorteil gegenüber dem Skript parallel zur Verwendung der meisten (Linux-) nativen Tools.

user6504312
quelle
0

cgrep kann, falls verfügbar, um Größenordnungen schneller sein als grep.

xhtml
quelle
0

MCE 1.508 enthält ein Dual-Chunk-Level-Wrapper-Skript (Datei, Liste), das viele C-Binärdateien unterstützt. zustimmen, grep, egrep, fgrep und tre-zustimmen.

https://metacpan.org/source/MARIOROY/MCE-1.509/bin/mce_grep

https://metacpan.org/release/MCE

Man muss nicht in Kleinbuchstaben konvertieren, wenn -i schnell ausgeführt werden soll. Übergeben Sie einfach --lang = C an mce_grep.

Die Ausgabereihenfolge bleibt erhalten. Die Ausgabe -n und -b ist ebenfalls korrekt. Leider ist dies bei der auf dieser Seite erwähnten GNU-Parallele nicht der Fall. Ich hatte wirklich gehofft, dass GNU Parallel hier funktioniert. Außerdem führt mce_grep beim Aufrufen der Binärdatei keine Unter-Shell (sh -c / path / to / grep) durch.

Eine weitere Alternative ist das in MCE enthaltene MCE :: Grep-Modul.

Mario Roy
quelle
Sie müssen einen Haftungsausschluss angeben, da Sie Autor des genannten Tools sind.
FractalSpace
0

Eine leichte Abweichung vom ursprünglichen Thema: Die indizierten Suchbefehlszeilen-Dienstprogramme aus dem GoogleCodesearch-Projekt sind viel schneller als grep: https://github.com/google/codesearch :

Sobald Sie es kompiliert haben (das Golang- Paket wird benötigt), können Sie einen Ordner indizieren mit:

# index current folder
cindex .

Der Index wird unter erstellt ~/.csearchindex

Jetzt können Sie suchen:

# search folders previously indexed with cindex
csearch eggs

Ich leite die Ergebnisse immer noch durch grep, um farbige Übereinstimmungen zu erhalten.

ccpizza
quelle