Dizeyi büyük (70GB), tek satırlı, metin dosyasında değiştirin


126

Büyük bir (70GB), bir satır , metin dosyasına sahibim ve içindeki bir dizgiyi (token) değiştirmek istiyorum. Belirteci <unk>, başka bir sahte belirteçle değiştirmek istiyorum ( eldiven sorunu ).

Denedim sed:

sed 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

ancak çıktı dosyasının corpus.txt.newsıfır baytı var!

Perl kullanarak da denedim:

perl -pe 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

ama yetersiz bellek hatasıyla karşılaştım.

Daha küçük dosyalar için, yukarıdaki komutların ikisi de çalışır.

Nasıl bir dize değiştirebilirim böyle bir dosyadır? Bu ilgili bir soru, ancak cevapların hiçbiri benim için çalıştı.

Düzenleme : Dosyayı sedher biri 10GB'lık (veya her neyse) parçalara bölmek ve her birine uygulamak ve daha sonra bunları birleştirmek cat? bu mantıklı mı? Daha zarif bir çözüm var mı?


@Gilles’in belirttiği gibi, tek büyük çizginizde özel sınırlayıcı olarak işlev görebilecek bazı tekrarlanan karakterleri tespit edebiliyor musunuz?
RomanPerekhrest

Sadece arama ve değiştirme yapabilen, ancak daha karmaşık bir regex yapamayan bir aracın daha hızlı olacağını düşünüyorum. Aynı zamanda bir satır yapmaktan da faydalanmayacağından, bu dosyada boğulmayacaktı. Ne yazık ki, böyle bir aracın varlığı hakkında hiçbir fikrim yok, ancak yazmak zor olmasa da. Biri kapalıysa, cevaplardan birinde olduğu gibi yeni satır karakterleri koymak muhtemelen en kolayı olacaktır.
ctrl-alt-delor

Dosyanız ASCII dışında bir şey içeriyor mu? Eğer öyleyse, tüm unicode işleme ihmal edilebilir ve işlenmemiş bayt işlenebilir.
Patrick Bucher,

@PatrickButcher ile aynı fikirdeyim Daha büyük bir resme bak. Bu metni hemen değiştirme ihtiyacının yanı sıra, bu dosyanın başka hangi amaçla kullanılması gerekiyor? Bir tür kütük ise, kimse onunla etkili bir şekilde çalışamaz. Bazı uygulamaların kullandığı bir veri dosyasıysa, o uygulama bu dosyadaki verileri koruma sorumluluğunu üstlenmelidir.
Thomas Carlisle

2
Sen kullanabilirsiniz splitile -bopsiyon bayt öbek dosya boyutları tanımlayan. Her birini sırayla kullanarak sedtekrar birleştirin. <unk>İki dosyaya bölünebilmesi ve bulunmaması riski var ...
Vladislavs Dovgalecs

Yanıtlar:


106

Normal metin işleme araçları RAM'e uymayan satırları işlemek için tasarlanmamıştır. Bir kaydı (bir satır) okuyup, işleyerek ve sonucu çıkarıp bir sonraki kayda (satır) geçerek çalışma eğilimindedirler.

Dosyada sıkça görünen ve içinde görünmeyen bir ASCII karakteri varsa <unk>veya <raw_unk>bu durumda, bunu kayıt ayırıcı olarak kullanabilirsiniz. Çoğu araç özel kayıt ayırıcılara izin vermediğinden, bu karakter ve yeni satırlar arasında geçiş yapın. trsatırları değil baytları işler, bu nedenle herhangi bir kayıt büyüklüğünü önemsemez. Diyelim ki ;işe yarıyor:

<corpus.txt tr '\n;' ';\n' |
sed 's/<unk>/<raw_unk>/g' |
tr '\n;' ';\n' >corpus.txt.new

Ayrıca, arama metninde tekrarlanmadığını ve yeterince sık göründüğünü varsayarsak, aradığınız metnin ilk karakterine demir atabilirsiniz. Dosya başlayabiliyorsa unk>, sed '2,$ s/…sahte bir eşleşmeyi önlemek için sed komutunu değiştirin .

