Ordina i contenuti di un file di testo estremamente grande (800 GB) su Windows


25

Ho un file di testo con una parola in ogni riga, la dimensione del file è di 800 GB. Devo ordinare le parole in ordine alfabetico.

Ho provato a utilizzare il programma di ordinamento di Windows utilizzando:

sort.exe input.txt /o output.txt

che dà l'errore: memoria principale insufficiente per completare l'ordinamento.

Ho 32 GB di RAM, quindi quando provo a specificare 10 GB di memoria per l'ordinamento usando:

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

Ottengo:

Avviso: la dimensione della memoria specificata viene ridotta alla memoria di paging disponibile.

Il record di input supera la lunghezza massima. Specifica un massimo più grande.

Quali sono le mie opzioni?



10
Questo non è un cross-post, non sono una macchina, quindi pubblicare questo ed eliminare l'altro richiede alcuni minuti!
MaYaN

3
In futuro permetti alla comunità di emigrare la tua domanda
Ramhound

4
Con Linux, è possibile applicare questo metodo . Con file di 100 Mb, non dovrebbe essere un grosso problema.
Eric Duminil,

3
Quale versione di Windows stai usando? Sort.exe con il piuttosto vecchio Windows Server 2012 R2 afferma di essere in grado di eseguire un ordinamento di unione esterno con l'uso di un file temporaneo su disco (senza documentare un limite di dimensioni). Prova a utilizzare / T per specificare un disco con 800 GB gratuiti per il file temporaneo. E il messaggio sul "record di input supera la lunghezza massima" sembra non correlato allo spazio - guarda l'opzione / REC e considera qual è il tuo terminatore di linea.
davidbak,

Risposte:


16

Quali sono le mie opzioni?

Prova Freeware Command Line Sort Utility CMSort .

Utilizza più file temporanei e li unisce alla fine.

CMsort sta leggendo i record di un file di input fino al raggiungimento della memoria regolata. Quindi i record vengono ordinati e scritti in un file temporaneo. Questo verrà ripetuto fino a quando non verranno elaborati tutti i record. Infine, tutti i file temporanei vengono uniti nel file di output. Se la memoria disponibile è sufficiente, non vengono scritti file temporanei e non è necessaria l'unione.

Un utente segnala di aver ordinato un file di 130.000.000 di byte.

Se vuoi modificare da solo un po 'di codice, c'è anche l' ordinamento di file di testo enormi - CodeProject - "Algoritmo di linee di ordinamento nella dimensione dei file di testo che supera la memoria disponibile"


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

3
@DavidPostill Sei sicuro che l'ordinamento da coreutils per Windows non sia più efficiente ( --parallelopzione se hai più di un core ...)?
Hastur,

23

Un'altra opzione è quella di caricare il file in un database. EG MySQL e MySQL Workbench.
I database sono candidati perfetti per lavorare con file di grandi dimensioni

Se il tuo file di input contiene solo parole separate da una nuova riga, questo non dovrebbe essere troppo difficile.

