2008-08-08 5 views
2

PERL이없는 머신에서 동일한 id를 갖고 있고 4 시간 동안 등록 된 경우 중복 된 것으로 간주되는 레코드를 필터링해야합니다. 시간이 걸리는 복제본을 찾는 더 빠른 방법

나는 AWK을 사용하고 꽤 잘 작동이 필터를 구현하지만 훨씬 빠른 솔루션이 필요 : 데이터 파일의 모든 레코드를 포함

 
# Generar lista de Duplicados 
awk 'BEGIN { 
FS="," 
} 
/OK/ { 
    old[$8] = f[$8]; 
    f[$8] = mktime($4, $3, $2, $5, $6, $7); 
    x[$8]++; 
} 
/OK/ && x[$8]>1 && f[$8]-old[$8] 

Any suggestions? Are there ways to improve the environment (preloading the file or someting like that)?

The input file is already sorted.

With the corrections suggested by jj33 I made a new version with better treatment of dates, still maintaining a low profile for incorporating more operations:

awk 'BEGIN { FS=","; SECSPERMINUTE=60; SECSPERHOUR=3600; SECSPERDAY=86400; split("0 31 59 90 120 151 181 212 243 273 304 334", DAYSTOMONTH, " "); split("0 366 731 1096 1461 1827 2192 2557 2922 3288 3653 4018 4383 4749 5114 5479 5844 6210 6575 6940 7305", DAYSTOYEAR, " "); } /OK/ { old[$8] = f[$8]; f[$8] = mktime($4, $3, $2, $5, $6, $7); x[$8]++; } /OK/ && x[$8]>1 && f[$8]-old[$8] 2) && (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))) { d2m = d2m + 1; } d2y = DAYSTOYEAR[ y - 1999 ]; return ss + (mm*SECSPERMINUTE) + (hh*SECSPEROUR) + (d*SECSPERDAY) + (d2m*SECSPERDAY) + (d2y*SECSPERDAY); } '

답변

1

경우 (즉, 그것은 내 dupicate ID를하지 않는 레코드를 포함 파일)을 미리 처리하고 중복 (ids)이있는 레코드 만 포함하는 파일을 생성 할 수 있습니다.

AWK 프로그램으로 처리해야하는 파일의 크기를 줄이는 경우.

1

입력 파일은 어떻게 정렬됩니까? 고양이 파일 | 정렬, 또는 하나의 특정 필드 또는 여러 필드를 통해 정렬? 여러 필드가있는 경우, 필드와 순서는 무엇입니까? 시간 필드는 12 시간이 아닌 24 시간 시계 인 것 같습니다. 맞습니까? 모든 날짜/시간 필드가 0으로 채워져 있습니까 (9시 또는 9 시가 되나요?)

모든 달이 30 일이라고 가정하므로 코드의 월 경계에 문제가있는 것처럼 보입니다. 긴. 2008-05-31/12 : 00 : 00과 2008-06-01 : 12 : 00 : 00 두 가지 날짜를 선택하십시오. 24 시간 따로 있지만 코드는 두 시간에 동일한 시간 코드를 생성합니다. (63339969600)

1

윤년을 고려해야합니다. 나는 수학을하지는 않았지만 윤년 중에는 feb에 대한 28 일의 하드 코드를 사용하여 2/29의 정오와 3/1의 정오를 비교하면 이전과 동일한 중복 타임 스탬프가 발생한다고 생각합니다. . 당신은 그런 식으로 구현하지 않은 것처럼 보입니다. 당신이 구현 한 방식으로, 나는 여전히 문제가 있다고 생각하지만, $ leapyear의 12/31과 $ leapyear + 1의 1/1 날짜 사이에 있습니다.

코드를 처리하는 시간대를 처리해야하는 경우 시간 변경 중에 충돌이 발생할 수도 있습니다.