<corpus.txt tr '\n<' '<\n' |
sed 's/^unk>/raw_unk>/g' |
tr '\n<' '<\n' >corpus.txt.new

Alternatif olarak, son karakteri kullanın.

<corpus.txt tr '\n>' '>\n' |
sed 's/<unk$/<raw_unk/g' |
tr '\n>' '>\n' >corpus.txt.new

Bu tekniğin, sed'nin yeni bir satırla bitmeyen bir dosya üzerinde sorunsuz bir şekilde çalıştığını, yani son kısmi satırı kesmeden ve son bir yeni satır eklemeden işlediğini varsaydığını unutmayın. GNU sed ile çalışır. Dosyanın son karakterini kayıt ayırıcı olarak seçebilirseniz, taşınabilirlik sorunlarından kaçınırsınız.


8
Sınamak için böyle bir dosya yok, ancak Awk içinde "Kayıt Ayırıcı" ve "Çıkış Kayıt Ayırıcı" belirtebilirsiniz. Yani, dosyanızda düzgün bir virgül yayılması olduğunu varsayarsak, şunu çözebilirsin: awk -v RS=, -v ORS=, '{gsub(/<unk>/, "<raw_unk>"); print}' Hayır?
Wildcard

4
@Wildcard Evet, bu başka bir çözüm. Awk, sed'den daha yavaş olma eğilimindedir, bu yüzden büyük bir dosya için tercih edilen bir çözüm olarak sunmuyorum.
Gilles,

Kayıt ayırıcıyı Perl'de komut satırı seçeneğiyle -0ve bir karakterin sekizlik değeriyle veya komut dosyası içinde özel değişkenle ayarlanabilir$/
beasy

@Gilles: Fakat kullanmak awk, akıntıyı iki kere geçmekten kaçınmak tr. Öyleyse hala daha yavaş olur mu?
user285259

2
@ user285259 Genellikle değil. trçok hızlı ve boru bile paralelleştirilebilir.
Gilles

110

Böyle büyük bir dosya için, bir olasılık Flex. Olsun unk.l:

%%
\<unk\>     printf("<raw_unk>");  
%%

Sonra derleyin ve yürütün:

$ flex -o unk.c  unk.l
$ cc -o unk -O2 unk.c -lfl
$ unk < corpus.txt > corpus.txt.new

5
makeBunun için varsayılan kuralları vardır, flex / cc yerine %option mainunk.l 'nin ilk satırı olarak ekleyebilir ve daha sonra sadece make unk. Ben daha çok ya da daha az refleksle kullanmak %option main 8bit fastve sahip export CFLAGS='-march=native -pipe -Os'skinTenimde .bashrc.
jthill

1
@ undercat: Konu dışı değilse, su seviyesi problemini çözmekten özel amaçlı girdi ayrıştırmaya kadar bir dizi derleyici olmayan ön uygulama gösterebilirim. Kutunun dışında biraz düşünmek istersen, onunla neler yapabileceğini görmek şaşırtıcı :-)
jamesqf

@jthill, teşekkür ederim: %option main+ make+ isteğe bağlı CFLAGSolarak çok güzel bir oyun! Mı -march=nativevarsayılan davranış?
JJoao,

1
Dediğiniz gibi @jamesqf - bu konuyla ilgili bir soru yapmak zor olacak - ama ben de görmek istiyorum
Steven Penny

1
@jamesqf Üniversitedeki bir profesör, bir fabrika için kumaş türlerini tanıyan bir araç oluşturmak için esnek kullandı! Şunun gibi bir soruyu sormaya ne dersiniz: "esnek çok güçlü bir araç gibi gözüküyor, ancak herhangi bir derleyici / ayrıştırıcı yazmam pek mümkün değil - esneklik için başka kullanım senaryoları var mı?"
Paul Evans,

41

