Ganti string dalam file teks berukuran besar (70GB), satu baris

126

Saya memiliki file teks (70GB), satu baris , dan saya ingin mengganti string (token) di dalamnya. Saya ingin mengganti token <unk>, dengan token dummy lainnya ( masalah sarung tangan ).

Saya mencoba sed:

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

tetapi file output corpus.txt.newmemiliki nol-byte!

Saya juga mencoba menggunakan perl:

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

tapi saya mendapat kesalahan memori.

Untuk file yang lebih kecil, kedua perintah di atas berfungsi.

Bagaimana saya bisa mengganti string adalah file seperti itu? Ini adalah pertanyaan terkait, tetapi tidak ada jawaban yang cocok untuk saya.

Sunting : Bagaimana dengan memisahkan file dalam potongan 10GB (atau apa pun) masing-masing dan menerapkannya sedmasing-masing dan kemudian menggabungkannya cat? Apakah itu masuk akal? Apakah ada solusi yang lebih elegan?

Christos Baziotis
sumber
seperti yang dicatat @Gilles, dapatkah Anda mendeteksi beberapa karakter berulang yang dapat berfungsi sebagai pembatas khusus di baris besar tunggal Anda?
RomanPerekhrest
Saya berpikir bahwa alat yang hanya dapat melakukan pencarian dan penggantian, tetapi bukan regex yang lebih kompleks, akan lebih cepat. Itu juga tidak akan mendapat manfaat dari melakukan satu baris pada satu waktu, jadi tidak akan tersedak pada file ini. Sayangnya saya tidak tahu keberadaan alat seperti itu, meskipun tidak akan sulit untuk menulis. Jika itu salah maka ganti dalam karakter baris baru seperti dalam salah satu jawaban mungkin akan lebih mudah.
ctrl-alt-delor
Apakah file Anda mengandung selain ASCII? Jika demikian, semua penanganan unicode dapat dihilangkan dan byte mentah dapat diproses.
Patrick Bucher
Saya setuju dengan @PatrickButcher. Lihatlah gambar yang lebih besar. Selain kebutuhan mendesak untuk mengganti teks ini, untuk apa lagi file ini digunakan? Jika ini adalah semacam log, tidak ada yang bisa bekerja dengannya secara efektif. Jika itu adalah file data yang digunakan beberapa aplikasi, maka aplikasi tersebut harus memikul tanggung jawab untuk menjaga data dalam file itu.
Thomas Carlisle
2
Anda dapat menggunakan splitdengan -bopsi mendefinisikan ukuran file potongan dalam byte. Proses masing-masing pada gilirannya menggunakan seddan merakit kembali. Ada risiko adalah bahwa <unk>dapat dipecah menjadi dua file dan tidak akan ditemukan ...
Vladislavs Dovgalecs

Jawaban:

106

Alat pemrosesan teks yang biasa tidak dirancang untuk menangani garis yang tidak sesuai dengan RAM. Mereka cenderung bekerja dengan membaca satu rekaman (satu baris), memanipulasinya, dan mengeluarkan hasilnya, kemudian melanjutkan ke rekaman berikutnya (baris).

Jika ada karakter ASCII yang sering muncul dalam file dan tidak muncul di <unk>atau <raw_unk>, maka Anda dapat menggunakannya sebagai pemisah rekaman. Karena sebagian besar alat tidak memungkinkan pemisah rekaman khusus, tukar antara karakter itu dan baris baru. trmemproses byte, bukan garis, sehingga tidak peduli tentang ukuran rekaman apa pun. Andaikan itu ;bekerja:

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

Anda juga bisa berlabuh pada karakter pertama dari teks yang Anda cari, dengan asumsi itu tidak diulang dalam teks pencarian dan itu muncul cukup sering. Jika file dapat dimulai dengan unk>, ubah perintah sed sed '2,$ s/…untuk menghindari kecocokan palsu.

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

Atau, gunakan karakter terakhir.

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

Perhatikan bahwa teknik ini mengasumsikan bahwa sed beroperasi dengan mulus pada file yang tidak berakhir dengan baris baru, yaitu bahwa ia memproses baris parsial terakhir tanpa memotongnya dan tanpa menambahkan baris baru akhir. Ini bekerja dengan sed GNU. Jika Anda dapat memilih karakter terakhir dari file sebagai pemisah rekaman, Anda akan menghindari masalah portabilitas.

