큰 (70GB) 한 줄의 텍스트 파일에서 문자열 교체


126

거대한 (70GB), 한 줄 의 텍스트 파일이 있고 문자열 (토큰)을 바꾸고 싶습니다. 토큰 <unk>을 다른 더미 토큰 ( 장갑 문제 ) 으로 바꾸고 싶습니다 .

나는 시도했다 sed:

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

그러나 출력 파일 corpus.txt.new에는 0 바이트가 있습니다!

나는 또한 perl을 사용해 보았습니다.

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

하지만 메모리 부족 오류가 발생했습니다.

작은 파일의 경우 위의 두 명령이 모두 작동합니다.

문자열을 어떻게 교체 할 수 있습니까? 이것은 관련 질문이지만 답변이 없습니다.

편집 : 10GB (또는 무엇이든) 청크로 파일을 분할하고 각 파일에 적용 sed한 다음 병합하는 것은 cat어떻습니까? 말이 돼? 더 우아한 솔루션이 있습니까?


@Gilles가 지적했듯이 큰 줄에서 맞춤 구분 기호로 사용할 수있는 반복되는 문자를 감지 할 수 있습니까?
RomanPerekhrest

검색 및 교체 만 할 수 있지만 더 복잡한 정규 표현식은 수행 할 수없는 도구가 더 빠를 것이라고 생각합니다. 한 번에 한 줄씩 수행해도 이점이 없으므로이 파일을 질식 시키지는 않습니다. 불행히도 나는 그러한 도구의 존재에 대해 전혀 알지 못하지만 작성하기는 어렵지 않습니다. 그것이 하나의 경우라면 대답 중 하나에서와 같이 개행 문자를 대체하는 것이 가장 쉬울 것입니다.
ctrl-alt-delor

파일에 ASCII 이외의 것이 포함되어 있습니까? 그렇다면 모든 유니 코드 처리를 생략하고 원시 바이트를 처리 할 수 ​​있습니다.
Patrick Bucher

@PatrickButcher에 동의합니다. 더 큰 사진을보십시오. 이 텍스트를 즉시 교체해야 할 필요 외에도이 파일은 다른 용도로 사용되어야합니까? 어떤 종류의 로그라면 아무도 효과적으로 작업 할 수 없습니다. 일부 앱에서 사용하는 데이터 파일 인 경우 해당 앱은 해당 파일에서 데이터를 유지 관리 할 책임이 있습니다.
토마스 칼라일

2
청크 파일 크기를 바이트 단위로 정의하는 옵션 split과 함께 사용할 수 있습니다 -b. 을 사용 sed하여 재 조립 하여 차례로 처리하십시오 . <unk>두 파일로 나눌 수없고 발견되지 않을 위험이 있습니다 ...
Vladislavs Dovgalecs

답변:


106

일반적인 텍스트 처리 도구는 RAM에 맞지 않는 행을 처리하도록 설계되지 않았습니다. 그들은 한 레코드를 읽고 (한 줄), 조작하고 결과를 출력 한 후 다음 레코드 (줄)로 진행하는 경향이 있습니다.

파일에 자주 나타나고 <unk>또는에 나타나지 않는 ASCII 문자가 있으면이를 <raw_unk>레코드 구분 기호로 사용할 수 있습니다. 대부분의 도구는 사용자 정의 레코드 구분 기호를 허용하지 않으므로 해당 문자와 ​​줄 바꿈을 바꾸십시오. tr행이 아닌 바이트를 처리하므로 레코드 크기에 신경 쓰지 않습니다. ;작동 한다고 가정 :

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

검색 텍스트에서 반복되지 않고 자주 나타나는 것으로 가정하여 검색중인 텍스트의 첫 문자를 고정 할 수도 있습니다. 파일이로 시작될 수있는 경우 unk>sed 명령을 변경하여 sed '2,$ s/…가짜 일치를 피하십시오.

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

또는 마지막 문자를 사용하십시오.

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

이 기술은 sed가 줄 바꿈으로 끝나지 않는 파일에서 완벽하게 작동한다고 가정합니다. 즉, 마지막 부분 줄을 잘라 내지 않고 마지막 줄 바꿈을 추가하지 않고 마지막 부분 줄을 처리한다고 가정합니다. GNU sed와 함께 작동합니다. 파일의 마지막 문자를 레코드 구분 기호로 선택할 수 있으면 이식성 문제가 발생하지 않습니다.