파일이 실제로 유용한 방식으로 정렬되지 않은 것 같습니다. 나는 그 필드 $ 1이 일종의 상태 (당신이 확인하고있는 "OK")라고 추측한다. 따라서 기록 상태별로 정렬 한 다음 일, 월, 일, 시간, 분, 초별로 정렬합니다. 년, 월, 일이라면 몇 가지 최적화가있을 수 있다고 생각합니다. 아직도 내 뇌가 다른 방향으로 가고있을 수도 있습니다.

전체 줄 수에 비례하여 중복 키 수가 적은 경우 가장 좋은 방법은 awk 스크립트가 파일을 복사하여 키를 복제하는 것입니다 (David said). 존재하는 유일한 행이/OK/행이되도록 파일을 사전 처리 할 수도 있습니다. 첫 번째 awk 스크립트는 중복 ID가있는 행만 인쇄하고 두 번째 awk 스크립트는 기본적으로 위의 명령을 사용하지만/OK /를 찾지 않도록 최적화 된 파이프 라인을 통해이 작업을 수행 할 수 있다고 생각합니다. 중복 키.

모든 줄 또는 대부분의 줄에 반복되는 키가있을 것이라는 것을 미리 알고 있다면 아마도 혼란에 빠질 가치가 없을 것입니다. 저는 총알을 물고 C로 작성했습니다. awk 스크립트보다 훨씬 더 많은 코드 줄이 있습니다.

1

많은 unixen에서 특정 열 또는 필드별로 정렬 할 수 있습니다. 따라서 ID로 파일을 정렬 한 다음 날짜별로 파일을 정렬하면 각 ID를 마지막으로 보았을 때 더 이상 연관 배열을 유지할 필요가 없습니다. 모든 문맥은 파일 순서대로 있습니다.GNU 정렬을 가지고 내 맥에

, 그건 :

sort -k 8 <input.txt> output.txt 

는 ID 필드에 정렬. 예를 들어 8,3 대신 2 개의 필드 만 사용하여 두 번째 필드에서도 정렬 할 수 있습니다. 그래서 유닉스 스타일의 time_t 타임 스탬프는 파일에서 나쁜 생각이 아닐 수도있다 - 그것은 정렬하기 쉽고, 모든 날짜 계산을 저장한다. 또한, (적어도 GNU awk에서도) mktime function이 있는데 이는 구성 요소로부터 time_t를 생성합니다.

1

@AnotherHowie, 전 전처리가 sort와 uniq로 수행 될 수 있다고 생각했습니다. 문제는 OP의 데이터가 쉼표로 구분되어 있고 (Solaris 8의) uniq이 레코드 분리자를 지정하는 것을 허용하지 않기 때문에 표준 유닉스 도구를 사용하여 전처리를 수행하는 수퍼 클린 방법이 없다는 것입니다. 나는 빨리 그래서 정확한 옵션을 조회하지 않을거야있을 거라고 생각하지 않습니다,하지만 당신은 같은 것을 할 수 있습니다 : 그것은을 포함하는 모든 라인에 대한 GREP을 실행하기 때문에 매우 좋지 않아 그

cut -d, -f8 <infile.txt | sort | uniq -d | xargs -i grep {} infile.txt >outfile.txt 

을 중복 키. Uniq 출력을 grep에 공급할 단일 정규 표현식으로 마사지 할 수도 있지만, OP가 예상 된 중복 키가 포함 된 행의 예상 비율을 파일의 총 행에 게시하는 경우에만 이점을 알 수 있습니다.

3

실제 데이터베이스의 작업처럼 들립니다. SQLite와 같은 것조차 아마 당신을 여기에서 합리적으로 잘 도울 수 있습니다. 내가 보는 큰 문제는 "4 시간 이내"에 대한 정의입니다. 이것은 슬라이딩 윈도우 문제입니다. 즉 모든 데이터를 4 시간 단위로 양자화 할 수는 없으며 다른 모든 요소에 대해 모든 "인접한"요소를 개별적으로 계산해야합니다. 응.

관련 문제