Gilles
sumber
8
Saya tidak memiliki file seperti itu untuk diuji, tetapi dalam Awk Anda dapat menentukan "Pemisah Rekaman" dan "Pemisah Catatan Keluaran". Jadi dengan asumsi Anda memiliki sedikit tanda koma dalam file Anda, ada kemungkinan Anda bisa menyelesaikannya dengan: awk -v RS=, -v ORS=, '{gsub(/<unk>/, "<raw_unk>"); print}' Tidak?
Wildcard
4
@ Kartu Memori Ya, itu solusi lain. Awk cenderung lebih lambat daripada sed, itu sebabnya saya tidak menawarkannya sebagai solusi pilihan untuk file besar.
Gilles
Anda dapat mengatur pemisah rekaman dalam Perl dengan opsi baris perintah -0dan nilai oktal dari char, atau di dalam skrip dapat diatur dengan variabel khusus$/
beasy
@Gilles: Tetapi gunakan awkmenghindari melewati aliran dua kali untuk tr. Jadi apakah masih lebih lambat?
user285259
2
@ user285259 Biasanya tidak. trsangat cepat dan pipa bahkan dapat diparalelkan.
Gilles
110

Untuk file sebesar itu, satu kemungkinan adalah Flex. Biarkan unk.l:

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

Kemudian kompilasi dan jalankan:

$ flex -o unk.c  unk.l
$ cc -o unk -O2 unk.c -lfl
$ unk < corpus.txt > corpus.txt.new
Joao
sumber
5
makememiliki aturan default untuk ini, alih-alih flex / cc Anda dapat menambahkan %option mainsebagai baris pertama unk.l dan kemudian hanya make unk. Saya lebih atau kurang secara refleks menggunakan %option main 8bit fast, dan memiliki export CFLAGS='-march=native -pipe -Os'di saya .bashrc.
jthill
1
@undercat: Jika bukan di luar topik, saya bisa menunjukkan kepada Anda sejumlah aplikasi ujung depan non-kompiler, dari menyelesaikan masalah level air hingga penguraian input tujuan khusus. Sungguh menakjubkan apa yang dapat Anda lakukan dengan itu, jika Anda berpikir di luar kotak sedikit :-)
jamesqf
@ jthill, terima kasih: %option main+ make+ opsional CFLAGSadalah trik yang sangat bagus !! Apakah -march=nativeperilaku default?
JJoao
1
@ jamesqf seperti yang Anda katakan - akan sulit untuk membuat itu pada pertanyaan topik - tapi saya ingin melihatnya juga
Steven Penny
1
@jamesqf Seorang profesional saya di uni menggunakan flex untuk membuat alat yang mengenali jenis kain untuk pabrik! Bagaimana kalau menanyakan sesuatu seperti: "flex sepertinya alat yang sangat kuat tapi saya tidak mungkin menulis kompiler / parser - apakah ada case penggunaan lain untuk flex?"
Paul Evans
40

Jadi Anda tidak memiliki cukup memori fisik (RAM) untuk menampung seluruh file sekaligus, tetapi pada sistem 64-bit Anda memiliki ruang alamat virtual yang cukup untuk memetakan seluruh file. Pemetaan virtual dapat berguna sebagai peretasan sederhana dalam kasus seperti ini.

Semua operasi yang diperlukan termasuk dalam Python. Ada beberapa seluk yang menjengkelkan, tetapi tidak menghindari menulis kode C. Secara khusus, perawatan diperlukan untuk menghindari menyalin file dalam memori, yang akan mengalahkan sepenuhnya. Di sisi positifnya, Anda mendapatkan pelaporan kesalahan secara gratis (python "exception") :).