8
테스트 할 파일이 없지만 Awk에서는 "Record Separator"와 "Output Record Separator"를 지정할 수 있습니다. 따라서 파일에 쉼표가 적당히 있다고 가정하면 다음과 같이 해결할 수 있습니다 awk -v RS=, -v ORS=, '{gsub(/<unk>/, "<raw_unk>"); print}' .
와일드 카드

4
@Wildcard 네, 다른 솔루션입니다. Awk는 sed보다 속도가 느리기 때문에 큰 파일에 대해 선호하는 솔루션으로 제공하지 않습니다.
Gilles

당신은 명령 줄 옵션을 사용하여 Perl로 레코드 분리를 설정할 수 -0와 문자의 8 진수 값 또는 스크립트 내에서 그것은 특별한 변수로 설정할 수 있습니다$/
beasy

@Gilles : 그러나 awk스트림을 두 번 전달하지 마십시오 tr. 그래도 여전히 느릴까요?
user285259

2
@ user285259 일반적으로 아닙니다. tr매우 빠르며 파이프를 평행하게 만들 수도 있습니다.
Gilles

110

이러한 큰 파일의 경우 Flex가 가능합니다. 하자 unk.l:

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

그런 다음 컴파일하고 실행하십시오.

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

5
makeflex / cc 대신 %option mainunk.l의 첫 번째 줄로을 추가 한 다음 그냥을 추가 할 수 있습니다 make unk. 나는 다소 반사적으로 사용 %option main 8bit fast하고 export CFLAGS='-march=native -pipe -Os'.bashrc.
jthill

1
@undercat : 주제가 아닌 경우 수위 문제 해결에서 특수 목적의 입력 구문 분석에 이르기까지 많은 비 컴파일러 프론트 엔드 응용 프로그램을 보여줄 수 있습니다. 상자 밖에서 약간 생각하면 :-)
jamesqf

@jthill, 감사합니다 : %option main+ make+ 선택적 CFLAGS으로 아주 좋은 트릭입니다! 가 -march=native기본 동작은?
JJoao

1
@ jamesqf 당신이 말한대로-주제에 대한 질문을하기가 어려울 것입니다-그러나 나는 또한 그것을보고 싶습니다
Steven Penny

1
@jamesqf uni의 교수는 flex를 사용하여 공장의 직물 유형을 인식하는 도구를 만들었습니다! "flex는 매우 강력한 도구 인 것 같지만 컴파일러 / 파서를 작성하지 않을 것입니다. flex에 대한 다른 사용 사례가 있습니까?"
Paul Evans

41

따라서 전체 파일을 한 번에 저장할 수있는 실제 메모리 (RAM) 가 충분하지 않지만 64 비트 시스템 에는 전체 파일을 매핑하기에 충분한 가상 주소 공간이 있습니다. 가상 매핑은 이와 같은 경우 간단한 해킹으로 유용 할 수 있습니다.

필요한 작업은 모두 Python에 포함되어 있습니다. 몇 가지 성가신 미묘한 점이 있지만 C 코드를 작성하지 않아도됩니다. 특히, 파일을 메모리에 복사하는 것을 피하기 위해서는주의가 필요합니다. 긍정적 인 측면에서, 당신은 무료로 오류보고를 얻습니다 (python "exceptions") :).

#!/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):])

내 시스템에 8GB에서 약 4GB의 후속 메모리가 있으면 mem = mmap.mmap (sys.stdin.fileno (), 0, access = mmap.ACCESS_READ)는 해당 공간에 데이터를 배치한다는 의미입니까? 아니면 훨씬 더 낮을까요 (1GB?)>
Rahul

1
@Rahul "RAM이 충분하지 않지만 64 비트 시스템 에는 전체 파일을 매핑하기에 충분한 가상 주소 공간이 있습니다." 주문형 (또는 부족한 경우) 물리적 램 안팎으로 페이징됩니다. 이 프로그램은 많은 양의 물리적 RAM을 요구하지 않고 작동해야합니다. 64 비트 시스템은 최대 실제 램보다 훨씬 더 많은 가상 주소 공간을 갖습니다. 또한 실행중인 각 프로세스에는 자체 가상 주소 공간이 있습니다. 즉, 전체 가상 주소 공간이 부족한 시스템은 문제가 아니며 올바른 개념이 아닙니다.
sourcejedi

4
@Rahul p! python mmap.mmap ()은 C 함수 mmap () 주위의 상당히 얇은 래퍼입니다. mmap ()은 실행 파일을 실행하고 공유 라이브러리에서 코드를 작성하는 데 사용되는 것과 동일한 메커니즘입니다.
sourcejedi