Böylece tüm dosyayı bir seferde tutacak kadar fiziksel belleğe (RAM) sahip değilsinizdir , ancak 64 bit sistemde tüm dosyayı eşleştirmek için yeterli sanal adres alanına sahipsiniz . Sanal eşlemeler, bu gibi durumlarda basit bir hack olarak yararlı olabilir.

Gerekli işlemlerin tümü Python'a dahil edilmiştir. Birkaç can sıkıcı incelik vardır, ancak C kodu yazmak zorunda kalmaz. Özellikle, dosyayı tamamen kopyalayabilen belleğe kopyalamaktan kaçınmak için özen gösterilmelidir. Artı tarafta, ücretsiz hata raporlama alıyorsunuz (python "istisnalar") :).

#!/usr/bin/python3
# This script takes input from stdin
# (but it must be a regular file, to support mapping it),
# and writes the result to stdout.

search = b'<unk>'
replace = b'<raw_unk>'


import sys
import os
import mmap

# sys.stdout requires str, but we want to write bytes
out_bytes = sys.stdout.buffer

mem = mmap.mmap(sys.stdin.fileno(), 0, access=mmap.ACCESS_READ)
i = mem.find(search)
if i < 0:
    sys.exit("Search string not found")

# mmap object subscripts to bytes (making a copy)
# memoryview object subscripts to a memoryview object
# (it implements the buffer protocol).
view = memoryview(mem)

out_bytes.write(view[:i])
out_bytes.write(replace)
out_bytes.write(view[i+len(search):])

Eğer sistemim yaklaşık 4 gb ile 8 gb arasında boş hafızaya sahipse, mem = mmap.mmap (sys.stdin.fileno (), 0, access = mmap.ACCESS_READ) verileri o alana yerleştirdiği anlamına mı gelir? Ya da çok daha düşük olurdu (1 gb?)>
Rahul

1
@Rahul "Böylece, yeterli RAM'iniz yok, ancak 64 bit sistemde tüm dosyayı eşleştirmek için yeterli sanal adres alanına sahipsiniz ." Talep üzerine fiziksel koç içine veya dışına çağrılır (veya bunların eksikliği). Bu program büyük miktarda fiziksel RAM gerektirmeden çalışmalıdır. 64 bit sistemler, maksimum fiziksel koçtan çok daha fazla sanal adres alanına sahiptir. Ayrıca çalışan her işlemin kendi sanal adres alanı vardır. Bu, sistemin bir bütün olarak sanal adres alanını tükettiği anlamına gelmez, bir şey değildir, geçerli bir kavram değildir.
kaynakjedi

4
@Rulul yep! python mmap.mmap (), C işlevi mmap () etrafında oldukça ince bir sargıdır. Ve mmap (), çalıştırılabilir dosyaları çalıştırmak için kullanılan mekanizma ile aynıdır ve paylaşılan kütüphanelerden kod yazmaktadır.
kaynakjedi

2
@jamesqf Yanılıyor olabilirim ama bunun sadece kişisel bir seçim olduğunu düşünüyorum. Performans kayıpları ihmal edilebilir olacağından (dediği gibi, gerçek fonksiyon c işlevini çağırır), genel gider israfı çok düşüktür, çünkü aralarında başka hiçbir şey yoktur. C daha iyi olurdu, ancak bu çözüm daha büyük ve zor 70GB'lık sorunu çözmek için optimizasyon için değildi.
Rahul

1
Genel olarak, python ile yazmak daha kolaydır. Bu durumda, python versiyonunda birkaç detay olduğu ortaya çıktı ve C versiyonunun yazması daha hoş olabilirdi. ( searchNUL karakteri içeriyorsa bu kadar basit olmasa da, buradaki diğer C sürümünün de NUL karakterlerini desteklemediğini farkettim replace.) Karşılaştırma amacıyla C versiyonunu türetmekten memnuniyet duyarız. Ancak, sürümümün gerçekleştirdiği işlemler için temel hata bildirimi içerdiğini unutmayın. Hata bildirimi eklendiğinde, C sürümü en azından IMO'yu okumak için can sıkıcı olurdu .
18'de kaynakjedi

