Windows'ta son derece büyük (800 GB) bir metin dosyasının içeriğini sıralama


25

Her satırda bir kelimesi olan bir metin dosyasına sahibim, dosyanın boyutu 800GB. Kelimeleri alfabetik olarak sıralamam gerekiyor.

Aşağıdakileri kullanarak Windows sıralama programını kullanmayı denedim :

sort.exe input.txt /o output.txt

Bu da hata veriyor: Sıralamayı tamamlamak için yeterli ana bellek yok.

Ben 32GB var RAM kullanıyorum tür hafıza 10GB belirtmeyi deneyin böylece zaman:

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

Alırım:

Uyarı: belirtilen hafıza boyutu mevcut disk belleği belleğine düşürülüyor.

Giriş kaydı maksimum uzunluğu aşıyor. Daha büyük maksimum belirtin.

Seçeneklerim neler?



10
Bu bir çapraz mesaj değil, bu yüzden bir makine değilim, bunu postalamak ve diğerini silmek birkaç dakika alır!
MaYaN

3
Gelecekte, topluluğun sorunuzu
aşmasına

4
Linux ile bu yöntemi uygulayabilirsiniz . 100Mb dosyaları ile büyük bir sorun olmamalıdır.
Eric Duminil

3
Hangi Windows sürümünü kullanıyorsunuz? Oldukça eski Windows Server 2012 R2 bulunan sort.exe, diskteki geçici bir dosya kullanarak (boyut sınırı belgelenmeden) harici birleştirme sıralaması yapabileceğini iddia ediyor. Geçici dosya için 800 Gb boş disk seçmek için / T düğmesini kullanın. Ve "giriş kaydı maksimum uzunluğu aşıyor" mesajı alanla ilgisiz görünüyor - / REC seçeneğine bakın ve satır sonlandırıcınızın ne olduğunu düşünün.
davidbak

Yanıtlar:


16

Seçeneklerim neler?

Deneyin SORULAR Komut Satırı Yardımcı CMSort sıralama .

Birden çok geçici dosya kullanır ve sonunda bunları birleştirir.

CMsort, ayarlanmış hafızaya ulaşılana kadar bir giriş dosyasının kayıtlarını okuyor. Daha sonra kayıtlar sıralanır ve geçici bir dosyaya yazılır. Bu, tüm kayıtlar işlenene kadar tekrarlanacaktır. Son olarak, tüm geçici dosyalar çıktı dosyasına birleştirilir. Kullanılabilir hafıza yeterliyse, geçici bir dosya yazılmaz ve birleştirme gerekmez.

Bir kullanıcı 130.000.000 baytlık bir dosyayı sıraladığını bildirdi.

Kendinizin bir kodunu değiştirmek istiyorsanız, ayrıca Büyük Metin Dosyalarını Sıralama - CodeProject - "Metin dosyalarının boyutunda kullanılabilir belleği geçen satırları sıralama algoritması" da vardır.


26
Vay, 130 megabayt !!! +1
David Foerster

3
@DavidPostill Windows için coreutil'den gelen sıralamanın daha verimli --parallelolmadığından emin misiniz ( birden fazla çekirdeğiniz varsa seçenek ...)?
Hastur

23

Diğer bir seçenek de dosyayı bir Veritabanına yüklemek. EG MySQL ve MySQL Tezgahı.
Veritabanları büyük dosyalarla çalışmak için mükemmel adaylardır

Giriş dosyanız yalnızca yeni bir satıra ayrılmış kelimeler içeriyorsa, bu zor olmamalıdır.

Veritabanını ve MySQL Workbench'i kurduktan sonra yapmanız gereken şey budur.
Öncelikle şema oluşturun (bu, argüman değerini artırarak değiştirebilmenize rağmen, kelimelerin 255 karakterden daha uzun olmayacağını varsayar). İlk sütun "idwords" bir birincil anahtardır.

CREATE SCHEMA `tmp` ;

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

İkincisi, verileri içe aktarın: EG Bu, tüm kelimeleri tabloya aktaracaktır (bu adımın tamamlanması biraz zaman alabilir. Tavsiyem, önce küçük kelimeli bir dosya içeren bir test yapmak ve formatın aynı olduğundan emin olduğunuzda) daha büyük (tabloyu kes. .. IE Temizle) ve tüm veri setini yükle).

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


Bu bağlantı, yük için doğru formatın alınmasına yardımcı olabilir. https://dev.mysql.com/doc/refman/5.7/en/load-data.html
EG İlk satırı atlamak gerekirse, aşağıdakileri yaparsınız.

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

Sonunda sıralanmış dosyayı kaydedin. Bu, bilgisayarınıza bağlı olarak da biraz zaman alabilir.

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

İstediğiniz gibi istediğiniz gibi verileri de arayabilirsiniz. EG Bu size ilk sıradaki 50 kelimeyi artan bir sıra ile verir (0 ya da ilk kelimeden başlayarak).

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

İyi şanslar
Pete


2
Bu IS hatırı sayılır bir farkla doğru cevap.
MonkeyZeus

1
Bu yaklaşım kesinlikle daha esnek olacaktır, özellikle de sıralamayı farklı bir düzende yeniden çalıştırmanız gerektiğini keşfederseniz.
barbekü