2
@ jamesqf 내가 틀릴 수는 있지만 그것이 개인적인 선택이라고 생각합니다. 성능 손실은 무시할 수 있기 때문에 (실제로 함수가 c 함수를 호출하기 때문에) 그 사이에 다른 물건이 없기 때문에 오버 헤드 낭비가 매우 적습니다. C는 더 나 았지만이 솔루션은 최적화를 목표로하지 않았으며, 더 크고 어려운 70gb 문제를 해결하기위한 것이 었습니다.
Rahul

1
일반적으로 파이썬으로 작성하는 것이 더 간결합니다. 이 경우 파이썬 버전에 몇 가지 세부 사항이 있으며 C 버전이 더 좋을 수도 있습니다. ( searchNUL 문자를 포함 할 수 있다면 그렇게 간단 하지는 않지만 여기서 다른 C 버전은에서 NUL 문자를 지원하지 않습니다 replace.) 비교 목적으로 C 버전을 파생시키는 것은 매우 환영합니다. 그러나 내 버전에는 수행중인 작업에 대한 기본 오류보고가 포함되어 있습니다. C 버전은 오류보고가 포함될 때 적어도 IMO 를 읽는 것이 더 성가시다 .
sourcejedi

17

C 버전이 훨씬 더 나은 성능을 발휘할 수 있다고 생각합니다.

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

편집 : 의견의 제안에 따라 수정되었습니다. 패턴으로 버그가 수정되었습니다 <<unk>.