17

C versiyonunun daha iyi performans gösterebileceğini düşünüyorum:

#include <stdio.h>
#include <string.h>

#define PAT_LEN 5

int main()
{
    /* note this is not a general solution. In particular the pattern
     * must not have a repeated sequence at the start, so <unk> is fine
     * but aardvark is not, because it starts with "a" repeated, and ababc
     * is not because it starts with "ab" repeated. */
    char pattern[] = "<unk>";          /* set PAT_LEN to length of this */
    char replacement[] = "<raw_unk>"; 
    int c;
    int i, j;

    for (i = 0; (c = getchar()) != EOF;) {
        if (c == pattern[i]) {
            i++;
            if (i == PAT_LEN) {
                printf("%s", replacement);
                i = 0;
            }
        } else {
            if (i > 0) {
                for (j = 0; j < i; j++) {
                    putchar(pattern[j]);
                }
                i = 0;
            }
            if (c == pattern[0]) {
                i = 1;
            } else {
                putchar(c);
            }
        }
    }
    /* TODO: fix up end of file if it ends with a part of pattern */
    return 0;
}

EDIT: yorumlardan gelen önerilere göre değiştirildi. Ayrıca desenli hata düzeltildi <<unk>.


2
(buf [j]) yerine (desen [j]) yazdırabilirsiniz (bu noktada eşittirler, bu nedenle arabellek gerekmez
RiaD

3
Ayrıca kod "<" dizgesi için çalışmayacak ideone.com/ncM2yy
RiaD

10
0.3 saniyede 30 MB? Bu sadece 90 MB / saniye. memcpyHız (yani bellek tıkanıklığı), yeni bir x86 işlemcideki (örneğin Skylake) 12GB / saniye gibi bir şey. Stdio + sistem çağrısı ek yükü olsa bile, disk önbelleğinde 30 MB'lık bir dosya için verimli bir uygulama için 1GB / saniye beklenebilir. Optimizasyon devre dışı bırakılmış halde mi derlediniz, yoksa bir kerede tek char I / O gerçekten bu kadar yavaş mı? getchar_unlocked/ putchar_unlockedbelki yardımcı olabilir, ama kesinlikle 128kiB'lik (çoğu x86 işlemcideki L2 önbellek boyutunun yarısıdır), belki 128kiB'lik parçalarda okumak / yazmak kesinlikle daha iyidir, bu nedenle çoğunlukla L2'de okuduktan sonra dönerken vurursunuz)
Peter Cordes

2
başım, getchar üst ve putchar gelen bir yavaş.
Rui F Ribeiro

3
fixİçin programa "<<unk>"eğer hala çalışmıyorsa patternkarakterlerin bir tekrarlanan dizisi ile başlar (yani size zebra aardvark değiştirmeye çalışıyormuş işe yaramaz ve aaardvak girişini vardı, yoksa ababc değiştirmeye çalışıyorlardı ve abababc girişi vardı). Genel olarak, okuduğunuz karakterlerle başlayan bir eşleşme olasılığı olmadığını bilmediğiniz sürece, okuduğunuz karakter sayısına göre ileri gidemezsiniz.
icarus

16

replaceMariadb-server / mysql-server paketinde bir yardımcı program var . Basit dizgilerin yerine geçer (normal ifadeler değil) ve grep / sed / awk'ın replaceumurunda değil \nve \0. Bellek tüketimi herhangi bir giriş dosyasında sabittir (makinemde yaklaşık 400 kb).

Tabii ki kullanmak için bir mysql sunucusu çalıştırmanıza gerek yoktur replace, sadece Fedora'da paketlenir. Diğer dağıtımlar / işletim sistemleri ayrı olarak paketlenmiş olabilir.


14

GNU grep, tüm satırları belleğe okumak zorunda kalmadan size "ikili" dosyalardaki eşleşmeleri ofsetini gösterebilir. Daha sonra ddbu ofseti okumak, eşleşmeyi atlamak, sonra dosyadan kopyalamaya devam etmek için kullanabilirsiniz.

