Grep nhanh nhất có thể


80

Tôi muốn biết nếu có bất kỳ mẹo nào để thực hiện grepnhanh nhất có thể. Tôi có một lượng lớn các tệp văn bản để tìm kiếm theo cách nhanh nhất có thể. Tôi đã tạo tất cả chúng bằng chữ thường, để tôi có thể loại bỏ -itùy chọn. Điều này làm cho việc tìm kiếm nhanh hơn nhiều.

Ngoài ra, tôi đã phát hiện ra rằng -F-Pcác chế độ nhanh hơn chế độ mặc định. Tôi sử dụng cái trước khi chuỗi tìm kiếm không phải là một biểu thức chính quy (chỉ là văn bản thuần túy), cái sau nếu có liên quan đến regex.

Có ai có bất kỳ kinh nghiệm trong việc tăng tốc độ grep? Có thể biên dịch nó từ đầu với một số cờ cụ thể (tôi đang sử dụng Linux CentOS), sắp xếp các tệp theo một kiểu nhất định hoặc có thể thực hiện tìm kiếm song song theo một cách nào đó?


1
Đây có phải luôn là cùng một tập hợp các tệp không? Nếu bạn thấy mình đang tìm kiếm cùng một tập hợp (lớn) các tệp grep, có lẽ đã đến lúc tìm giải pháp để lập chỉ mục chúng một cách chính xác (giải pháp "tốt nhất" sẽ phụ thuộc vào loại tệp này là gì).
FatalError,

vâng, nó là cùng một tập hợp các tệp. bạn có nghĩ rằng một giải pháp đầy đủ văn bản như lucene sẽ cải thiện hiệu suất không? nói chung mất khoảng 30/40 giây để thực hiện tìm kiếm qua 2500 tệp (mỗi tệp là một cuốn sách văn học) với tổng số từ khoảng 250 triệu từ.
pistacchio

1
"...or maybe make the search parallel in some way?"Tôi thực sự vui mừng khi nghe về điều này. grepnên hoàn toàn có thể hoạt động song song, nhưng tôi nghi ngờ việc tìm kiếm vẫn có thể bị ràng buộc I / O.
Conrad.Dean

2
Bạn đã thử sử dụng ack-grepchưa?
meder omuraliev

Câu trả lời:


104

Hãy thử với GNU song song , bao gồm một ví dụ về cách sử dụng nó vớigrep :

grep -rgreps đệ quy thông qua các thư mục. Trên các CPU đa lõi GNU parallelthường có thể tăng tốc độ này.

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

Điều này sẽ chạy 1,5 công việc cho mỗi lõi và đưa ra 1000 đối số grep.

Đối với các tệp lớn, nó có thể chia nhỏ dữ liệu đầu vào thành nhiều phần với các đối số --pipe--block:

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

Bạn cũng có thể chạy nó trên một số máy khác nhau thông qua SSH (cần có ssh-agent để tránh mật khẩu):

parallel --pipe --sshlogin server.example.com,server2.example.net grep foo < bigfile

5
sử dụng --color=alwaysđể bảo vệ màu grep (điều này là đúng bất cứ khi nào bạn đang sử dụng grep trong một ống cũng)
Jim