2
(buf [j]) 대신 (pattern [j])를 인쇄 할 수 있습니다 (이 시점에서는 동일하므로 버퍼가 필요 없습니다
RiaD

3
또한 코드 "<< unk>"에 대해 코드가 작동하지 않습니다. ideone.com/ncM2yy
RiaD

10
0.3 초 ​​안에 30MB? 그것은 단지 90MB / 초입니다. memcpy최근 x86 CPU (예 : Skylake)에서 속도 (예 : 메모리 병목 현상)는 12GB / 초와 같습니다. stdio + 시스템 호출 오버 헤드로도 30MB 파일의 디스크 캐시 핫은 효율적인 구현을 위해 1GB / 초가 될 것으로 예상됩니다. 최적화를 비활성화 한 상태에서 컴파일 했습니까? 아니면 한 번에 한 문자 씩만 I / O가 그렇게 느립니까? getchar_unlocked/ putchar_unlocked도움이 될 수 있지만 128kiB의 덩어리로 읽기 / 쓰기가 더 낫습니다 (대부분의 x86 CPU에서 절반의 L2 캐시 크기이므로 읽기 후에 반복하는 동안 L2에서 적중합니다)
Peter Cordes

2
내 머리 꼭대기에서 getchar와 putchar 느립니다.
Rui F Ribeiro

3
fix의 프로그램 "<<unk>"경우 여전히 작동하지 않습니다 pattern문자의 반복 순서에 시작은 (즉, 당신이 얼룩말과 땅 돼지를 교체하려고 한 경우 작동하지 않을 것입니다 당신이 aaardvak의 입력을 가지고, 또는 ababc을 대체하기 위해 노력하고 abababc의 입력을 받았습니다). 일반적으로 읽은 문자에서 일치하는 항목이 없다는 것을 모르면 읽은 문자 수만큼 앞으로 이동할 수 없습니다.
이카루스

16

replacemariadb-server / mysql-server 패키지에 유틸리티 가 있습니다 . 그것은 간단 문자열 (정규없는 표현)를 대체하고 그렙 / 나오지도 / AWK는 달리 replace걱정하지 않습니다 \n\0. 메모리 소비는 모든 입력 파일 (내 컴퓨터에서 약 400kb)과 일정합니다.

물론을 사용하기 위해 mysql 서버를 실행할 필요는 없으며 replaceFedora에서만 패키지화됩니다. 다른 배포판 / 운영 체제는 별도로 포장되어있을 수 있습니다.


14

GNU grep는 전체 줄을 메모리로 읽을 필요없이 "이진"파일에서 일치하는 오프셋을 표시 할 수 있습니다. 그런 다음을 사용 dd하여이 오프셋을 읽고 일치하는 항목을 건너 뛰고 파일에서 계속 복사 할 수 있습니다.

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"

속도를 높이기 위해 dd블록 크기 1048576의 큰 읽기와 한 번에 1 바이트의 작은 읽기로 나누었 지만 이러한 큰 파일에서는이 작업이 여전히 약간 느립니다. grep출력은, 예를 들면 13977:<unk>,이 변수로 판독하여 대장에 분할 offset하고 pattern. pos파일에서 이미 몇 바이트를 복사했는지 추적 해야합니다.


11

다음은 성능이 우수한 "블록 크기"를 "헌트"할 수 있기 때문에 다른 옵션보다 성능이 우수한 단일 UNIX 명령 줄입니다. 이를 강력하게하려면 모든 X 문자에 하나 이상의 공간이 있어야합니다. 여기서 X는 임의의 "블록 크기"입니다. 아래 예제에서 나는 1024 문자의 "블록 크기"를 선택했습니다.

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

여기에서 fold는 최대 1024 바이트를 차지 하지만 -s는 마지막 중단 이후 하나 이상이 있으면 공백에서 중단되도록합니다.

sed 명령은 귀하의 것이며 귀하가 기대하는 것을 수행합니다.

그런 다음 tr 명령은 파일을 "펼쳐서"다시 삽입 된 개행을 변환합니다.

더 큰 블록 크기를 시도하여 성능이 더 빠른지 확인해야합니다. 1024 대신 fold의 -w 옵션에 10240 및 102400 및 1048576을 시도 할 수 있습니다.

다음은 모든 N을 소문자로 변환하는 각 단계별로 세분화 된 예입니다.

[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 명령이 파일을 제거하기 때문에 파일 끝에 줄 바꿈이있는 경우 줄 바꿈을 추가해야합니다.


1
사용 가능한 공백이 충분하지 않은 엣지 케이스에서 패턴이 깨지지 않도록하려면 어떻게해야합니까?
rackandboneman

1
언급 한 바와 같이,이를 강력하게하려면 X 문자마다 최소한 하나의 공백이 있어야합니다. 선택한 모든 블록 크기로 분석을 쉽게 수행 할 수 있습니다. fold -w X mailtest.txt | grep -v ""| wc -l 반환되는 숫자는 잠재적 인 에지 케이스가있는 접힌 선의 수입니다. 0이면 솔루션이 작동하는 것입니다.
alfreema

10

사용 perl

자신의 버퍼 관리

당신은 사용할 수 IO::Handle의를 setvbuf기본 버퍼를 관리하기 위해, 또는 당신은 당신의 자신의 버퍼를 관리 할 수 있습니다 sysreadsyswrite. 확인 perldoc -f sysread하고 perldoc -f syswrite자세한 내용은 본질적으로 버퍼링 된 io를 건너 뜁니다.

여기서는 자체 버퍼 IO를 롤링하지만 1024 바이트에서 수동으로 임의로 수행합니다. 또한 RW 용 파일을 열므로 한 번에 동일한 FH에서 모두 수행합니다.

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

이 길을 갈 예정이라면

  1. 확인 <unk><raw_unk>같은 바이트 크기입니다.
  2. CHUNKSIZE1 바이트 이상을 교체하는 경우 버퍼링 된 메소드가 경계를 넘지 않도록 할 수 있습니다 .

2
<unk>덩어리 사이의 경계에 떨어지면 어떻게 됩니까?
liori

8

" 이진 파일의 경우"인 bbe ( 이진 블록 편집기 )를 사용해 볼 수 sed있습니다.

나는 EOL문자 가없는 7GB 텍스트 파일에서 그것을 성공적으로 사용 하여 여러 문자열을 다른 길이의 문자열로 대체했습니다. 최적화를 시도하지 않고 평균 처리량> 50MB / s를 제공했습니다.


5

을 사용 perl하면 다음과 같은 고정 길이 레코드로 작업 할 수 있습니다.

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

그리고 <unk>100MB 레코드 중 2 개에 걸쳐 있지 않기를 바랍니다 .


나는 또한이 방법에 대해 생각하고 있었지만 while read -N 1000 chunk;( 1000예를 들어 선택된 것)을 사용했습니다. <unk>청크 사이에서 깨진에 대한 해결책 은 파일을 통과하는 두 가지 단계입니다. 첫 번째는 100MB 청크가 있고 두 번째는 '100MB + 5 바이트'청크가 있습니다. 그러나 70GB 파일의 경우 최적의 솔루션이 아닙니다.
MiniMax

3
두 번의 패스가 필요하지 않습니다. 블록 A를 읽습니다. EOF는 아니지만 블록 B를 읽습니다. A + B에서 검색 / 바꾸기. A : = B. 루프. 복잡성으로 인해 교체품 내부를 교체하지 않아도됩니다.
roaima

@MiniMax, 첫 번째 패스가 각각의 발생에 대해 5 바이트를 추가했기 때문에 두 번째 패스가 반드시 도움이되지는 않습니다 <unk>.
Stéphane Chazelas

1
@roaima, 그렇습니다. 훨씬 더 많은 해결책이 될 것입니다. 합니다 (가정 여기에만 발생 가능성이 매우 높은 수있는 간단한 방법입니다 <unk>하지, 사용하는 경우 발생은, 지금까지 아파트되어 $/ = ">"s/<unk>\z/<raw_unk>/g올바른가되는).
Stéphane Chazelas

5

다음은 작업 ( unk.go) 을 수행하는 작은 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)
    }
}