file=...
newfile=...
replace='<raw_unk>'
grep -o -b -a -F '<unk>' <"$file" |
(   pos=0
    while IFS=$IFS: read offset pattern
    do size=${#pattern}
       let skip=offset-pos
       let big=skip/1048576
       let skip=skip-big*1048576
       dd bs=1048576 count=$big <&3
       dd bs=1 count=$skip <&3
       dd bs=1 count=$size of=/dev/null <&3
       printf "%s" "$replace"
       let pos=offset+size
    done
    cat <&3
) 3<"$file" >"$newfile"

Hız için, dd1048576 büyüklüğünde bir blok okuma ve bir seferde 1 byte daha küçük bir okumaya böldüm, ancak bu işlem bu kadar büyük bir dosyada hala biraz yavaş olacak. grepÇıkış, örneğin,, 13977:<unk>ve bu değişkenleri okuma ile kolon üzerine bölünür offsetve pattern. posDosyadan kaç baytın kopyalandığını takip etmeliyiz.


11

İşte diğer seçeneklerden daha iyi performans gösterebilecek tek bir UNIX komut satırı, çünkü iyi performans gösteren bir "blok boyutu" için "av" yazabiliyorsunuz. Bunun sağlam olması için, her X karakterinde en az bir alan bulunduğunu bilmeniz gerekir; burada X, keyfi "blok boyutunuz" dur. Aşağıdaki örnekte 1024 karakterden oluşan bir "blok boyutu" seçtim.

fold -w 1024 -s corpus.txt | sed 's/<unk>/<raw_unk>/g' | tr '/n' '/0'

Burada, katlama 1024 bayta kadar çıkacaktır , ancak son aradan sonra en az bir tane olması durumunda -s, bir boşlukta kopmasını sağlar.

Sed komutu sizindir ve beklediğiniz şeyi yapar.

Daha sonra tr komutu, tekrar eklenen yeni satırları hiçbir şeye dönüştürmeyen dosyayı "açacaktır".

Daha hızlı çalışıp çalışmadığını görmek için daha büyük blok boyutlarını denemelisiniz. 1024 yerine -w katlama seçeneği için 10240 ve 102400 ve 1048576'yı deneyebilirsiniz.

İşte tüm N'leri küçük harfe dönüştüren her adım için ayrılmış bir örnek:

[root@alpha ~]# cat mailtest.txt
test XJS C4JD QADN1 NSBN3 2IDNEN GTUBE STANDARD ANTI UBE-TEST EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt
test XJS C4JD QADN1
NSBN3 2IDNEN GTUBE
STANDARD ANTI
UBE-TEST
EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt | sed 's/N/n/g'
test XJS C4JD QADn1
nSBn3 2IDnEn GTUBE
STAnDARD AnTI
UBE-TEST
EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt | sed 's/N/n/g' | tr '\n' '\0'
test XJS C4JD QADn1 nSBn3 2IDnEn GTUBE STAnDARD AnTI UBE-TEST EMAIL*C.34X test

Tr komutu onu kaldıracağından eğer varsa, dosyanın sonuna yeni bir satır eklemeniz gerekecek.


1
Yeterli boşluk bulunmadığı kenar durumlarda deseni kırmadığınızdan nasıl emin olabilirsiniz?
rackandboneman

1
Daha önce de belirtildiği gibi, bunun sağlam olması için, her X karakterinde en az bir boşluk olması gerekliliği vardır. Bu analizi, seçtiğiniz blok öbekleri ile kolayca yapabilirsiniz: fold -w X mailtest.txt | grep -v "" | wc -l Döndürdüğü sayı, potansiyel kenar durumları olan katlanmış çizgilerin sayısıdır. Sıfır ise, çözüm çalışması için garanti edilir.
alfreema

10

kullanma perl

Kendi tamponlarınızı yönetme

Varsayılan arabellekleri yönetmek için IO::Handle's' i kullanabilir setvbufveya kendi arabelleklerinizi sysreadve ile yönetebilirsiniz syswrite. Daha fazla bilgi için kontrol edin perldoc -f sysreadve perldoc -f syswritetemelde tamponlanmış io'yu atlarlar.

Burada kendi arabelleğimizi IO'yu yuvarlıyoruz, ancak manuel olarak ve keyfi olarak 1024 baytta yapıyoruz. Ayrıca dosyayı RW için açıyoruz, böylece aynı FH'de bir seferde hepsini yapıyoruz.

use strict;
use warnings;
use Fcntl qw(:flock O_RDWR);
use autodie;
use bytes;

use constant CHUNK_SIZE => 1024 * 32;

sysopen my $fh, 'file', O_RDWR;
flock($fh, LOCK_EX);

my $chunk = 1;
while ( sysread $fh, my $bytes, CHUNK_SIZE * $chunk ) {
  if ( $bytes =~ s/<unk>/<raw_unk>/g ) {
    seek( $fh, ($chunk-1)* CHUNK_SIZE, 0 );
    syswrite( $fh, $bytes, 1024);
    seek( $fh, $chunk * CHUNK_SIZE, 0 );
  }
  $chunk++;
}

Eğer bu rotaya gidecekseniz

  1. Emin olun <unk>ve <raw_unk>aynı byte boyutunda.
  2. Tampon yöntemimizin CHUNKSIZE1 bayttan fazlasını değiştirirseniz , sınırı geçmediğinden emin olmak isteyebilirsiniz .

2
Ya <unk>parçalar arasındaki sınırın altına düşerse?
liori

8

Bir " ikili dosyalar için" bbe ( ikili blok editörü ) deneyebilirsiniz sed.

Bir EOLkarakterin 7GB metin dosyasında, karaktersiz, bir dize birden fazla oluşumunu farklı uzunluktaki bir taneyle değiştirerek başarılı oldum . Herhangi bir optimizasyon yapmadan,> 50MB / s'lik ortalama bir işlem hacmi verdi.


5

İle perlsabit uzunluktaki kayıtlarla çalışabilirsiniz:

perl -pe 'BEGIN{$/=\1e8}
          s/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

Ve <unk>bu 100 MB'lık kayıtların ikisinde yayılmayacağını umuyorum .


Ben de bu metodu düşünüyordum, fakat onu kullanarak while read -N 1000 chunk;( 1000örnek olarak seçildi). <unk>Parçalar arasında kırılan çözüm iki dosyadan geçer: birincisi 100MB'lık parçalar, ikincisi '100MB + 5 byte'lık parçalar. Ancak 70GB dosya durumunda en uygun çözüm değildir.
MiniMax

3
İki geçişte bile ihtiyacın yok. A bloğunu okuyun. EOF olmasa da, B bloğunu okuyun. A + B'de Ara / Değiştir. A: = B. Döngü. Karmaşıklık, değiştirmenin içinde yer değiştirmemenizi sağlar.
roaima

MiniMax, bu ikinci geçişte her geçişte 5 bayt ekleyeceği için mutlaka yardımcı olmaz <unk>.
Stéphane Chazelas

1
@roaima, evet bu çok daha karmaşık bir çözüm olurdu. İşte bu, sadece (olasılıkla <unk>olmasa, kullanmanın $/ = ">"ve kullanmanın s/<unk>\z/<raw_unk>/gdoğru olmadığına göre) doğru olma ihtimalinin yüksek olduğu basit bir yaklaşımdır .
Stéphane Chazelas

5

İşte görevi gerçekleştiren küçük bir Go programı ( unk.go):

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

func main() {
    const (
        pattern     = "<unk>"
        replacement = "<raw_unk>"
    )
    var match int
    var char rune
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanRunes)
    for scanner.Scan() {
        char = rune(scanner.Text()[0])
        if char == []rune(pattern)[match] {
            match++
            if match == len(pattern) {
                fmt.Print(replacement)
                match = 0
            }
        } else {
            if match > 0 {
                fmt.Print(string(pattern[:match]))
                match = 0
            }
            if char == rune(pattern[0]) {
                match = 1
            } else {
                fmt.Print(string(char))
            }
        }
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}

Sadece inşa et go build unk.gove çalıştır ./unk <input >output.

DÜZENLE:

Üzgünüm, her şeyin tek bir satırda olduğunu okumadım, bu yüzden dosya karakterini şimdi karakter okumaya çalıştım.

EDIT II:

C programındakilerle aynı düzeltme uygulandı.


1
bu dosyanın tamamını belleğe okumaktan kaçınıyor mu?
kedi

1
Dosya karakterini karaktere göre okur ve dosyanın tamamını asla bellekte tutmaz, yalnızca bireysel karakterleri.
Patrick Bucher,

1
scanner.Split(bufio.ScanRunes)sihir yapar.
Patrick Bucher,

Ayrıca go doc bufio.MaxScanTokenSizevarsayılan arabellek boyutunu da kontrol edin .
Patrick Bucher,

Senin gibi Cprograma, bu aaardvark bir girişi olan zebra aardvark değiştirilmesi için çalışmaz.
icarus

1

Bu, 70GB'lık bir dosya ve basit bir arama ve değiştirme için fazla olabilir, ancak Hadoop MapReduce çerçevesi şu anda sorununuzu ücretsiz olarak çözer (yerel olarak çalıştırmak için ayarlarken 'Tek Düğüm' seçeneğini seçin) - ve Kodunuzu değiştirmenize gerek kalmadan gelecekte sonsuz kapasiteye ölçeklendirilebilir.

Https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html adresindeki resmi kılavuz, Java'yı kullanıyor (ancak son derece basit) ancak Perl veya hangi dili kullanmak istersen.

Böylece daha sonra 7000 GB metin dosyalarında daha karmaşık işlemler yaptığınızı ve bunu günde 100 kez yapmak zorunda kaldığınızı tespit ederseniz, iş yükünü sağladığınız veya sizin için otomatik olarak bir bulut tarafından sağlanan birden fazla düğüme dağıtabilirsiniz. tabanlı Hadoop kümesi.


1
Evet evet o. "Hadoop kullanmayın - verileriniz o kadar büyük değil" . Bu çok basit bir akış IO problemidir.
kaynakjedi

0

Önceki önerilerin tümü dosyanın tamamını okumayı ve dosyanın tamamını yazmayı gerektirir. Bu sadece uzun zaman alır, aynı zamanda 70GB boş alan gerektirir.

1) Sizi özel olarak doğru bir şekilde anlarsam, yerine SAME uzunluğunun başka bir dizgisi koymak kabul edilebilir mi?