Dopo aver installato il database e MySQL Workbench questo è ciò che dovresti fare.
Per prima cosa crea lo schema (questo presuppone che le parole non saranno più lunghe di 255 caratteri anche se potresti modificarlo aumentando il valore dell'argomento). La prima colonna "idwords" è una chiave primaria.

CREATE SCHEMA `tmp` ;

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

In secondo luogo importare i dati: EG Questo importerà tutte le parole nella tabella (questo passaggio potrebbe richiedere del tempo per il completamento. Il mio consiglio sarebbe di eseguire prima un test con un piccolo file di parole e una volta che sei sicuro che il formato sia lo stesso di il più grande (troncare la tabella .. IE Cancellarlo e caricare il set di dati completo).

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


Questo link può aiutare a ottenere il formato giusto per il caricamento. https://dev.mysql.com/doc/refman/5.7/en/load-data.html
EG Se fosse necessario saltare la prima riga, procedere come segue.

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

Infine salva il file ordinato. Questo potrebbe richiedere del tempo anche a seconda del tuo PC.

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

Puoi anche cercare i dati a tuo piacimento. EG Questo ti darà le prime 50 parole in ordine crescente (a partire dalla 0a o prima parola).

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

Buona fortuna
Pete


2
Questa è la risposta corretta con un margine considerevole.
MonkeyZeus

1
Questo approccio sarà sicuramente più flessibile, soprattutto se scopri che è necessario rieseguire l'ordinamento con un ordine diverso, ad esempio.
barbecue

Non mi interessa quanto sia veloce la tua istanza di MySQL , MariaDB o qualsiasi altro DBMS , non arriverà in alcun modo vicino alle prestazioni di inserimento di SQLite in esecuzione sulla stessa macchina. Anche con qualcosa di veloce come SQLite questa quantità di dati è troppo (e lenta) da elaborare (credetemi, l'ho provato prima!), Quindi la soluzione migliore è ordinare e rimuovere prima i duplicati, quindi inserirli in un DB come SQLite . Quindi, sebbene questa soluzione possa essere valida per alcuni casi, certamente non è per quello che sto cercando di fare. Grazie per aver dedicato del tempo a pubblicare questo comunque.
MaYaN,

Ordinare entro mywordsrichiederà un'eternità. Anche con il LIMIT, ci vorrà tutto il tempo perché MySQL dovrà esaminare ogni singolo valore mywordse ordinarli. Per risolvere questo problema, devi fare quanto segue dopo averlo fatto LOAD DATA. Aggiungi un indice a mywords. Ora puoi ordinare per quella colonna e non avere un millennio. Ed è meglio aggiungere l'indice dopo aver caricato i dati anziché al momento in cui è stata creata la tabella (caricamento dei dati molto più veloce).
Buttle Butkus,

7

sort

Esistono molti algoritmi utilizzati per ordinare i file ordinati e non ordinati [ 1 ] .
Poiché tutti questi algoritmi sono già implementati, scegli un programma già testato.

In coreutils (da Linux ma disponibile anche per Windows [ 2 ] ), esiste il sortcomando in grado di funzionare in parallelo con processori multi-core: di solito è sufficiente.

Se il tuo file è così grande , puoi aiutare a dividere l'elaborazione ( split -l), il file in alcuni blocchi, possibilmente usando l'opzione parallela ( --parallel), e ordinare i blocchi ordinati risultanti con l' -mopzione ( unisci ordinamento ).
Uno dei molti modi per farlo è spiegato qui (dividere il file, ordinare singoli pezzi, unire i pezzi ordinati, eliminare i file temporanei).

Gli appunti:

  • In Windows 10 esiste il cosiddetto sottosistema Windows per Linux in cui tutto l'esempio di Linux sembrerà più naturale.
  • L'ordinamento con algoritmi diversi ha tempi di esecuzione diversi che si ridimensionano in funzione del numero di voci di dati da ordinare (O (n m ), O (nlogn) ...).
  • L'efficienza dell'algoritmo dipende dall'ordine già presente nel file originale.
    (Ad esempio, un ordinamento a bolle è l'algoritmo più veloce per un file già ordinato - esattamente N -, ma non è efficiente in altri casi).

2

Per offrire una soluzione alternativa a Peter H, esiste un programma q che consente comandi in stile SQL su file di testo. Il comando seguente farebbe lo stesso (eseguito dal prompt dei comandi nella stessa directory del file), senza la necessità di installare SQL Workbench o creare tabelle.

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

c1 è una scorciatoia per la colonna 1.

Puoi escludere parole duplicate con

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

e invia l'output a un altro file

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

Hai idea se questo riuscirà a far fronte a un file da 800 gig?
Rawling

1
Non sono sicuro al 100%: ho testato quanto sopra con un file di 1200 righe (9 KB). La pagina degli sviluppatori ha una pagina "limitazioni" che non menziona nulla sulla dimensione massima del file. Un file di grandi dimensioni può ancora incontrare un problema di memoria.
Brian

3
q non è in grado di elaborare questa quantità di dati ricordare che q utilizza SQLite dietro la scena se non sono riuscito a caricare i dati direttamente su SQLite cosa ti fa pensare che q possa?
MaYaN,

2

Se le parole su ciascuna riga provengono da un vocabolario limitato (come l'inglese), puoi ordinare l'elenco in O (n + m log m) tempo usando una TreeMap e registrando i conteggi (dove m è il numero di valori univoci).

Altrimenti puoi usare la libreria java big-sorter . Suddivide l'input in file intermedi ordinati e li unisce in modo efficiente (O generale (nlogn)). Per ordinare il tuo file è simile al seguente:

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

Ho creato un file da 1,7 GB (linee da 100m) con parole di 16 caratteri generate casualmente e l'ho ordinato come sopra in 142s e basato sulla complessità computazionale O (n log n) del metodo che sto usando stima che 800 GB di parole di 16 caratteri sarebbero impiega circa 24 ore per ordinare single-threaded sul mio laptop i5 2.3GHz con SSD.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.