Cải thiện hiệu suất để grepping trên một tập tin lớn


10

Tôi có FILE_A có hơn 300.000 dòng và FILE_B có hơn 30 triệu dòng. Tôi đã tạo một tập lệnh Bash greps từng dòng trong FILE_A trong FILE_B và ghi kết quả của grep vào một tệp mới.

Toàn bộ quá trình này mất hơn 5 giờ.

Làm cách nào để cải thiện hiệu suất của tập lệnh?

Tôi đang sử dụng grep -F -m 1như lệnh grep. FILE_A trông như thế này:

123456789 
123455321

và FILE_B giống như thế này:

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

Vì vậy, với Bash, tôi có một whilevòng lặp chọn dòng tiếp theo trong FILE_A và greps nó trong FILE_B. Khi mẫu được tìm thấy trong FILE_B, tôi viết nó vào tệp result.txt.

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

Câu trả lời:


17

Hãy thử sử dụng grep --file==FILE_A. Nó gần như chắc chắn tải các mẫu vào bộ nhớ, có nghĩa là nó sẽ chỉ quét FILE_B một lần.

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

Điều này sẽ làm việc chỉ giả sử tôi có đủ bộ nhớ phải không?
rogerio_marcio

Thành thật mà nói, tôi đã không tự mình thử nó trên các tệp có kích thước đó, nhưng tôi tin rằng nó sẽ cải thiện đáng kể tốc độ của bạn. Nếu bạn đang sử dụng máy hiện đại, bạn sẽ không gặp khó khăn gì khi giữ tệp 300K trong bộ nhớ. (Hoặc một 30 triệu cho vấn đề đó.)
Gort the Robot

Khi tôi sử dụng tùy chọn -f (--file), về cơ bản nó đã tạo lại 30MFile. Tôi có làm điều gì sai?
rogerio_marcio

Hmmm ... có lẽ 300Kfile có một dòng trống trong đó?
Gort Robot

ngay tại chỗ! Điều đó là vậy đó! Nó hoạt động hoàn hảo, nó đã hoàn thành trong 30 giây! cảm ơn bạn!!
rogerio_marcio

2

Đây là một câu trả lời Perl cho hậu thế. Tôi thường xuyên làm điều này để khớp các dòng 1M với các dòng 30-35M. Phải mất khoảng 10 giây để hoàn thành.

Đầu tiên, băm lên 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;

Sau đó, nếu tập tin lớn của bạn được giới hạn và biết những gì cột để theo đuổi, kiểm tra các chỉ sự tồn tại của khóa băm như bạn chạy xuống FILE_B, mà là nhiều, nhiều nhanh hơn so với kiểm tra bình đẳng hoặc phù hợp với biểu thức chính quy:

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;

Nếu tệp mục tiêu lớn hơn của bạn không thể phân tích cú pháp, thì tập lệnh này sẽ mất giá trị vì rất nhiều tốc độ của nó xuất phát từ việc không phải kích hoạt công cụ biểu thức chính quy .


1

Nếu bạn không quan tâm đến việc lập trình nhiều hơn, hãy xem xét sử dụng cây hậu tố (hoặc một biến thể).

Bạn có thể tiền xử lý FILE_Bbằng thuật toán của Ukkonen trong thời gian tuyến tính. Sau đó, bạn truy vấn từng dòng theo FILE_Athời gian tuyến tính theo chiều dài dòng và nhận tất cả các số dòng khớp (có thể cần điều chỉnh cây một tad) mà bạn có thể ghi vào tệp kết quả.

Toàn bộ quy trình chạy trong thời gian O (n + Nm) nếu n là độ dài của FILE_B, Nlà số dòng trong FILE_Avà m là độ dài của dòng dài nhất trong FILE_A- đây thực chất là thời gian chạy tuyến tính. Đánh bại thời gian bậc hai mà cách tiếp cận ban đầu của bạn cần theo độ lớn.


1

--mmapGần đây tôi đã tìm thấy lá cờ, không có cơ hội để kiểm tra nó, nhưng tôi sẽ rất vui khi nghe về những phát hiện của bạn. Dưới đây là mô tả từ trang người đàn ông:

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

Xem cái này hoặc cái này để biết thêm thông tin về mmap.


Tôi chắc chắn sẽ cho nó một shot và tôi sẽ cho bạn biết nó diễn ra như thế nào. Làm thế nào có khả năng là tôi sẽ gặp một bãi chứa lõi?
rogerio_marcio

@rogerio_marcio Vâng, như tôi hiểu người đàn ông, "nếu tập tin co lại trong khi grep đang hoạt động hoặc nếu xảy ra lỗi I / O.". Không thực sự có thể, nhưng bạn nên biết điều này tốt hơn. (Nếu như tôi giả sử tập tin bị ảnh hưởng trong khi grep - điều này không nên xảy ra)
Ramzi Kahil

Để kiểm tra --mmapliều đó không đổ bất cứ thứ gì, tôi khuyên bạn nên chạy cùng --mmapvà không có. Và sau đó sử dụng wcđể thấy rằng bạn có cùng một lượng đầu ra - đây sẽ là một thử nghiệm mạnh mẽ khi xem xét rằng chúng tôi đã chạy 2 lần grep và chỉ một cờ khác nhau.
Ramzi Kahil

@rogerio_marcio Bạn đã thử cái này chưa? Bất kỳ hiểu biết?
Ramzi Kahil

-1

Tại sao bạn không đặt tệp đó vào cơ sở dữ liệu cơ sở dữ liệu thực sự tốt trong việc thực hiện kết hợp vòng lặp, hàm băm, lồng nhau hiệu quả như thế này. Và họ thực sự giỏi trong việc sử dụng bộ nhớ ảo


Tất cả những gì bạn đang làm với tất cả các câu trả lời khác là phát minh lại bánh xe cơ sở dữ liệu
Andyz Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.