Devasa bir dosyada grepping için performansı artırma


10

300.000 satırın üzerinde FILE_A ve 30 milyon satırın üzerinde FILE_B var. FILE_B içinde FILE_A'daki her satırı açığa çıkaran ve grep sonucunu yeni bir dosyaya yazan bir Bash betiği oluşturdum .

Tüm bu süreç 5 saatten fazla sürüyor.

Senaryomun performansını nasıl artırabilirim?

Ben grep -F -m 1grep komutu olarak kullanıyorum . FILE_A şöyle görünür:

123456789 
123455321

ve FILE_B şöyle:

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

Bash ile whileFILE_A'da bir sonraki satırı seçip FILE_B'de karşılıyor bir döngü var. Desen FILE_B içinde bulunduğunda onu sonuç.txt dosyasına yazarım.

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

Yanıtlar:


17

Kullanmayı deneyin grep --file==FILE_A. Neredeyse kesinlikle kalıpları belleğe yükler, yani FILE_B'yi yalnızca bir kez tarar.

grep -F -m1 --file==300KFile 30MFile

Bu sadece yeterli belleğe sahip olduğumu varsayarsak işe yarar mı?
rogerio_marcio

Dürüst olmak gerekirse, bu boyuttaki dosyalar üzerinde kendimi denemedim, ancak hızınızı önemli ölçüde artırması gerektiğine inanıyorum. Modern bir makinedeyseniz, 300K dosyasını bellekte tutmakta sorun yaşamamanız gerekir. (Ya da bu konu için 30M.)
Robotu

-f (--file) seçeneğini kullandığımda temel olarak 30MFile dosyasını yeniden oluşturdu. Yanlış bir şey mi yapıyorum?
rogerio_marcio

Hmmm ... belki 300Kfile'da boş bir satır var?
Robot Gort

tam yerinde! bu kadar! mükemmel çalıştı, 30 saniye içinde bitti! teşekkür ederim!!
rogerio_marcio

2

İşte gelecek kuşaklar için bir Perl cevabı. Bunu 1M hatlarını 30-35M hatlarıyla eşleştirmek için rutin olarak yapıyorum. Tamamlanması yaklaşık 10 saniye sürer.

İlk olarak, karma 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;

Ardından, büyük dosya olup olmadığını kontrol edin peşine ne kolon ayrılmış ve know eğer sadece varlığını sen kadar FILE_B, aşağı koşmak olarak karma anahtarın çok daha hızlı eşitlik veya normal ifade eşleşmesi için kontrol daha:

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;

Daha büyük hedef dosyanız iyi ayrıştırılamıyorsa, bu komut dosyası, normal ifade motorunu ateşlemek zorunda kalmamaktan dolayı hızını kaybeder .


1

Daha fazla programlamanın bir sakıncası yoksa, ek ağaçları (veya bir varyantı) kullanmayı düşünün .

Ukkonen algoritmasınıFILE_B kullanarak doğrusal zamanda önişleme yapabilirsiniz . Ardından, her satırı satır uzunluğunda doğrusal olarak sorgular ve sonuç dosyasına yazabileceğiniz eşleşen tüm satır numaralarını alırsınız (ağacı biraz uyarlamanız gerekebilir).FILE_A

Tüm prosedür, n uzunluğu ise FILE_B, Nsatır sayısı FILE_Ave m en uzun satırın uzunluğu ise O (n + Nm) zamanında çalışır FILE_A- bu esasen doğrusal çalışma süresidir. Orijinal yaklaşımınızın ihtiyaç duyduğu ikinci dereceden zamanı büyüklüklerle yener.


1

--mmapSon zamanlarda bayrağı buldum, test etme şansım olmadı, ancak bulgularınızı duymaktan mutluluk duyacağım. İşte adam sayfasından açıklama:

--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.

Hakkında daha fazla bilgi için bu veya buna bakın mmap.


Kesinlikle bunu deneyeceğim ve nasıl gittiğini size bildireceğim. Bir çekirdek dökümü ile karşılaşmam ne kadar olası?
rogerio_marcio

@rogerio_marcio Adamı anladığım gibi, "dosya grep çalışırken küçülürse veya bir G / Ç hatası oluşursa". Gerçekten değil, ama bunu daha iyi bilmelisin. (Eğer grep sırasında dosyaya dokunulmaz varsayalım - bu olmamalı)
Ramzi Kahil

Bu --mmapdozu hiçbir şey dökmemek için test etmek için --mmap, ve olmadan bir çalışma öneriyoruz . Ve sonra wcaynı miktarda çıktıya sahip olduğunuzu görmek için kullanın - bu, 2 kez grep koştuğumuzu ve sadece bir bayrak farklı olduğunu göz önünde bulundurarak sağlam bir test olmalıdır.
Ramzi Kahil

@rogerio_marcio Bunu denediniz mi? Herhangi bir görüşün var mı?
Ramzi Kahil

-1

neden bu dosyayı bir veritabanı veritabanına koymuyorsunuz verimli bir birleştirme, karma, iç içe döngü birleştirme gibi gerçekten iyi. Ve sanal belleği kullanmada gerçekten çok iyi


Tüm diğer cevaplarla yaptığınız tek şey veritabanı tekerleğini yeniden icat etmek
Andyz Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.