Sắp xếp nội dung của tệp văn bản cực lớn (800 GB) trên Windows


25

Tôi có một tệp văn bản với một từ trong mỗi dòng, kích thước của tệp là 800GB. Tôi cần sắp xếp các từ theo thứ tự abc.

Tôi đã thử sử dụng chương trình sắp xếp Windows bằng cách sử dụng:

sort.exe input.txt /o output.txt

Điều này gây ra lỗi: Không đủ bộ nhớ chính để hoàn thành sắp xếp.

Tôi có 32GB RAM vì vậy khi tôi thử chỉ định 10GB bộ nhớ cho loại bằng cách sử dụng:

sort.exe input.txt /o output.txt /M 10000000

Tôi có:

Cảnh báo: kích thước bộ nhớ đã chỉ định đang được giảm xuống bộ nhớ phân trang có sẵn.

Bản ghi đầu vào vượt quá chiều dài tối đa. Chỉ định tối đa lớn hơn.

Những lựa chọn của tôi là gì?



10
Đây không phải là một bài viết chéo, tôi không phải là một cái máy nên việc đăng cái này và xóa cái kia mất vài phút!
MaYaN

3
Trong tương lai, cho phép cộng đồng di chuyển câu hỏi của bạn
Ramhound

4
Với Linux, bạn có thể áp dụng phương pháp này . Với các tệp 100Mb, nó không phải là một vấn đề lớn.
Eric Duminil

3
Phiên bản Windows nào bạn đang sử dụng? Sort.exe với Windows Server 2012 R2 khá cũ tuyên bố có thể thực hiện sắp xếp hợp nhất bên ngoài với việc sử dụng tệp tạm thời trên đĩa (mà không cần ghi lại giới hạn kích thước). Hãy thử sử dụng / T để chỉ định một đĩa có 800Gb miễn phí cho tệp tạm thời. Và thông báo về "bản ghi đầu vào vượt quá độ dài tối đa" dường như không liên quan đến không gian - hãy xem tùy chọn / REC và xem xét đầu cuối dòng của bạn là gì.
davidbak

Câu trả lời:


16

Những lựa chọn của tôi là gì?

Hãy dùng thử phần mềm tiện ích sắp xếp dòng lệnh miễn phí CMSort .

Nó sử dụng nhiều tập tin tạm thời và sau đó hợp nhất chúng vào cuối.

CMsort đang đọc các bản ghi của một tệp đầu vào cho đến khi đạt được bộ nhớ đã điều chỉnh. Sau đó các hồ sơ được sắp xếp và ghi vào một tập tin tạm thời. Điều này sẽ được lặp lại cho đến khi tất cả các hồ sơ được xử lý. Cuối cùng, tất cả các tệp tạm thời được hợp nhất vào tệp đầu ra. Nếu bộ nhớ khả dụng là đủ, không có tệp tạm thời nào được ghi và không cần hợp nhất.

Một người dùng báo cáo nó đã sắp xếp một tệp 130.000.000 byte.

Nếu bạn muốn tự chỉnh sửa một số mã, đó cũng là Sắp xếp các tệp văn bản khổng lồ - CodeProject - "Thuật toán sắp xếp các dòng trong kích thước tệp văn bản vượt quá bộ nhớ khả dụng"


26
Ồ, 130 megabyte !!! +1
David Foerster

3
@DavidPostill Bạn có chắc rằng việc sắp xếp từ coreutils cho windows không hiệu quả hơn ( --paralleltùy chọn nếu bạn có nhiều hơn một lõi ...)?
Hastur

23

Một tùy chọn khác là tải tệp vào Cơ sở dữ liệu. Bàn làm việc của MySQL và MySQL.
Cơ sở dữ liệu là ứng cử viên hoàn hảo để làm việc với các tệp lớn

Nếu tệp đầu vào của bạn chỉ chứa các từ được phân tách bằng một dòng mới thì điều này không nên khó.

