จัดเรียงเนื้อหาของไฟล์ข้อความที่มีขนาดใหญ่มาก (800GB) บน Windows


25

ฉันมีไฟล์ข้อความที่มีคำในแต่ละบรรทัดขนาดของไฟล์คือ 800GB ฉันต้องการเรียงลำดับตัวอักษรตามลำดับตัวอักษร

ฉันได้ลองใช้โปรแกรมเรียงลำดับWindows โดยใช้:

sort.exe input.txt /o output.txt

ซึ่งให้ข้อผิดพลาด: หน่วยความจำหลักไม่เพียงพอที่จะทำการเรียงลำดับให้เสร็จสมบูรณ์

ฉันมีRAMขนาด 32GB ดังนั้นเมื่อฉันลองระบุหน่วยความจำ 10GB สำหรับการเรียงลำดับโดยใช้:

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

ฉันเข้าใจ:

คำเตือน: ขนาดหน่วยความจำที่ระบุลดลงเป็นหน่วยความจำการเพจที่มีอยู่

บันทึกอินพุตเกินความยาวสูงสุด ระบุค่าสูงสุดที่ใหญ่กว่า

ตัวเลือกของฉันคืออะไร?



10
นี่ไม่ใช่การโพสต์ข้ามฉันไม่ใช่เครื่องจักรดังนั้นการโพสต์สิ่งนี้และการลบรายการอื่นใช้เวลาสองสามนาที!
MaYaN

3
ในอนาคตอนุญาตให้ชุมชนโยกย้ายคำถามของคุณ
Ramhound

4
ด้วย Linux คุณสามารถใช้วิธีนี้ได้ ด้วยไฟล์ขนาด 100Mb ไม่ควรเป็นปัญหาใหญ่
Eric Duminil

3
คุณใช้ Windows รุ่นใดอยู่ sort.exe ที่มี Windows Server 2012 R2 ค่อนข้างเก่าอ้างว่าสามารถทำการผสานภายนอกด้วยการใช้ไฟล์ชั่วคราวบนดิสก์ (โดยไม่บันทึกขนาด จำกัด ) ลองใช้ / T เพื่อระบุดิสก์ที่มี 800Gb ฟรีสำหรับไฟล์ชั่วคราว และข้อความเกี่ยวกับ "บันทึกอินพุตเกินความยาวสูงสุด" ดูเหมือนว่าไม่เกี่ยวข้องกับพื้นที่ - ดูที่ตัวเลือก / REC และพิจารณาว่าเทอร์มินอลไลน์ของคุณคืออะไร
davidbak

คำตอบ:


16

ตัวเลือกของฉันคืออะไร?

ลองฟรีแวร์บรรทัดคำสั่งเรียงยูทิลิตี้ CMSort

มันใช้ไฟล์ชั่วคราวหลายไฟล์แล้วรวมเข้าด้วยกันในตอนท้าย

CMsort กำลังอ่านบันทึกของไฟล์อินพุตจนกว่าจะถึงหน่วยความจำที่ปรับแล้ว จากนั้นระเบียนจะถูกจัดเรียงและเขียนลงในไฟล์ชั่วคราว จะทำซ้ำจนกว่าจะมีการประมวลผลบันทึกทั้งหมด ในที่สุดไฟล์ชั่วคราวทั้งหมดจะถูกรวมเข้าไปในไฟล์เอาต์พุต หากหน่วยความจำที่มีอยู่เพียงพอไม่เขียนไฟล์ชั่วคราวและไม่จำเป็นต้องรวมเข้าด้วยกัน

ผู้ใช้รายหนึ่งรายงานว่าเรียงลำดับไฟล์เป็น 130,000,000 ไบต์

หากคุณต้องการปรับแต่งโค้ดด้วยตัวคุณเองก็ยังมีการเรียงไฟล์ข้อความขนาดใหญ่ - CodeProject - "อัลกอริทึมของการเรียงลำดับบรรทัดในขนาดไฟล์ข้อความที่เกินกว่าหน่วยความจำที่มีอยู่"


26
ว้าว 130 เมกะไบต์ !!! +1
David Foerster

3
@DavidPostill คุณแน่ใจหรือไม่ว่าการเรียงลำดับจากcoreutils สำหรับ windowsไม่มีประสิทธิภาพมากขึ้น ( --parallelตัวเลือกหากคุณมีมากกว่าหนึ่งแกน ... )
Hastur

23

อีกตัวเลือกหนึ่งคือการโหลดไฟล์ลงในฐานข้อมูล EG MySQL และ MySQL Workbench
ฐานข้อมูลเป็นตัวเลือกที่สมบูรณ์แบบสำหรับการทำงานกับไฟล์ขนาดใหญ่

หากไฟล์อินพุตของคุณมีเพียงคำที่คั่นด้วยบรรทัดใหม่สิ่งนี้ไม่ควรยาก