2a) Çoklu oluşumlar var mı? 2b) Öyleyse kaç tane olduğunu biliyor musunuz?

Eminim bu yıl artı sorunu zaten çözdünüz ve hangi çözümü kullandığınızı bilmek istiyorum.

Olası blok geçişini göz önünde bulundurarak her birini dize araştıran dosyanın BLOCKS'unu okuyacak bir çözüm (en çok C cinsinden) öneririm. Bir kez bulundu dize SAME uzunluğu alternatif ile değiştirin ve sadece bu BLOCK yazın. Bilinen olay sayısı için veya dosyanın sonuna kadar devam ediyor. Bu, oluşma sayısı kadar az yazar ve en fazla iki katına ihtiyaç duyar (her olay 2 blok arasında bölündüyse). Bu ek alan gerektirmez!


-1

Minimum miktarda <unk>tutarımız varsa (Zipf yasasına göre beklendiği gibi),

awk -v RS="<unk>" -v ORS="<raw_unk>" 1

1
Hayır sed, ne olursa olsun bir anda bir satırın belleğine okur. Bu çizgiye sığamayacak.
Kusalananda

1
Bu bayrağı kullanırken GNU’dan başka bir şey sedgiriş / çıkış tamponlama yapmayacağını söyleyen hiçbir belge bulamıyorum . Kısmi satırları okuyacağını göremiyorum.
Kusalananda
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.