2
Nếu find-print0vị từ (hầu hết do) thì sẽ được ưu tiên sử dụng hơn find . -type f -print0 | parallel -0 -k …. Ví dụ của tôi man(1) parallelthực sự nói lên điều này. Ngoài ra, tôi nghi ngờ với globstarbạn có thể làm điều này thậm chí nhanh hơn nếu bạn đang theo đuổi một mô hình tập tin cụ thể:shopt -s globstar; parallel -k -j150% -n 1000 -m fgrep -H -n STRING ::: **/*.c
Kojiro

3
@WilliamPursell, đó là một công dụng hữu ích catnếu bạn muốn sudotruy cậpbigfile
Jayen

2
Tại sao bạn đặt 1,5 công việc cho mỗi lõi? Tại sao không phải là 1 công việc cho mỗi lõi?
JohnGalt

2
@JohnGalt Thường thì I / O đĩa sẽ ngừng một trong các quá trình. Bằng cách bắt đầu nhiều hơn số lõi, vẫn sẽ có việc phải làm cho tất cả các lõi - ngay cả khi một số công việc đang chờ dữ liệu. Điều chỉnh 150% để xem những gì hoạt động tốt nhất trên hệ thống của bạn.
Ole Tange

70

Nếu bạn đang tìm kiếm các tệp rất lớn, thì việc đặt ngôn ngữ của bạn thực sự có thể hữu ích.

GNU grep đi nhanh hơn rất nhiều trong ngôn ngữ C so với UTF-8.

export LC_ALL=C

1
Ấn tượng, có vẻ như dòng đơn này cho tốc độ gấp 2 lần.
Fedir RYKHTIK

Ai đó có thể giải thích tại sao điều này là?
Robert E Mealey

5
"Simple byte so vs nhiều so byte ký tự" <nói ông chủ của tôi ... đúng đúng đúng
Robert E Mealey

7
Vì vậy, điều này không chính xác an toàn, đặc biệt nếu bạn đang đối sánh mẫu (thay vì chỉ đối sánh chuỗi) hoặc nếu nội dung tệp của bạn không phải là ascii. vẫn đáng làm trong một số trường hợp nhưng hãy thận trọng.
Robert E Mealey

@RobertEMealey Anh ấy đã nói "Độc thân" thay vì "Đơn giản"?
Elijah Lynn

12

Ripgrep tuyên bố bây giờ là nhanh nhất.

https://github.com/BurntSushi/ripgrep

Cũng bao gồm song song theo mặc định

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

Từ README

Nó được xây dựng dựa trên động cơ regex của Rust. Công cụ regex của Rust sử dụng ô tô hữu hạn, SIMD và tối ưu hóa theo nghĩa đen tích cực để giúp tìm kiếm rất nhanh.


Điều này là cực kỳ nhanh chóng!
Đánh bại


4

Không hoàn toàn là một cải tiến về mã nhưng một thứ tôi thấy hữu ích sau khi chạy grep trên hơn 2 triệu tệp.

Tôi đã chuyển thao tác sang một ổ SSD giá rẻ (120GB). Với giá khoảng 100 đô la, đây là một lựa chọn hợp lý nếu bạn thường xuyên xử lý nhiều tệp.


3

Nếu bạn không quan tâm về những file chứa chuỗi, bạn có thể muốn tách đọcgrepping vào hai công việc, vì nó có thể là tốn kém để đẻ trứng grepnhiều lần - một lần cho mỗi tập tin nhỏ.

  1. Nếu bạn có một tệp rất lớn:

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

  2. Nhiều tệp nén nhỏ (sắp xếp theo inode)

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

Tôi thường nén các tệp của mình bằng lz4 để có thông lượng tối đa.

  1. Nếu bạn chỉ muốn tên tệp phù hợp:

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


2

Dựa trên phản ứng của Sandro, tôi đã xem tài liệu tham khảo mà anh ấy cung cấp ở đây và chơi với BSD grep so với GNU grep. Kết quả điểm chuẩn nhanh của tôi cho thấy: GNU grep là cách, nhanh hơn.

Vì vậy, khuyến nghị của tôi cho câu hỏi ban đầu "grep nhanh nhất có thể": Hãy đảm bảo rằng bạn đang sử dụng GNU grep chứ không phải BSD grep (ví dụ: là mặc định trên MacOS).


Tôi đang hiển thị BSD Grep nhanh hơn trên MacBook Pro 13 inch của mình so với 8GB, Linode 6 lõi trong khi tìm kiếm tệp kết xuất .sql 250 MB. 6 giây so với 25 giây
AnthumChris

2

Cá nhân tôi sử dụng ag (trình tìm kiếm bạc) thay vì grep và nó nhanh hơn, bạn cũng có thể kết hợp nó với khối song song và khối ống.

https://github.com/ggreer/the_silver_searcher

Cập nhật: Bây giờ tôi sử dụng https://github.com/BurntSushi/ripgrep , nhanh hơn ag tùy thuộc vào trường hợp sử dụng của bạn.


Tôi tìm thấy một lỗi trong này. Đôi khi nó không đi sâu vào cây và tôi có trường hợp grep hiển thị kết quả nhưng ag thì không. Tôi không thể thỏa hiệp về độ chính xác cho tốc độ.
username_4567

1
Bạn nên mở Sự cố trên tài khoản github của họ và báo cáo (Tôi sẽ làm điều đó nhưng tôi không thể sao chép nó), vì cho đến nay tôi không tìm thấy bất kỳ điểm nào không chính xác. Chắc chắn họ sẽ giải quyết vấn đề này và vâng bạn nói đúng, tôi hoàn toàn đồng ý: độ chính xác trước tiên.
Jinxmcg

1

Một điều tôi thấy nhanh hơn khi sử dụng grep để tìm kiếm (đặc biệt là để thay đổi các mẫu) trong một tệp lớn duy nhất là sử dụng split + grep + xargs với cờ song song của nó. Ví dụ:

Có một tệp id bạn muốn tìm kiếm trong một tệp lớn có tên là my_ids.txt Tên của tệp bigfile bigfile.txt

Sử dụng tách để chia tệp thành các phần:

# 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

Trong trường hợp của tôi, điều này đã cắt giảm công việc 17 giờ thành công việc 1 giờ 20 phút. Tôi chắc chắn rằng có một số loại đường cong ở đây về hiệu quả và rõ ràng việc xem qua các lõi có sẵn sẽ không mang lại lợi ích gì cho bạn nhưng đây là một giải pháp tốt hơn nhiều so với bất kỳ nhận xét nào ở trên cho các yêu cầu của tôi như đã nêu ở trên. Điều này có một lợi ích bổ sung so với tập lệnh song song trong việc sử dụng hầu hết các công cụ gốc (linux).


0

cgrep, nếu nó có sẵn, có thể là đơn đặt hàng có cường độ nhanh hơn grep.


0

MCE 1.508 bao gồm một tập lệnh trình bao bọc cấp độ kép {file, list} hỗ trợ nhiều mã nhị phân C; agrep, grep, egrep, fgrep và tre-agrep.

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

https://metacpan.org/release/MCE

Người ta không cần chuyển đổi thành chữ thường khi muốn -i chạy nhanh. Đơn giản chỉ cần chuyển --lang = C đến mce_grep.

Thứ tự đầu ra được giữ nguyên. Đầu ra -n và -b cũng đúng. Thật không may, đó không phải là trường hợp song song GNU được đề cập trên trang này. Tôi thực sự hy vọng GNU Parallel sẽ hoạt động ở đây. Ngoài ra, mce_grep không phụ shell (sh -c / path / to / grep) khi gọi nhị phân.

Một thay thế khác là mô-đun MCE :: Grep đi kèm với MCE.


Bạn cần cung cấp tuyên bố từ chối trách nhiệm, là tác giả của công cụ nói trên.
FractalSpace

0

Hơi lệch so với chủ đề ban đầu: các tiện ích dòng lệnh tìm kiếm được lập chỉ mục từ dự án googlecodesearch nhanh hơn grep: https://github.com/google/codesearch :

Khi bạn biên dịch nó ( cần có gói golang ), bạn có thể lập chỉ mục một thư mục với:

# index current folder
cindex .

Chỉ mục sẽ được tạo dưới ~/.csearchindex

Bây giờ bạn có thể tìm kiếm:

# search folders previously indexed with cindex
csearch eggs

Tôi vẫn đang chuyển kết quả thông qua grep để có được các kết quả phù hợp được tô màu.

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.