หลังจากที่คุณติดตั้งฐานข้อมูลและ MySQL Workbench นี่คือสิ่งที่คุณต้องทำ
ขั้นแรกให้สร้างสคีมา (ซึ่งจะถือว่าคำไม่ยาวเกิน 255 อักขระแม้ว่าคุณจะสามารถแก้ไขได้โดยการเพิ่มค่าอาร์กิวเมนต์) คอลัมน์แรก "idwords" เป็นคีย์หลัก

CREATE SCHEMA `tmp` ;

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

ประการที่สองนำเข้าข้อมูล: EG สิ่งนี้จะนำเข้าคำทั้งหมดลงในตาราง (ขั้นตอนนี้อาจใช้เวลาสักครู่จนเสร็จสมบูรณ์คำแนะนำของฉันจะทำการทดสอบด้วยไฟล์คำเล็ก ๆ ก่อนและเมื่อคุณแน่ใจว่ารูปแบบนั้นเหมือนกัน อันที่ใหญ่กว่า (ตัดทอนตาราง .. IE ลบออกและโหลดชุดข้อมูลแบบเต็ม)

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


ลิงค์นี้อาจช่วยให้การจัดรูปแบบถูกต้องสำหรับการโหลด https://dev.mysql.com/doc/refman/5.7/en/load-data.html
EG หากคุณต้องการข้ามบรรทัดแรกคุณต้องทำสิ่งต่อไปนี้

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

ในที่สุดบันทึกไฟล์ที่เรียงลำดับ การดำเนินการนี้อาจใช้เวลาสักครู่ขึ้นอยู่กับพีซีของคุณ

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

คุณยังสามารถค้นหาข้อมูลได้ตามต้องการ EG สิ่งนี้จะให้ 50 คำแรกตามลำดับจากน้อยไปหามาก (เริ่มจากคำที่ 0 หรือคำแรก)

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

ขอให้โชคดี
พีท


2
นี่คือคำตอบที่ถูกต้องด้วยส่วนต่างที่สำคัญ
MonkeyZeus

1
วิธีการนี้จะมีความยืดหยุ่นมากขึ้นโดยเฉพาะอย่างยิ่งหากคุณพบว่าคุณจำเป็นต้องเรียกใช้การเรียงลำดับใหม่ด้วยลำดับที่แตกต่างกัน
บาร์บีคิว

ฉันไม่สนใจว่าอินสแตนซ์ของMySQL , MariaDBหรือDBMSอื่น ๆของคุณนั้นเร็วแค่ไหนมันจะไม่เข้าใกล้ประสิทธิภาพการแทรกของSQLite ที่ทำงานบนเครื่องเดียวกัน ถึงแม้จะมีบางสิ่งบางอย่างให้เร็วที่สุดเท่าSQLiteปริมาณของข้อมูลนี้เป็นมากเกินไป (และช้า) กับกระบวนการ (ความไว้วางใจฉันฉันพยายามที่แรก!) ดังนั้นทางออกที่ดีที่สุดคือการจัดเรียงและลบที่ซ้ำกันครั้งแรกแล้วใส่ไปยังฐานข้อมูลเช่นข้อมูล SQLite ดังนั้นในขณะที่วิธีนี้อาจใช้งานได้ในบางกรณีแน่นอนว่าไม่ใช่สำหรับสิ่งที่ฉันพยายามทำ ขอบคุณที่สละเวลาโพสต์เรื่องนี้อยู่ดี
MaYaN

การสั่งซื้อโดยmywordsจะใช้เวลาตลอดไป แม้LIMITจะใช้เวลานานเท่าที่ทุกอย่างเพราะ MySQL จะต้องผ่านทุกค่าmywordsและสั่งซื้อ ในการแก้ไขปัญหานี้คุณต้องทำสิ่งต่อไปนี้หลังจากคุณทำเสร็จLOAD DATAแล้ว mywordsเพิ่มดัชนี ตอนนี้คุณสามารถสั่งซื้อตามคอลัมน์นั้นและไม่ต้องใช้เวลานับพันปี และเป็นการดีกว่าที่จะเพิ่มดัชนีหลังจากโหลดข้อมูลแทนที่จะเป็นเวลาที่คุณสร้างตาราง (โหลดข้อมูลเร็วขึ้นมาก)
Buttle Butkus

7

sort

มีขั้นตอนวิธีการที่ใช้ในการจัดเรียงสั่งซื้อและไฟล์ที่ไม่ได้สั่งซื้อ[ 1 ]
เนื่องจากอัลกอริธึมเหล่านั้นมีการใช้งานแล้วให้เลือกโปรแกรมที่ทดสอบแล้ว

ในcoreutils (จาก Linux แต่มีให้สำหรับ windows ด้วย[ 2 ] ) มันมีsortคำสั่งที่สามารถทำงานแบบขนานภายใต้ตัวประมวลผลแบบมัลติคอร์: ปกติแล้วมันก็เพียงพอแล้ว

หากไฟล์ของคุณมีขนาดใหญ่มากคุณสามารถช่วยในการแยกการประมวลผล ( split -l) ไฟล์ในบางชิ้นอาจใช้ตัวเลือกแบบขนาน ( --parallel) และเรียงลำดับผลการสั่งซื้อชิ้นด้วย-mตัวเลือก ( ผสานการเรียง )
หนึ่งในหลาย ๆ วิธีที่จะอธิบายได้ที่นี่ (แบ่งไฟล์สั่งชิ้นส่วนเดียวรวมกลุ่มสั่งลบลบไฟล์ temp)

หมายเหตุ:

  • ใน windows 10 มีอยู่แล้วที่เรียกว่าระบบย่อย Windows สำหรับ Linuxซึ่งตัวอย่าง Linux ทั้งหมดจะดูเป็นธรรมชาติมากขึ้น
  • การเรียงลำดับด้วยอัลกอริธึมที่แตกต่างกันมีเวลาดำเนินการที่แตกต่างกันตามขนาดของฟังก์ชั่นของจำนวนข้อมูลที่จะเรียงลำดับ (O (n m ), O (nlogn) ... )
  • ประสิทธิภาพของอัลกอริทึมขึ้นอยู่กับลำดับที่มีอยู่แล้วในไฟล์ต้นฉบับ
    (ตัวอย่างเช่นการเรียงลำดับฟองเป็นอัลกอริทึมที่เร็วที่สุดสำหรับไฟล์ที่สั่งซื้อแล้ว - ตรง N - แต่มันก็ไม่ได้มีประสิทธิภาพในกรณีอื่น ๆ )

2

เพื่อเสนอทางเลือกอื่นให้กับ Peter H มีโปรแกรมqที่อนุญาตให้ใช้คำสั่งแบบ SQL กับไฟล์ข้อความ คำสั่งด้านล่างจะทำเช่นเดียวกัน (เรียกใช้จากพรอมต์คำสั่งในไดเรกทอรีเดียวกันกับไฟล์) โดยไม่จำเป็นต้องติดตั้ง SQL Workbench หรือสร้างตาราง

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

c1 จดชวเลขสำหรับคอลัมน์ 1

คุณสามารถยกเว้นคำที่ซ้ำกันด้วย

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

และส่งออกไปยังไฟล์อื่น

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

มีความคิดว่าสิ่งนี้จะรับมือกับไฟล์ 800 กิ๊กหรือไม่?
Rawling

1
ฉันไม่แน่ใจ 100% - ฉันทดสอบข้างต้นด้วยไฟล์ 1200 บรรทัด (9KB) หน้านักพัฒนามีหน้า "ข้อ จำกัด " ที่ไม่ได้กล่าวถึงขนาดไฟล์สูงสุด ไฟล์ขนาดใหญ่อาจยังคงมีปัญหาหน่วยความจำ
Brian

3
Qไม่สามารถดำเนินการจำนวนนี้ของข้อมูลจำไว้ว่าQใช้SQLiteเบื้องหลังถ้าฉันไม่สามารถโหลดข้อมูลโดยตรงไปยังSQLiteสิ่งที่ทำให้คุณคิดQสามารถ?
MaYaN

2

หากคำในแต่ละบรรทัดมาจากคำศัพท์ที่ จำกัด (เช่นภาษาอังกฤษ) คุณสามารถเรียงลำดับรายการในเวลา O (n + m log m) โดยใช้ TreeMap และจำนวนการบันทึก (โดยที่ m คือจำนวนค่าที่ไม่ซ้ำกัน)

มิฉะนั้นคุณสามารถใช้ห้องสมุด Java ใหญ่เรียงลำดับ มันแยกอินพุตไปยังไฟล์ระดับกลางที่เรียงลำดับแล้วผสานเข้าด้วยกันอย่างมีประสิทธิภาพ (โดยรวม O (nlogn)) ในการจัดเรียงไฟล์ของคุณมีลักษณะดังนี้:

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

ฉันสร้างไฟล์ 1.7GB (100m บรรทัด) โดยสร้างคำ 16 อักขระแบบสุ่มและเรียงตามข้างต้นใน 142s และขึ้นอยู่กับความซับซ้อนในการคำนวณ O (n log n) ของวิธีที่ฉันใช้ฉันประเมินว่า 800GB จาก 16 ตัวอักษรจะ ใช้เวลาประมาณ 24 ชั่วโมงในการจัดเรียงเธรดเดี่ยวบนแล็ปท็อป i5 2.3GHz ของฉันกับ SSD

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.