Mam plik, który rośnie około 200 000 wierszy dziennie, i wszystko składa się z bloków po trzy linie jako takie:
1358726575123 # key
Joseph Muller # name
carpenter # job
9973834728345
Andres Smith
student
7836472098652
Mariah Anthony
dentist
Teraz mam inny plik, z którego wyodrębniam około 10 000 wzorców kluczy, takich jak 1358726575123
. Następnie uruchamiam for
pętlę z tymi wzorami i muszę je porównać z pierwszym plikiem. Jeśli plik nie zawiera takiego wzorca, zapisuję go w trzecim pliku do dalszego przetwarzania:
for number in $(grep -o '[0-9]\{12\}' file2); do # finds about 10.000 keys
if ! grep -q ^$number$ file1; then # file1 is a huge file
printf "$number\n" >>file3 # we'll process file3 later
fi
done
Przykładowy kod przechwytuje ogromny plik 10 000 razy, a tę pętlę uruchamiam mniej więcej raz na minutę, przez cały dzień .
Ponieważ ogromny plik wciąż rośnie, co mogę zrobić, aby to wszystko przyspieszyć i zaoszczędzić trochę procesora? Zastanawiam się, czy posortowanie pliku według klucza (jeśli tak, to w jaki sposób?) Czy użycie db zamiast zwykłego tekstu pomogłoby ...
Odpowiedzi:
Ta odpowiedź oparta jest na
awk
odpowiedzi wysłanej przez potong .Jest dwa razy szybsza niż
comm
metoda (w moim systemie), dla tych samych 6 milionów linii w głównym pliku i 10 tysięcy kluczy ... (teraz zaktualizowano, by używało FNR, NR)Chociaż
awk
jest szybszy niż twój obecny system i da tobie i twojemu komputerowi trochę przestrzeni do oddychania, pamiętaj, że gdy przetwarzanie danych jest tak intensywne, jak opisano, uzyskasz najlepsze ogólne wyniki, przechodząc do dedykowanej bazy danych; na przykład. SQlite, MySQL ...źródło
file1 -> mainfile
ifile2 -> keys
z gawk i mawk i wyprowadza błędnych kluczy.awk
pozwalają na odczytanie szeregu plików .. W tym przypadku ta seria zawiera 3. Pliki wyjściowe trafiają dostdout
mainfile
, I będzie to również wydrukować żadnych kluczy zkeys
pliku, które są nie wmainfile
... To jest chyba to, co się dzieje ... (będę patrzeć nieco dalej do niego ...$RANDOM
do przesłania.Problem polega oczywiście na tym, że uruchamiasz grep na dużym pliku 10 000 razy. Oba pliki powinieneś przeczytać tylko raz. Jeśli chcesz pozostać poza językami skryptowymi, możesz to zrobić w ten sposób:
comm
na posortowanych listach, aby uzyskać to, co jest tylko na drugiej liścieCoś takiego:
Zobaczyć
man comm
.Jeśli możesz obcinać duży plik każdego dnia (np. Plik dziennika), możesz przechowywać pamięć podręczną posortowanych liczb i nie musisz za każdym razem analizować go w całości.
źródło
{12}
... OP użył 12, ale przykładowe klucze mają 13 długości ...<(grep...sort)
nazw plików.tail -n +$linenum
do wyświetlania tylko najnowszych danych. W ten sposób będziesz przetwarzał tylko około 200 000 linii każdego dnia. Właśnie przetestowałem go z 6 milionami linii w pliku głównym i 10 tysiącami kluczy ... czas : prawdziwe 0m0.016s, użytkownik 0m0.008s, sys 0m0.008sTak, zdecydowanie skorzystaj z bazy danych. Są wykonane dokładnie do takich zadań.
źródło
To może Ci pomóc:
EDYTOWAĆ:
Zmieniony skrypt pozwalający na duplikaty i nieznane klucze w obu plikach, nadal wytwarza klucze z pierwszego pliku nieobecnego w drugim:
źródło
Przy tak dużej ilości danych naprawdę powinieneś przełączyć się na bazę danych. W międzyczasie jedyną rzeczą, którą musisz zrobić, aby zbliżyć się do przyzwoitej wydajności, jest nie szukać
file1
osobno dla każdego klucza. Uruchom pojedynczy,grep
aby wyodrębnić wszystkie niewykluczone klucze naraz. Ponieważ togrep
również zwraca wiersze, które nie zawierają klucza, odfiltruj je.(
-Fx
oznacza przeszukiwanie całych linii, dosłownie.-f -
oznacza odczytanie listy wzorców ze standardowego wejścia).źródło
-v
(-Fxv
) może się tym zająć.comm
.Pozwól mi wzmocnić to, co powiedzieli inni: „Zabierz cię do bazy danych!”
Pliki binarne MySQL są swobodnie dostępne dla większości platform.
Dlaczego nie SQLite? Opiera się na pamięci, ładuje płaski plik po uruchomieniu, a następnie zamyka po zakończeniu. Oznacza to, że jeśli komputer ulegnie awarii lub proces SQLite zniknie, wszystkie dane również.
Twój problem wygląda jak tylko kilka wierszy SQL i będzie działał w milisekundach!
Po zainstalowaniu MySQL (które zalecam w porównaniu z innymi opcjami) wydałbym 40 USD na książkę kucharską SQL O'Reilly autorstwa Anthony'ego Molinaro, która ma wiele wzorców problemów, zaczynając od prostych
SELECT * FROM table
zapytań, przechodząc przez agregacje i wiele sprzężeń.źródło
Nie jestem pewien, czy jest to dokładnie to, czego szukasz, ale prawdopodobnie najłatwiejszym sposobem jest:
Możesz także użyć:
Każdy z nich tworzy tymczasowy plik sygnatur, który służy do zbierania liczb z dużego pliku (
file1
).źródło
grep -vf
zamiastgrep -f
.W pełni zgadzam się z twoją bazą danych (MySQL jest dość łatwy w użyciu). Dopóki tego nie uruchomisz, podoba mi się
comm
rozwiązanie Angusa , ale tak wielu ludzi próbujegrep
i robi to źle, że myślałem, że pokażę (lub przynajmniej jeden) właściwy sposób, aby to zrobićgrep
.Pierwszy
grep
dostaje klucze. Trzecigrep
(w<(...)
) pobiera wszystkie klucze użyte w dużym pliku, a<(...)
przekazuje go jak plik jako argument-f
w drugim grep. To powoduje, że drugigrep
używa go jako listy pasujących linii. Następnie używa go do dopasowania danych wejściowych (listy kluczy) z potoku (najpierwgrep
) i drukuje wszystkie klucze wyodrębnione z pliku kluczy, a nie (-v
) duży plik.Oczywiście możesz to zrobić z plikami tymczasowymi, które musisz śledzić i pamiętać o usunięciu:
Spowoduje to wydrukowanie wszystkich linii
allkeys
, które się nie pojawiająusedkeys
.źródło
grep: Memory exhausted
comm
w tej kolejności.Plik klucza się nie zmienia? Następnie powinieneś unikać ciągłego przeszukiwania starych wpisów.
Dzięki
tail -f
możesz uzyskać wynik rosnącego pliku.grep -f odczytuje wzorce z pliku, jedna linia jako wzorzec.
źródło
Nie zamierzałem publikować mojej odpowiedzi, ponieważ uważałem, że taka ilość danych nie powinna być przetwarzana za pomocą skryptu powłoki, a już podano prawidłową odpowiedź na użycie bazy danych. Ale od teraz istnieje 7 innych podejść ...
Odczytuje pierwszy plik z pamięci, następnie greps drugi plik dla liczb i sprawdza, czy wartości są przechowywane w pamięci. Powinno to być szybsze niż wiele
grep
s, jeśli masz wystarczającą ilość pamięci, aby załadować cały plik, to znaczy.źródło
Zgadzam się z @ jan-steinman , że powinieneś używać bazy danych do tego rodzaju zadań. Istnieje wiele sposobów na zhakowanie rozwiązania za pomocą skryptu powłoki, jak pokazują inne odpowiedzi, ale zrobienie tego w ten sposób doprowadzi do wielu nieszczęść, jeśli zamierzasz używać i utrzymywać kod przez dłuższy czas niż tylko jednodniowy projekt jednorazowy.
Zakładając, że korzystasz z Linuksa, najprawdopodobniej masz domyślnie zainstalowanego Pythona, który zawiera bibliotekę sqlite3 od Python v2.5. Możesz sprawdzić swoją wersję Pythona za pomocą:
Polecam korzystanie z biblioteki sqlite3, ponieważ jest to proste rozwiązanie oparte na plikach, które istnieje na wszystkich platformach (w tym w przeglądarce internetowej!) I nie wymaga instalacji serwera. Zasadniczo zerowa konfiguracja i zerowa konserwacja.
Poniżej znajduje się prosty skrypt Pythona, który przeanalizuje format pliku podany jako przykład, a następnie wykona proste zapytanie „zaznacz wszystko” i wyświetli wszystko, co jest zapisane w bazie danych.
Tak, oznacza to, że musisz nauczyć się trochę SQL , ale na dłuższą metę będzie to warte zachodu. Ponadto zamiast parsowania plików dziennika może być możliwe zapisanie danych bezpośrednio w bazie danych sqlite.
źródło
/usr/bin/sqlite3
działa w ten sam sposób dla skryptów powłoki ( packages.debian.org/squeeze/sqlite3 ), chociaż nigdy go nie używałem./usr/bin/sqlite3
ze skryptami powłoki, jednak zalecam unikanie skryptów powłoki z wyjątkiem prostych programów służących do wyrzucania i zamiast tego używaj języka takiego jak python, który ma lepszą obsługę błędów i jest łatwiejszy w utrzymaniu i rozwoju.