Meningkatkan kinerja untuk menangkap file besar

10

Saya memiliki FILE_A yang memiliki lebih dari 300.000 baris dan FILE_B yang memiliki lebih dari 30 juta baris. Saya membuat skrip Bash yang membuat setiap baris dalam FILE_A berakhir di FILE_B dan menulis hasil grep ke file baru.

Seluruh proses ini memakan waktu lebih dari 5 jam.

Bagaimana saya dapat meningkatkan kinerja skrip saya?

Saya menggunakan grep -F -m 1sebagai perintah grep. FILE_A terlihat seperti ini:

123456789 
123455321

dan FILE_B seperti ini:

123456789,123456789,730025400149993,
123455321,123455321,730025400126097,

Jadi dengan Bash saya memiliki whileloop yang mengambil baris berikutnya di FILE_A dan melihatnya di FILE_B. Ketika pola ditemukan di FILE_B, saya menulisnya ke file result.txt.

while read -r line; do
   grep -F -m1 $line 30MFile
done < 300KFile
rogerio_marcio
sumber

Jawaban:

17

Coba gunakan grep --file==FILE_A. Hampir pasti memuat pola ke dalam memori, artinya hanya akan memindai FILE_B sekali.

grep -F -m1 --file==300KFile 30MFile
Gort the Robot
sumber
Ini hanya akan bekerja dengan asumsi saya memiliki cukup memori, kan?
rogerio_marcio
Jujur, saya belum mencobanya sendiri pada file sebesar itu, tapi saya percaya itu akan secara dramatis meningkatkan kecepatan Anda. Jika Anda menggunakan mesin modern, Anda seharusnya tidak kesulitan menyimpan file 300K dalam memori. (Atau yang 30M dalam hal ini.)
Gort the Robot
ketika saya menggunakan opsi -f (--file) pada dasarnya menciptakan 30MFile. Apakah saya melakukan sesuatu yang salah?
rogerio_marcio
Hmmm ... mungkin 300Kfile memiliki garis kosong di dalamnya?
Gort the Robot
tepat di tempat! itu dia! yang bekerja dengan sempurna, selesai dalam 30 detik! Terima kasih!!
rogerio_marcio
2

Berikut adalah jawaban Perl untuk anak cucu. Saya secara rutin melakukan ini untuk mencocokkan 1M baris ke 30-35M baris. Diperlukan sekitar 10 detik untuk menyelesaikannya.

Pertama, hash hingga FILE_A:

my %simple_hash;
open my $first_file, '<', 'FILE_A' or die "What have you done?! $!";
while (<$first_file>) {
  chomp;                 ## Watch out for Windows newlines
  $simple_hash{$_} = 1;  ## There may be an even faster way to define this
}
close $first_file;

Lalu, jika file besar Anda dibatasi dan tahu kolom mana yang harus dicari, periksa keberadaan kunci hash saat Anda menjalankan FILE_B, yang jauh, lebih cepat daripada memeriksa persamaan atau pencocokan ekspresi reguler:

open my $second_file, '<', 'FILE_B' or die "Oh no, not again.. $!";
while (<$second_file>) {
  my ($col1, undef) = split ',';
  if (exists($simple_hash{$col1}) {
    print $_;
  }
}
close $second_file;

Jika file target Anda yang lebih besar tidak dapat diurai dengan baik, maka skrip ini kehilangan nilainya karena begitu banyak kecepatannya berasal dari tidak harus menyalakan mesin ekspresi reguler .

Mintx
sumber
1

Jika Anda tidak keberatan dengan pemrograman yang lebih terlibat, pertimbangkan untuk menggunakan pohon suffix (atau varian).

Anda dapat melakukan preproses FILE_Bmenggunakan algoritma Ukkonen dalam waktu linier. Kemudian, Anda kueri setiap baris dalam FILE_Awaktu linier dalam panjang garis dan mendapatkan semua nomor baris yang cocok (mungkin perlu mengadaptasi pohon sedikit) yang dapat Anda tulis ke file hasil.

Seluruh prosedur berjalan dalam waktu O (n + Nm) jika n adalah panjang FILE_B, Nadalah jumlah baris FILE_Adan m adalah panjang dari garis terpanjang dalam FILE_A- ini pada dasarnya adalah runtime linier. Mengalahkan waktu kuadratik yang dibutuhkan pendekatan orisinal Anda dengan besaran.

Raphael
sumber
1

Saya menemukan --mmapbendera belakangan ini, tidak memiliki kesempatan untuk mengujinya, tetapi saya akan senang mendengar tentang temuan Anda. Berikut ini deskripsi dari halaman manual:

--mmap If  possible, use the mmap(2) system call to read input, instead
      of the default read(2) system call.  In some situations,  --mmap
      yields  better performance.  However, --mmap can cause undefined
      behavior (including core dumps) if an input file  shrinks  while
      grep is operating, or if an I/O error occurs.

Lihat ini atau ini untuk info lebih lanjut tentang mmap.

Ramzi Kahil
sumber
Saya pasti akan mencoba ini dan saya akan memberi tahu Anda bagaimana hasilnya. Seberapa besar kemungkinan saya akan menemukan dump inti?
rogerio_marcio
@rogerio_marcio Yah, seperti yang saya mengerti pria itu, "jika file menyusut saat grep sedang beroperasi, atau jika kesalahan I / O terjadi.". Mungkin tidak terlalu, tetapi Anda harus tahu ini lebih baik. (Jika seperti yang saya asumsikan file tersebut tidak tersentuh saat grep - ini seharusnya tidak terjadi)
Ramzi Kahil
Untuk menguji --mmapdosis itu tidak membuang apa pun, saya akan merekomendasikan lari dengan --mmap, dan satu tanpa. Dan kemudian gunakan wcuntuk melihat bahwa Anda memiliki jumlah output yang sama - ini harus menjadi tes yang kuat mengingat kami berlari 2 kali grep, dan hanya sebuah flag yang berbeda.
Ramzi Kahil
@rogerio_marcio Sudahkah Anda mencoba ini? Ada wawasan?
Ramzi Kahil
-1

kenapa tidak Anda letakkan file itu dalam basis data database yang benar-benar bagus dalam melakukan penggabungan yang efisien, hash, nested loop, bergabung seperti ini. Dan mereka sangat baik dalam menggunakan memori virtual

Andyz Smith
sumber
Yang Anda lakukan dengan semua jawaban lainnya adalah menciptakan kembali roda basis data
Andyz Smith