#!/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):])
sourcejedi
sumber
Jika sistem saya memiliki sekitar 4 gb memori yang dihasilkan bebas dari 8 gb, apakah mem = mmap.mmap (sys.stdin.fileno (), 0, akses = mmap.ACCESS_READ) berarti ia meletakkan data di ruang itu? Atau akankah ini jauh lebih rendah (1gb?)>
Rahul
1
@Rahul "Jadi Anda tidak memiliki cukup RAM, tetapi pada sistem 64-bit Anda memiliki cukup ruang alamat virtual untuk memetakan seluruh file." Ini masuk dan keluar dari ram fisik pada permintaan (atau ketiadaan). Program ini harus bekerja tanpa memerlukan sejumlah besar RAM fisik. Sistem 64-bit memiliki lebih banyak ruang alamat virtual daripada ram fisik maksimum. Juga setiap proses yang berjalan memiliki ruang alamat virtual sendiri. Ini berarti sistem secara keseluruhan kehabisan ruang alamat virtual bukanlah suatu hal, itu bukan konsep yang valid.
sourcejedi
4
@Rahul ya! python mmap.mmap () adalah pembungkus yang cukup tipis di sekitar fungsi C mmap (). Dan mmap () adalah mekanisme yang sama yang digunakan untuk menjalankan executable, dan kode dari pustaka bersama.
sourcejedi
2
@ jamesqf Saya bisa saja salah, tapi saya rasa itu hanya pilihan pribadi. Karena kehilangan kinerja akan diabaikan (karena seperti yang dia katakan, fungsi sebenarnya memanggil fungsi c), pemborosan overhead sangat rendah, karena tidak ada hal lain yang terjadi di antaranya. C akan lebih baik, tetapi solusi ini tidak bertujuan untuk optimasi, hanya untuk menyelesaikan masalah 70GB yang lebih besar dan sulit.
Rahul
1
Secara umum, menulis dengan python lebih ringkas. Dalam hal ini ternyata ada beberapa detail dalam versi python, dan versi C mungkin lebih baik untuk ditulis. (Meskipun tidak begitu sederhana jika searchdapat berisi karakter NUL. Dan saya perhatikan versi C lainnya di sini tidak mendukung karakter NUL replace.). Anda dipersilakan untuk menurunkan versi C untuk tujuan perbandingan. Namun ingat bahwa versi saya mencakup pelaporan kesalahan dasar untuk operasi yang dilakukan. Versi C setidaknya akan lebih mengganggu untuk membaca IMO, ketika pelaporan kesalahan disertakan.
sourcejedi
16

Ada replaceutilitas dalam paket mariadb-server / mysql-server. Ini menggantikan string sederhana (bukan ekspresi reguler) dan tidak seperti grep / sed / awk replacetidak peduli \ndan \0. Konsumsi memori konstan dengan file input apa pun (sekitar 400kb pada komputer saya).

Tentu saja Anda tidak perlu menjalankan server mysql untuk menggunakannya replace, hanya dikemas seperti itu di Fedora. Distro / sistem operasi lain mungkin mengemasnya secara terpisah.

legolegs
sumber
16

Saya pikir versi C mungkin berkinerja lebih baik:

#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: Dimodifikasi sesuai dengan saran dari komentar. Juga memperbaiki bug dengan polanya <<unk>.