MySQL , MariaDB veya diğer herhangi bir DBMS örneğinizin ne kadar hızlı olduğu umurumda değil , aynı makinede çalışan SQLite ekleme performansına yakın bir yere gelmeyecek . SQLite kadar hızlı bir şey olsa bile, bu miktarda veri işlemek için çok fazla (ve yavaştır) (güven bana önce bunu denedim!), Bu yüzden en iyi çözüm ilk önce kopyaları sıralamak ve kaldırmak, sonra da SQLite gibi bir DB'ye eklemek . Dolayısıyla bu çözüm bazı durumlar için geçerli olsa da kesinlikle yapmaya çalıştığım şey için değil. Buna zaman göndermek için zaman ayırdığınız için teşekkür ederiz.
MaYaN

Tarafından sipariş mywordssonsuza kadar sürecek. Bununla birlikte, LIMITher şey çok uzun sürecek çünkü MySQL'in her değerden geçmesi mywordsve sipariş etmesi gerekiyor. Bunu düzeltmek için, yaptıktan sonra aşağıdakileri yapmanız gerekir LOAD DATA. Dizinini ekle mywords. Şimdi bu sütuna göre sipariş verebilirsiniz ve bin yıl sürmemesini sağlayabilirsiniz. Ve olduğu veriyi yükledikten sonra yerine tabloyu oluşturdu zaman (çok daha hızlı veri yükü) olarak dizin eklemek daha iyi.
Buttle Butkus

7

sort

Sıralı ve sıralı olmayan dosyaları sıralamak için kullanılan birçok algoritma vardır [ 1 ] .
Tüm bu algoritmalar zaten uygulanmış olduğundan, zaten test edilmiş bir program seçin.

Gelen coreutils (Linux ancak Windows için uygun çok [ 2 ] ), bu mevcut sortçok çekirdekli işlemci altında paralel bir şekilde çalıştırmak için yetenekli komutu: genellikle yeterlidir.

Dosyanız kadar büyük sen işleme bölme (yardımcı olabilir split -lmuhtemelen paralel seçeneği (kullanarak), bazı parçalar dosyayı --parallel) ve sonuçlandı sıralama sipariş-parçalarını ile -mseçeneği ( birleştirme tür ).
Bunu yapmanın birçok yolundan biri burada açıklanmaktadır (dosya bölme, tek parça sipariş etme, sipariş edilen parça parça birleştirme, geçici dosyaları silme).

Notlar:

  • Windows 10'da, tüm Linux örneğinin daha doğal görüneceği Linux için Windows Alt Sistemi adı verilir .
  • Farklı algoritmalarla sıralama, sıralanacak veri girişi sayısının fonksiyonu olarak ölçeklendirilen farklı yürütme sürelerine sahiptir (O ​​(n m ), O (nlogn) ...).
  • Algoritmanın etkinliği, orijinal dosyada zaten mevcut olan sıraya bağlıdır.
    (Örneğin, bir kabarcık sıralama zaten sipariş edilmiş bir dosya için en hızlı algoritmadır - tam olarak N -, ancak diğer durumlarda etkili değildir).

2

Peter H'ye alternatif bir çözüm sunmak için, metin dosyalarına karşı SQL stil komutlarına izin veren bir program q vardır. Aşağıdaki komut, SQL Workbench'i kurmaya veya tablo oluşturmaya gerek kalmadan, aynı şeyi yapar (komut isteminden aynı dizinde çalıştırılır).

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

c1 sütun 1 için kısaca.

İle yinelenen kelimeleri hariç tutabilirsiniz.

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

ve çıktıyı başka bir dosyaya gönderin

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

Bunun 800 gig dosyasıyla baş edip edemeyeceği konusunda bir fikrin var mı?
Rawling

1
% 100 emin değilim - Yukarıdakileri 1200 satırlık bir dosyayla (9KB) test ettim. Geliştiriciler sayfasının, maksimum dosya boyutu hakkında hiçbir şeyden söz etmeyen bir "sınırlamalar" sayfası vardır. Büyük bir dosya hala bir bellek sorununa karşı gelebilir.
Brian

3
q veriler unutmayın bu miktarı işleyemez q kullanan SQLite Veri doğrudan yüklenemedi eğer sahnenin arkasında SQLite sizce ne yapar q can?
MaYaN

2

Her satırdaki sözcükler sınırlı bir kelimeden geliyorsa (İngilizce gibi) o zaman bir TreeMap ve kayıt sayıları kullanarak listeyi O (n + m log m) zamanına göre sıralayabilirsiniz (burada m, benzersiz değerlerin sayısıdır).

Aksi takdirde java kütüphanesini big-sıralayıcısı kullanabilirsiniz . Girdiyi sıralanmış ara dosyalara böler ve onları verimli bir şekilde birleştirir (genel O (nlogn)). Dosyanızı sıralamak için şöyle görünür:

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

Rasgele oluşturulmuş 16 karakter kelimesiyle bir 1.7GB'lık dosya (100m satır) oluşturdum ve onu 142'lerde yukarıdaki gibi sıraladım ve kullandığım yöntemin O (n logn) işlemsel karmaşıklığına dayanarak kullandım. iD 2.3GHz dizüstü bilgisayarımda SSD'li tek iş parçacıklı dizimi sıralamak yaklaşık 24 saatimi alıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.