Sau khi bạn đã cài đặt cơ sở dữ liệu và MySQL Workbench, đây là việc bạn cần làm.
Trước tiên hãy tạo lược đồ (điều này giả sử các từ sẽ không dài hơn 255 ký tự mặc dù bạn có thể thay đổi điều này bằng cách tăng giá trị đối số). Cột đầu tiên "idwords" là khóa chính.

CREATE SCHEMA `tmp` ;

CREATE TABLE `tmp`.`words` (
  `idwords` INT NOT NULL AUTO_INCREMENT,
  `mywords` VARCHAR(255) NULL,
  PRIMARY KEY (`idwords`));

Nhập dữ liệu thứ hai: EG Điều này sẽ nhập tất cả các từ vào bảng (bước này có thể mất một lúc để hoàn thành. Lời khuyên của tôi là trước tiên hãy chạy thử nghiệm với một tệp từ nhỏ và một khi bạn chắc chắn định dạng giống như cái lớn hơn (cắt bớt bảng .. IE Xóa nó ra và tải bộ dữ liệu đầy đủ).

LOAD DATA LOCAL INFILE "C:\\words.txt" INTO TABLE tmp.words
LINES TERMINATED BY '\r\n'
(mywords);


Liên kết này có thể giúp có được định dạng phù hợp với tải. https://dev.mysql.com/doc/refman/5.7/en/load-data.html
EG Nếu bạn cần bỏ qua dòng đầu tiên bạn sẽ làm như sau.

LOAD DATA LOCAL INFILE "H:\\words.txt" INTO TABLE tmp.words
-- FIELDS TERMINATED BY ','
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
(mywords);

Cuối cùng Lưu tập tin đã sắp xếp. Điều này có thể mất một lúc cũng tùy thuộc vào máy tính của bạn.

SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
INTO OUTFILE 'C:\\sorted_words.csv';

Bạn cũng có thể tìm kiếm dữ liệu theo ý muốn. EG Điều này sẽ cung cấp cho bạn 50 từ đầu tiên theo thứ tự tăng dần (bắt đầu từ 0 hoặc từ đầu tiên).

SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
LIMIT 0, 50 ;

Chúc may mắn
Pete


2
Đây câu trả lời đúng bởi một lề đáng kể.
MonkeyZeus

1
Cách tiếp cận này chắc chắn sẽ linh hoạt hơn, đặc biệt nếu bạn phát hiện ra bạn cần chạy lại sắp xếp với một thứ tự khác, chẳng hạn.
thịt nướng

Tôi không quan tâm đến phiên bản MySQL , MariaDB hoặc bất kỳ DBMS nào của bạn nhanh như thế nào , nó sẽ không đến bất kỳ nơi nào gần với hiệu năng chèn của SQLite chạy trên cùng một máy. Ngay cả với thứ gì đó nhanh như SQLite , lượng dữ liệu này quá nhiều (và chậm) để xử lý (tin tôi đi, tôi đã thử trước rồi!) Vì vậy, giải pháp tốt nhất là sắp xếp và loại bỏ các bản sao trước sau đó chèn vào DB như SQLite . Vì vậy, trong khi giải pháp này có thể hợp lệ đối với một số trường hợp, nó chắc chắn không phải là những gì tôi đang cố gắng làm. Cảm ơn bạn đã dành thời gian để đăng bài này.
MaYaN

Đặt hàng bởi mywordssẽ mất mãi mãi. Ngay cả với LIMIT, nó sẽ mất chừng nào toàn bộ bởi vì MySQL sẽ phải trải qua mọi giá trị duy nhất mywordsvà đặt hàng chúng. Để khắc phục điều này, bạn phải làm như sau sau khi hoàn thành LOAD DATA. Thêm một chỉ mục vào mywords. Bây giờ bạn có thể đặt hàng theo cột đó và không mất một thiên niên kỷ. Và tốt hơn thêm chỉ mục sau khi tải dữ liệu thay vì tại thời điểm bạn tạo bảng (tải dữ liệu nhanh hơn nhiều).
Butussy Butkus

7

sort

Có nhiều thuật toán được sử dụng để sắp xếp các tập tin theo thứ tự và không theo thứ tự [ 1 ] .
Vì tất cả các thuật toán đã được thực hiện, hãy chọn một chương trình đã được thử nghiệm.

Trong coreutils (từ Linux nhưng cũng có sẵn cho windows [ 2 ] ), nó tồn tại sortlệnh có khả năng chạy song song trong các bộ xử lý đa lõi: thông thường là đủ.

Nếu tệp của bạn quá lớn, bạn có thể giúp xử lý tách ( split -l), tệp trong một số khối, có thể sử dụng tùy chọn song song ( --parallel) và sắp xếp các khối được sắp xếp theo thứ tự với -mtùy chọn ( sắp xếp hợp nhất ).
Một trong nhiều cách để làm điều đó được giải thích ở đây (chia tệp, sắp xếp các khối đơn, hợp nhất các khối được đặt hàng, xóa các tệp tạm thời).

Ghi chú:

  • Trong windows 10 tồn tại cái gọi là Hệ thống con Windows cho Linux, trong đó tất cả các ví dụ về Linux sẽ có vẻ tự nhiên hơn.
  • Sắp xếp với các thuật toán khác nhau có thời gian thực hiện khác nhau theo tỷ lệ là hàm số lượng mục nhập dữ liệu sẽ được sắp xếp (O (n m ), O (nlogn) ...).
  • Hiệu quả của thuật toán phụ thuộc vào thứ tự đã có trong tệp gốc.
    (Ví dụ: sắp xếp bong bóng là thuật toán nhanh nhất cho một tệp đã được đặt hàng - chính xác là N -, nhưng nó không hiệu quả trong các trường hợp khác).

2

Để cung cấp một giải pháp thay thế cho Peter H, có một chương trình q cho phép các lệnh kiểu SQL đối với các tệp văn bản. Lệnh dưới đây sẽ làm tương tự (chạy từ dấu nhắc lệnh trong cùng thư mục với tệp), mà không cần phải cài đặt SQL Workbench hoặc tạo bảng.

q "select * from words.txt order by c1"

c1 là tốc ký cho cột 1.

Bạn có thể loại trừ các từ trùng lặp với

q "select distinct c1 from words.txt order by c1"

và gửi đầu ra cho một tập tin khác

q "select distinct c1 from words.txt order by c1" > sorted.txt

Bất kỳ ý tưởng cho dù điều này sẽ đối phó với một tập tin 800 gig?
Rawling

1
Tôi không chắc chắn 100% - Tôi đã thử nghiệm ở trên với tệp 1200 dòng (9KB). Trang nhà phát triển có trang "giới hạn" không đề cập bất cứ điều gì về kích thước tệp tối đa. Một tập tin lớn vẫn có thể gặp phải vấn đề về bộ nhớ.
Brian

3
q không thể xử lý lượng dữ liệu này, hãy nhớ rằng q sử dụng SQLite phía sau cảnh nếu tôi không thể tải dữ liệu trực tiếp vào SQLite, điều gì khiến bạn nghĩ rằng q có thể?
MaYaN

2

Nếu các từ trên mỗi dòng là từ một từ vựng hạn chế (như tiếng Anh) thì bạn có thể sắp xếp danh sách theo thời gian O (n + m log m) bằng TreeMap và số lần ghi (trong đó m là số lượng giá trị duy nhất).

Nếu không, bạn có thể sử dụng thư viện java sắp xếp lớn . Nó phân tách đầu vào để sắp xếp các tệp trung gian và hợp nhất chúng một cách hiệu quả (tổng thể O (nlogn)). Để sắp xếp tệp của bạn trông như thế này:

Sorter.serializerTextUtf8()
      .input(inputFile)
      .output(outputFile)
      .loggerStdOut() // display some progress
      .sort();

Tôi đã tạo một tệp 1,7 GB (100m dòng) với 16 từ ký tự được tạo ngẫu nhiên và sắp xếp nó như trên trong 142 giây và dựa trên độ phức tạp tính toán của O (n log n) của phương pháp tôi đang sử dụng Tôi ước tính rằng 800 GB từ 16 ký tự sẽ mất khoảng 24 giờ để sắp xếp một luồng trên máy tính xách tay i5 2.3GHz của tôi với SSD.

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.