Patrick Bucher
sumber
2
Anda dapat mencetak (pola [j]) alih-alih (buf [j]) (mereka sama pada saat ini, jadi Anda tidak perlu penyangga
RiaD
3
juga kode tidak akan bekerja untuk string "<< unk>" ideone.com/ncM2yy
Riad
10
30 MB dalam 0,3 detik? Itu hanya 90 MB / detik. memcpykecepatan (yaitu kemacetan memori) adalah sesuatu seperti 12GB / detik pada CPU x86 baru-baru ini (misalnya Skylake). Bahkan dengan stdio + system call overhead, untuk file 30MB panas di cache disk, saya berharap mungkin 1GB / detik untuk implementasi yang efisien. Apakah Anda mengompilasi dengan optimasi yang dinonaktifkan, atau apakah I / O pada satu waktu sangat lambat? getchar_unlockedSaya putchar_unlockedmungkin bisa membantu, tapi jelas lebih baik membaca / menulis dalam ukuran 128kiB (setengah dari ukuran cache L2 pada sebagian besar CPU x86, jadi Anda kebanyakan menekan L2 sambil mengulang setelah membaca)
Peter Cordes
2
dari atas kepala saya, getchar dan putchar adalah lambat.
Rui F Ribeiro
3
The fixke program untuk "<<unk>"masih tidak bekerja jika patterndimulai dengan urutan berulang karakter (yakni tidak akan bekerja jika Anda mencoba untuk mengganti aardvark dengan zebra dan Anda memiliki masukan dari aaardvak, atau Anda mencoba untuk mengganti ababc dan punya masukan abababc). Secara umum Anda tidak dapat bergerak maju dengan jumlah karakter yang telah Anda baca kecuali Anda tahu bahwa tidak ada kemungkinan kecocokan dimulai pada karakter yang telah Anda baca.
icarus
14

GNU grepdapat menunjukkan offset pada file "biner", tanpa harus membaca seluruh baris ke dalam memori. Anda kemudian dapat menggunakan dduntuk membaca hingga offset ini, melewati pertandingan, lalu melanjutkan menyalin dari file.

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"

Untuk kecepatan, saya membaginya ddmenjadi pembacaan besar dari blocksize 1048576 dan pembacaan yang lebih kecil dari 1 byte pada suatu waktu, tetapi operasi ini masih akan sedikit lambat pada file sebesar itu. The grepoutput, misalnya, 13977:<unk>dan ini dibagi pada usus besar dengan membaca ke dalam variabel offsetdan pattern. Kita harus melacak posberapa banyak byte yang telah disalin dari file.

meuh
sumber
11

Berikut ini adalah baris perintah UNIX lain yang mungkin berkinerja lebih baik daripada opsi lain, karena Anda dapat "berburu" untuk "ukuran blok" yang berkinerja baik. Agar ini kuat, Anda perlu tahu bahwa Anda memiliki setidaknya satu ruang di setiap karakter X, di mana X adalah "ukuran blok" sewenang-wenang Anda. Dalam contoh di bawah ini saya telah memilih "ukuran blok" 1024 karakter.

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

Di sini, lipat akan ambil sampai dengan 1024 byte, tetapi -s akan memastikan istirahat pada ruang jika ada setidaknya satu sejak terakhir istirahat.

Perintah sed adalah milik Anda dan melakukan apa yang Anda harapkan.

Kemudian perintah tr akan "membuka" file yang mengonversi baris baru yang dimasukkan kembali menjadi kosong.

Anda harus mempertimbangkan mencoba ukuran blok yang lebih besar untuk melihat apakah kinerjanya lebih cepat. Alih-alih 1024, Anda dapat mencoba 10240 dan 102400 dan 1048576 untuk opsi -w lipat.

Berikut adalah contoh yang diuraikan oleh setiap langkah yang mengubah semua N menjadi huruf kecil:

[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

Anda perlu menambahkan baris baru ke bagian paling akhir file jika ada, karena perintah tr akan menghapusnya.

alfreema
sumber
1
Bagaimana Anda memastikan Anda tidak melanggar pola dalam kasus tepi di mana tidak tersedia ruang kosong yang cukup?
rackandboneman
1
Seperti yang dinyatakan, untuk menjadi kuat ada persyaratan bahwa ada setidaknya satu ruang setiap karakter X. Anda dapat melakukan analisis itu dengan cukup mudah, dengan ukuran blok apa pun yang Anda pilih: fold -w X mailtest.txt | grep -v "" | wc -l Jumlah yang dikembalikan adalah jumlah garis terlipat dengan kasus tepi potensial. Jika nol, solusinya dijamin bekerja.
alfreema
10

Menggunakan perl

Mengelola buffer Anda sendiri

Anda dapat menggunakan IO::Handle's setvbufuntuk mengelola buffer default, atau Anda dapat mengelola buffer Anda sendiri dengan sysreaddan syswrite. Periksa perldoc -f sysreaddan perldoc -f syswriteuntuk informasi lebih lanjut, pada dasarnya mereka melewatkan buffer io.

Di sini kita menggulung buffer IO kita sendiri, tetapi kita melakukannya secara manual dan sewenang-wenang pada 1024 byte. Kami juga membuka file untuk RW sehingga kami melakukan semuanya pada FH yang sama sekaligus.

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++;
}

Jika Anda akan pergi dengan rute ini

  1. Pastikan <unk>dan <raw_unk>ukuran byte yang sama.
  2. Anda mungkin ingin memastikan metode buffered kami tidak melewati CHUNKSIZEbatas, jika Anda mengganti lebih dari 1 byte.
Evan Carroll
sumber
2
Bagaimana jika <unk>jatuh pada batas antara potongan?
liori
8

Anda dapat mencoba bbe ( editor blok biner ), sebuah " seduntuk file biner".

Saya sukses menggunakannya pada file teks 7GB tanpa EOLkarakter, menggantikan beberapa kemunculan string dengan panjang yang berbeda. Tanpa mencoba optimasi apa pun, ia memberikan throughput pemrosesan rata-rata> 50MB / s.

ovirt
sumber
5

Dengan perl, Anda dapat bekerja dengan catatan panjang tetap seperti:

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

Dan berharap tidak akan ada <unk>yang menjangkau dua dari 100MB rekaman itu.

Stéphane Chazelas
sumber
Saya juga sedang memikirkan metode ini, tetapi menggunakan while read -N 1000 chunk;( 1000memilih sebagai contoh). Solusi untuk <unk>, dipecah antara potongan-potongan, adalah dua melewati file: yang pertama dengan potongan 100MB dan yang kedua dengan potongan '100MB + 5 byte'. Tapi itu bukan solusi optimal dalam hal file 70GB.
MiniMax
3
Anda bahkan tidak perlu dua lintasan. Baca blok A. Meskipun bukan EOF, baca blok B. Cari / Ganti dalam A + B. A: = B. Loop. Kompleksitas memastikan Anda tidak mengganti di dalam penggantian.
roaima
@ MinMax, bahwa pass kedua tidak selalu membantu karena pass pertama akan menambahkan 5 byte untuk setiap kemunculan <unk>.
Stéphane Chazelas
1
@roaima, ya itu akan menjadi solusi yang jauh lebih terlibat. Ini adalah pendekatan sederhana yang hanya sangat mungkin (dengan asumsi <unk>kejadiannya sangat jauh, jika tidak, gunakan $/ = ">"dan s/<unk>\z/<raw_unk>/g) benar.
Stéphane Chazelas
5

Berikut adalah program Go kecil yang melakukan tugas ( 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)
    }
}

