Un mod mai rapid de a găsi duplicate condiționate de timp

Într-o mașină cu AIX fără PERL trebuie să filtrez înregistrările care vor fi considerate duplicate dacă au același ID și dacă au fost înregistrate între o perioadă de patru ore.

Am implementat acest filtru folosind AWK și lucrez destul de bine, dar am nevoie de o soluție mult mai rapidă:

# 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); } '
0
fr hi bn

6 răspunsuri

Dacă fișierul dvs. de date conține toate înregistrările (adică include înregistrări care nu au ID-uri duplicate în fișier), ați putea să o procesați în prealabil și să creați un fișier care conține numai înregistrări care au dubluri (IDs).

Dacă acesta este cazul, care ar reduce dimensiunea fișierului pe care trebuie să îl procesați cu programul dvs. AWK.

0
adăugat

Pe multe unixen, puteți să sortați după o anumită coloană sau câmp. Prin sortarea fișierului cu ID, apoi cu dată, nu mai trebuie să păstrați matricea asociativă de când ați văzut ultima dată fiecare cod. Tot contextul este acolo în ordinea dosarului.

Pe Mac-ul meu, care are genul GNU, este:

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

pentru a sorta pe câmpul ID. Puteți sorta și pe un al doilea câmp, spunând (de exemplu) 8,3 în schimb, dar NUMAI 2 câmpuri. Deci un timestamp de tip time_t în stil unix ar putea să nu fie o idee proastă în fișier - este ușor de sortare și vă salvează toate acele calcule date. De asemenea, (din nou, cel puțin în GNU awk), există o funcție funcția mktime care vă face timpul de la componente.

0
adăugat

Cum se sortează fișierul de intrare? Cum ar fi, sortarea fișierului pisică sau sortarea printr-un singur câmp specific sau câmpuri multiple? Dacă mai multe câmpuri, ce câmpuri și ce ordine? Se pare că câmpurile oră sunt un ceas de 24 de ore, nu 12, nu? Sunt toate câmpurile de dată / oră cu zgomot zero (ar fi 9 "9" sau "09"?)

Fără a ține cont de performanță, se pare că codul dvs. are probleme cu limitele lunii, deoarece presupune că toate lunile au o durată de 30 de zile. Luați cele două date 2008-05-31 / 12: 00: 00 și 2008-06-01: 12: 00: 00. Acestea sunt la intervale de 24 de ore, dar codul dvs. produce același cod de timp pentru ambele (63339969600)

0
adăugat

Cred că va trebui să luați în considerare anii de salt. Nu am făcut matematica, dar cred că, în timpul unui an bisect, cu un cod dur de 28 de zile pentru feb, o comparație de amiază pe 2/29 și la prânz pe 3/1 ar avea ca rezultat aceeași dublă timbră de timp ca înainte . Deși se pare că nu l-ai implementat așa. Pe modul în care l-ați implementat, cred că aveți în continuare problema, dar este între datele de pe 12/31 din $ leapyear și 1/1 din $ leapyear + 1.

Cred că ați putea avea și unele coliziuni în timpul schimbărilor de timp dacă codul dvs. trebuie să se ocupe de fusurile orare care le manipulează.

Fișierul nu pare a fi sortat într-un mod util. Cred că acel câmp $ 1 este un fel de statut ("OK" pe care îl verificați). Deci, este sortat după statutul de înregistrare, apoi pe DAY, apoi pe LUNĂ, ANUL, ORE, MINUTE, SECUNDARE. Dacă ar fi fost anul, luna, ziua, cred că ar putea exista unele optimizări acolo. Încă ar putea fi, dar creierul meu merge într-o direcție diferită chiar acum.

Dacă există un număr mic de chei duplicate proporțional cu numărul total de linii, cred că cel mai bun pariu este să reduceți fișierul pe care funcționează scriptul dvs. awk pentru a duplica cheile (ca David a spus ). Ați putea, de asemenea, să preprocesați fișierul astfel încât singurele linii prezente să fie linia / OK /. Cred că aș face acest lucru cu o conductă în care primul script awk imprimă numai liniile cu ID-uri duplicate, iar al doilea script awk este în esență cel de mai sus dar optimizat pentru a nu căuta / OK / și cu cunoștința că orice prezent cheie este cheia duplicat.

Dacă știți înaintea timpului că toate sau majoritatea liniilor vor avea chei repetate, probabil că nu merită. Aș mușca glonțul și îl scriu în C. Tons mai multe linii de cod, mult mai repede decât scriptul awk.

0
adăugat

@ AnotherHowie , am crezut că întreaga preprocesare ar putea fi realizat cu sortare și uniq. Problema este că datele OP par a fi delimitate cu virgulă și că uniq (Solaris 8's) nu vă permite să specificați în nici un fel separatorul de înregistrări, astfel încât nu a existat un mod foarte curat de a efectua preprocesarea folosind unități unix standard. Nu cred că ar fi mai rapid, așa că nu voi căuta opțiunile exacte, dar ați putea face ceva de genul:

cut -d, -f8 outfile.txt

Nu este foarte bun deoarece execută grep pentru fiecare linie care conține o cheie duplicat. Probabil că ați putea masura ieșirea uniq într-o singură regexp pentru a alimenta grep, dar beneficiul ar fi cunoscut numai dacă posturile OP așteaptă o rată a liniilor care conțin chei duplicate suspecte la liniile totale din fișier.

0
adăugat

Acest lucru pare a fi un loc de muncă pentru o bază de date actuală. Chiar ceva de genul SQLite ar putea să vă ajute, probabil, destul de bine aici. Marea problemă pe care o văd este definiția ta "în 4 ore". Aceasta este o problemă a ferestrelor glisante, ceea ce înseamnă că nu puteți cuantifica pur și simplu toate datele până la segmente de 4 ore ... trebuie să calculați toate elementele "din apropiere" pentru fiecare element separat. Ugh.

0
adăugat