로 빌드하고로 go build unk.go실행하십시오 ./unk <input >output.

편집하다:

죄송합니다. 모든 것이 한 줄에 있다는 것을 읽지 못했기 때문에 파일별로 문자를 읽으려고했습니다.

편집 II :

C 프로그램과 동일한 수정 사항이 적용되었습니다.


1
이것은 전체 파일을 메모리로 읽는 것을 피합니까?
cat

1
문자별로 파일을 읽고 메모리에 전체 파일을 보관하지 않으며 개별 문자 만 포함합니다.
Patrick Bucher

1
scanner.Split(bufio.ScanRunes)마술을합니다.
Patrick Bucher

go doc bufio.MaxScanTokenSize기본 버퍼 크기 도 확인하십시오 .
Patrick Bucher

C프로그램 과 마찬가지로 aardvark를 zea로 aaardvark 입력으로 대체하는 데는 작동하지 않습니다.
이카루스

1

이것은 70GB 파일과 간단한 검색 및 바꾸기에 과잉 일 수 있지만 Hadoop MapReduce 프레임 워크는 현재 무료로 문제를 해결할 것입니다 (로컬을 실행하도록 설정할 때 'Single Node'옵션을 선택하십시오). 나중에 코드를 수정하지 않고도 무한한 용량으로 확장 할 수 있습니다.

https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html 의 공식 자습서는 Java를 사용하지만 (매우 간단한) Perl 또는 사용하고 싶은 언어

나중에 나중에 7000GB 텍스트 파일에 대해보다 복잡한 작업을 수행하고 하루에 100 번 수행해야하는 경우 클라우드에서 프로비저닝하거나 클라우드에 의해 자동으로 프로비저닝 된 여러 노드에 작업 부하를 분산시킬 수 있습니다. 기반 하둡 클러스터.


1
예, 그렇습니다. "하둡을 사용하지 마십시오. 데이터가 그렇게 크지 않습니다 . " 이것은 매우 간단한 스트리밍 IO 문제입니다.
sourcejedi

0

이전의 모든 제안은 전체 파일을 읽고 전체 파일을 작성해야합니다. 시간이 오래 걸리고 70GB의 여유 공간이 필요합니다.

나는 당신에게 특정한 경우를 이해한다면)를 정확하게 동일한 길이의 다른 문자열로 <UNK> 교체가 허용 될 수?

2a) 여러 번 발생합니까? 2b) 그렇다면 얼마나 많은지 아십니까?

나는 당신이 이미 올해 문제를 해결했다고 확신하고 당신이 어떤 솔루션을 사용했는지 알고 싶습니다.

가능한 블록 교차를 고려하여 각 문자열을 검색하는 파일의 블록을 읽는 솔루션 (대부분 C 가능성)을 제안합니다. 발견되면 문자열을 SAME 길이 대체로 바꾸고 해당 블록 만 쓰십시오. 알려진 횟수만큼 계속 또는 파일 끝까지. 이것은 발생 횟수만큼의 쓰기가 필요하며 최대 두 번 (모든 발생이 2 개의 블록으로 분할 된 경우) 필요합니다. 추가 공간이 필요하지 않습니다!


-1

<unk>Zipf의 법칙에 따라 최소 금액이있는 경우 ,

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

1
아니요. 한 번에 sed한 줄씩 메모리에 읽습니다. 이 줄에 맞지 않을 것입니다.
Kusalananda

1
이 플래그를 사용할 때 GNU sed가 입 / 출력 버퍼링을 하지 않는다는 문서는 찾을 수 없습니다 . 부분 줄을 읽는 것을 볼 수 없습니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.