Cukup buat go build unk.godan jalankan sebagai ./unk <input >output.

SUNTING:

Maaf, saya tidak membaca bahwa semuanya dalam satu baris, jadi saya mencoba membaca file karakter demi karakter sekarang.

EDIT II:

Perbaikan yang sama diterapkan untuk program C.

Patrick Bucher
sumber
1
apakah ini menghindari membaca seluruh file ke dalam memori?
kucing
1
Bunyinya karakter file dengan karakter dan tidak pernah memegang seluruh file dalam memori, hanya karakter individu.
Patrick Bucher
1
scanner.Split(bufio.ScanRunes)melakukan keajaiban.
Patrick Bucher
Periksa juga go doc bufio.MaxScanTokenSizeukuran buffer default.
Patrick Bucher
Seperti Cprogram Anda , ini tidak berfungsi untuk mengganti aardvark dengan zebra dengan input aaardvark.
icarus
1

Ini mungkin berlebihan untuk file 70GB dan pencarian & penggantian sederhana, tetapi kerangka kerja Hadoop MapReduce akan menyelesaikan masalah Anda sekarang tanpa biaya (pilih opsi 'Node Tunggal' saat mengaturnya untuk menjalankannya secara lokal) - dan akan dapat diskalakan hingga kapasitas tak terbatas di masa depan tanpa perlu mengubah kode Anda.

Tutorial resmi di https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html menggunakan (sangat sederhana) Java tetapi Anda dapat menemukan perpustakaan klien untuk Perl atau bahasa apa pun yang Anda suka gunakan.

Jadi jika nanti Anda menemukan bahwa Anda melakukan operasi yang lebih kompleks pada file teks 7000GB - dan harus melakukan ini 100 kali per hari - Anda dapat mendistribusikan beban kerja di beberapa node yang Anda berikan atau yang secara otomatis disediakan untuk Anda oleh cloud- berdasarkan cluster Hadoop.

Sam Rahimi
sumber
1
ya, ya itu. "Jangan gunakan Hadoop - data Anda tidak sebesar itu" . Ini adalah masalah IO streaming yang sangat sederhana.
sourcejedi
0

Semua saran sebelumnya mengharuskan membaca seluruh file dan menulis seluruh file. Ini tidak hanya membutuhkan waktu lama tetapi juga membutuhkan ruang kosong 70GB.

1) Jika saya memahami Anda dengan benar, apakah dapat mengganti dengan string lain dengan panjang SAMA?

2a) Apakah ada beberapa kejadian? 2b) Jika ya, Anda tahu berapa banyak?

Saya yakin Anda telah menyelesaikan masalah tahun-plus ini dan saya ingin tahu solusi apa yang Anda gunakan.

Saya akan mengusulkan solusi (kemungkinan besar dalam C) yang akan membaca BLOCKS dari file mencari masing-masing untuk string dengan mempertimbangkan kemungkinan blok silang. Setelah ditemukan ganti string dengan panjang SAMA alternatif dan tulis hanya BLOCK itu. Melanjutkan untuk jumlah kejadian yang diketahui atau sampai akhir file. Ini akan membutuhkan sesedikit jumlah kejadian menulis dan paling banyak dua kali lipat (jika setiap kejadian dibagi antara 2 blok). Ini TIDAK memerlukan ruang tambahan!

DGerman
sumber
-1

Jika kami memiliki jumlah minimum <unk>(seperti yang diharapkan oleh hukum Zipf),

awk -v RS="<unk>" -v ORS="<raw_unk>" 1
Joao
sumber
1
Tidak. sedMembaca baris sekaligus ke memori terlepas. Itu tidak akan dapat sesuai dengan garis ini.
Kusalananda
1
Saya tidak dapat menemukan dokumentasi yang mengatakan selain GNU yang sedtidak akan melakukan buffer input / output saat menggunakan flag ini. Saya tidak dapat melihat bahwa ia akan membaca sebagian baris.
Kusalananda