[PHP] Array search startpunt

Pagina: 1
Acties:
  • 267 views sinds 30-01-2008
  • Reageer

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
CASE
log-file per dag van 4000+ regels, elk met een unique key
updated tot een bepaalde regel, maar er zijn nieuwe regels
log-bestand in een array, $logfile[x] . Elk element heeft een regel van de logfile

DOEL
Startpunt zoeken, en met het VOLGENDE element in de array verder gaan met { commands; }

VRAAG
Hoe?

Wijn is lekk0r :D Je kan de key van de array vinden door een array_search te doen. Maar hoe moet je dan verder gaan? Niet met een foreach loopje iig.. Ideeën? Als deze vraag te simpel is: plz een kort zoekbaar antwoord en een slotje ;)

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

waarom moet dat toch altijd in arrays??
Ga je straks een logfile van 2GB ook in een array inlezen? ;)

Oftewel vergeet dat array:
lees_vorige_in();
fopen();
fseek($vorige);
fgets(tot het einde);
$vorige = ftell(waar ben je nu?);
fclose();
sla_vorige_op();

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
nikolai@bigaction_dot_org
21-Mar-2002 06:39

> Don't try this and expect it to work:
>
> while(next($array))
>
> the loop will never begin on the first item in the array
> since next() advances the pointer BEFORE returning
> the values.

Humm... idee? Denk denk [Jaja, jullie maken het mee; Een live brain-storm! :D]

[00:31] <elviver> AAAAAAARGHZZZZ
[00:31] <elviver> completely excited about array_search()
[00:31] <elviver> PHP > 4.0.5
[00:31] <elviver> phpinfo() => 4.0.4 pl 1 AARGH

hum.. functie zelf maak ;) goed. mooi.

Mooi. Ik kan de KEY vinden van het element, vanaf dáár wil ik vender gaan ( while(next($array) ), maar hoe zet ik de pointer van die array daaro?

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Je hebt gelijk :P
Maar je uitleg snap ik niet helemaal wat je allemaal zegt. Volgens mij doe je (excuse de wijn) zoeken in het bestand naar de unique key. Maar hoe ga je dan de rest van het bestand afwerken (en de overige bestanden NA dat bestand in de geopende dir)?

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Op woensdag 17 april 2002 00:42 schreef elviver het volgende:
Je hebt gelijk :P
Maar je uitleg snap ik niet helemaal wat je allemaal zegt. Volgens mij doe je (excuse de wijn) zoeken in het bestand naar de unique key. Maar hoe ga je dan de rest van het bestand afwerken (en de overige bestanden NA dat bestand in de geopende dir)?
Nee, ik vergeet het principe van keys en werk met regelnummers/offsets in files :)

En dan kun je bij die fgets() wat met je dingen doen.
Maar ik denk dat je je vraag ietsje beter moet stellen wil je een werkbaar antwoord krijgen :)

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Betere vraag :)

Ik heb een log-file per dag van 4000 regels. Elke regel bevat een unieke code.

In PHP lees ik de regels in, en sla ze op een "normale" (lees niet 4000 regels lang) manier op in een db. Dit heet de update-functie ;)

De update-functie is klaar met draaien, en mag na 5 minuten weer. Maar dan moet ie dus opzoeken in het laatst geopende bestand naar de plaats waar die gebleven was. Dit is NA regel x (de unieke code IS opgeslagen in de DB).

Huidige situatie: Ik fetch de laatste unieke code en de datum uit de DB. Ik lees het bestand met de corresponderende datum in een array, en foreach die array totdat een van de elementen de juiste unieke key bevat. DAAR zet ik $fromhere op true, wat opgevangen wordt door de rest van de functie en met de rest van de regels gaat spelen.

Dit is TRAAAAAAAAAAG. Ik wil het anders. Maar hoe?

Verwijderd

elviver: Ik heb een log-file per dag van 4000 regels. Elke regel bevat een unieke code. [Ik] lees de regels in, en sla ze [...] op in een db.
5 minuten [later] moet ie dus opzoeken in het laatst geopende bestand naar de plaats waar die gebleven was.
[Hudige oplossing] is TRAAAAAAAAAAG. Ik wil het anders. Maar hoe?
Kijk eens naar ftell en fseek.

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Op woensdag 17 april 2002 00:56 schreef Arien het volgende:
Kijk eens naar ftell en fseek.
En dus nog eens naar mijn posting ;)

Verwijderd

ACM: En dus nog eens naar mijn posting ;)
Ehmmm... :o ja, ik zie het... nu. |:(

Het was vannacht wel erg laat geworden, maar dat wist je al? :P

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Op woensdag 17 april 2002 01:13 schreef Arien het volgende:
Het was vannacht wel erg laat geworden, maar dat wist je al? :P
Mja, als jij nu reageert... ;)

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Dus.. Ik zit weer op mijn werk.. Ik weet niet of het aan de wijn lag, maar me internet-verbinding lag er ineens spontaan uit.. Maar goed.

Ik heb even op php.net gekeken bij fseek, maar daar vind ik de volgende beschrijving: Sets the file position indicator for the file referenced by fp. The new position, measured in bytes from the beginning of the file, is obtained by adding offset to the position specified by whence..

Dus je moet het (sorry, kan het niet testen hiero) gebruikern als fseek($openfile, offset). Maar hoe kan ik dan in dat bestand zoeken? werkt iets als fseek($openfile, "24172341234") ook? Zet ie dan de filepointer op het begin waar 24172341234 voorkomt?

Verwijderd

elviver: Hoe kan ik in dat bestand zoeken met fseek?
Je moet met fseek niet zoeken in het bestand. Je moet met fseek gaan naar een record waarvan je offset al weet (omdat je daar bent opgehouden).

Nou moet het ondertussen wel lukken toch? :)

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Ghe, ik hoop dat het kan lukken.. Ik kan het niet testen helaas :( Maar ik kan wel kennis vergaren :D

Wat ik in de logfile heb, zijn zulke regels:
code:
1
2
3
4
5
6
2002-04-14 08:42:31,192.168.0.2,142543987,5
2002-04-14 08:42:57,192.168.0.4,142813477,3
2002-04-14 08:43:20,192.168.0.5,233471566,1
2002-04-14 08:43:20,192.168.0.1,814775632,6
     ^^^^        ^^^^    ^^^^   ^
     tijd         ip      UID    Hits

Ik sla in de database de UID (Unieke code) op.. Niet een offset. Wat dus de bedoeling is, is dat ie een van die UID's weer opzoekt.

Of zou het handiger zijn bij het updaten een offset op te slaan? Zo van als het het laatste bestand is en de filepointer de laatste regel voorbij is, sla dan zijn offset op in de db en ga bij de volgende update dáár verder? Maar wat gebeurt er dan als de log-file nog NIET groter is geworden (of in een andere logfile, die van de volgende dag) is verder gegaan?

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
^^^ (ja, deze mag even up, even verder lezen ;))

Owkeey.. Ik heb gespeeld met fseek en ftell. Het is inderdaad redelijk makkelijk te gebruiken. Weer iets meer van PHP geleerd! :)

Maar wat ik ook leerde: ik mijn situatie is fseek en ftell stukken trager! Hmmm.. Ik kijk nu die code weer door, en weet niet waarom ik ftell en fseek niet gebruikt heb, maar er was een reden voor! Kom er wel weer op.

Goed, mijn probleem. Ik prop een log-bestand dus alsnóg in een array, $lines = file ($file); Ik de database staat op welke regel die gebleven was, en dat zoek ik nu op de volgende manier op:
PHP:
1
<?$openfile = file ($filename); // Open het goede bestand  while (list ($linenr, $line) = each ($openfile)) {    if ($linenr >= $fromline) { // Goede (vervolg-)regel gevonden    $field = explode (",", $line);    if (isset ($field[1])) { // Als het geen leeg veld is (en dus hopelijk geen corrupte lijn)      commands();    } // if  } // if linenumber groter dan wat er in de database staat} // while?>

$fromline is dus uit de database afkomstig. Het wérkt, maar het is langzaam.

Voordat jullie gaan roepen: gebruik toch fseek, fgets & ftell: Dat ga ik zo er weer instoppen en testen wat sneller is!!

Wat ik jullie wil vragen: HOE zet ik de array-pointer van $openfile op het element $fromfile ? Dan kan ik vanaf dáár verderlezen met de while (list ($linenr, $line) = each ($openfile));

  • Bpje
  • Registratie: November 2000
  • Laatst online: 21-06 16:07
ik neem aan dat je wat wil doen met die gegevens die toegevoegt zijn okay order by tijd en een limit er bij zo dat je niet alls hoeft te doen, je cobineerd geween de aktie met de zoek functie. Lijkt mij:?

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Op dinsdag 23 april 2002 09:51 schreef Bpje het volgende:
ik neem aan dat je wat wil doen met die gegevens die toegevoegt zijn okay order by tijd en een limit er bij zo dat je niet alls hoeft te doen, je cobineerd geween de aktie met de zoek functie. Lijkt mij:?
Wát zeg je??? Ik snap niets van je zinnen.. Sorry!

Ik wil wat doen met de gegevens ja.. Deze code wordt op een bepaald moment uitgevoerd.. Het bestand wordt later aangepast (het is immers een logfile), en als deze code opnieuw uitgevoerd wordt, moet ie iets doen met de NIEUWE gegevens.
Ik heb in de database opgeslagen in welke regel hij gebleven was.. De vraag is nu alleen hoe ik zonder die while-if combinatie sneller de pointer van de array op de goeie regel kan zetten..

  • Bpje
  • Registratie: November 2000
  • Laatst online: 21-06 16:07
Okay ik was ook wat kort maar goed hier gaat het nog een keer:
je log file:
code:
1
2
3
4
5
6
7
2002-04-14 08:42:31,192.168.0.2,142543987,5
2002-04-14 08:42:57,192.168.0.4,142813477,3
//een hele hoop regels 
2002-04-14 08:43:20,192.168.0.5,233471566,1
2002-04-14 08:43:20,192.168.0.1,814775632,6
     ^^^^        ^^^^    ^^^^   ^
     tijd         ip      UID    Hits

nu begin je van af boven te lezen net zo lang tot je je laatste element tegen komt en dan stopje, in het proces van het lezen sla je het niet op maar doe je gelijk het aanpassen van je stats.

Ik ben er wel van uit gegaan dat je je stats opslaat en die eens in de zoveel tijd wil updaten. dus je hebt een log file en je stats file die wil je weer tot 1 nieuwe file maken. of dat nou gegevens in een tabel zijn of gewoon een tekst file dat moet niet uit maken.

Ik wil hier dus mee zeggen dt je het helemaal niet op hoeft te slaan, scheelt een hoop snelheid en ruimte.

(als je source wil dan moet je dat zeggen)

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Ik zeg nix ;) Ik hoef geen source..
Ik pak gewoon dat hele bestand in een array inderdaad.. Dan ga ik lezen tot het keynummer bij de betreffende regel is, alleen kan dat nogal lang duren als er 4000+ regels in 1 logbestand zit..

Ik zoek een soort fseek functie om de pointer van een array te verplaatsen.

  • Tim
  • Registratie: Mei 2000
  • Laatst online: 04-08-2025

Tim

En als je nou eens aan de andere kant van het bestand begint? Dus van achter naar voren?

Of snap ik het nu niet?

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Op dinsdag 23 april 2002 16:57 schreef Timpie het volgende:
En als je nou eens aan de andere kant van het bestand begint? Dus van achter naar voren?

Of snap ik het nu niet?
Sjonge jonge jonge jonge.. Soms kan het zóóóóó simpel zijn! w00000t

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Je weet toch waar je eindigt (punt Y) in de file op moment X ?
Dan kan je op moment X+1 toch naar punt Y gaan en dan verder lezen??

Waarom moet je toch zo moeilijk doen met een array? Je slaat zelfs al op bij welke regel ie gebleven was gestopt...

  • Bpje
  • Registratie: November 2000
  • Laatst online: 21-06 16:07
Ik wil eerst iets duidelijk hebben. Waarom sla je het op in tekst file en niet in een DataBeest en wat wil je doen met de gegevens die die dag binnen zijn gekomen? En graag een beetje uitgebreid niet van ik maak er stats mee. meer iets van ik haal uit elke regel gegevens enz..

ACM helemaal met je eens waarom zo moeilijk array is niet gebouwd voor zulke datastructuren en DB wel. Mijn keuze zou zo en zo een db zijn maar ja ik ben hele goed bevriendt met mijn db :)

Verwijderd

als je nou op moment X (om het zo maar even te noemen), de grootte in bytes van het bestand ergens opslaat en je gebruikt die grootte als offset in fseek op moment x+1?

of zit ik dan weer verkeerd...

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Dat is wat ik bedoel... Tenminste, als je dan zo handig bent de ftell() functie ervoor te gebruiken ;)

Verwijderd

achja, volgende keer lees ik eerst wel alles doro voordat ik iets zeg :D

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Ghehehe wat een lol hier allemaal weer :)

Ik ben dus ontzettend veel log-files aan het doornemen.. Ik ben aan het timen wat voor mij het snelste is. De vorige keer probeerde ik het met fopen en ftell inderdaad, en vergeleek dat met file().. Dat laatste bleek sneller te zijn, dus ben ik daar maar mee doorgegaan.

Ik ben nu weer terug naar fopen, fseek en ftell, omdat ik dan de pointer erg mooi kan opslaan in de database. Maar iets dergelijks kun je natuurlijk ook door voor file(). Gewoon de key opslaan in de database, zo van daar was ik. Maar met array's heb je volgens mij niet zo'n mooie functie om de pointer te verplaatsen als fseek, behalve als je inderdaad aan het eind van de array begint en telkens 1tje teruggaat (while list = each { prev (array); prev (array) }. Dat ga ik óók nog testen :) Ik vrees alleen dat dat langzamer is, maar dat zien we dan wel weer :)

  • Apollo_Futurae
  • Registratie: November 2000
  • Niet online
Als je het dan toch graag met arrays wilt doen, kun je de volgende twee functies gebruiken:

array array_slice ( array array, int offset [, int length])

array_slice() returns the sequence of elements from the array array as specified by the offset and length parameters.

foreach(array_expression as $value) { statement }


denk erom dat je bij offset de index waar je gebleven was met 1 moet verhogen *D

Pas de replâtrage, la structure est pourrie.


  • Bpje
  • Registratie: November 2000
  • Laatst online: 21-06 16:07
Waarom maak je niet een soort header in de file of hou bij hoeveel elementen erbij worden gevoegt in een andere file ofzo.

Maar ik weet nog steeds niet wat je wil doen met die gegevens? Zou je een kleine uitleg kunnen geven. of beantwoord de volgende vraag eens: Moet ik alle informatie die op 1 dag (o.i.d.) is binnnen gekomen evalueren ? of gaat het alleen maar om de laatste/ eerste?

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Oke oke oke... Zal ik dan maar niet zo kinderachtig zijn en maar laten zien waar ik mee bezig ben? Kunnen anderen ook ideeën krijgen enzo.. Je bent de tweede die het vraagt (ook in dir draadje), en ik heb nu zoiets van what the heck. :)

Ik ben een DPC logfile parser aan het maken. Die zijn er toch al? Jawel, maar niet realtime, en daar ben ik dus mee bezig *D

Logfile wordt bijgewerkt door de proxy. Die kan een hourly, daily, weekly, monthly, yearly of geen logrotation hebben. Stukkie logfile:
code:
1
2
3
4
5
2001-04-15 19:09:06,212.120.110.212,dpc_viedz@hotmail.com,2420c56c60000000,294,1,1,8010
2001-04-15 21:30:41,213.75.7.21,dpc_viedz@hotmail.com,2245c18d00000000,12,1,1,8010
2001-04-15 23:24:37,213.10.120.13,dpc_viedz@hotmail.com,22a88e53f0000000,809,1,1,8010
2001-04-15 23:44:43,192.168.0.2,dpc_viedz@hotmail.com,208db57f70000000,487,4,1,8010
2001-04-15 23:53:35,212.204.142.202,dpc_viedz@hotmail.com,23d614f580000000,603,1,1,8010

Van links naar rechts: Datum, IP, email, code, units (aka blocks), OS, CPU en version.

De stats die gegeven gaan worden: By email, OS, CPU, Version, Full detail (dus OS, CPU en Version), én: byhost. Dat werktte al een tijd (lees een half jaar), maar meer en mensen begonnen te flushen, en de update-byhost combinatie duurde veel te lang om te laden. 30 seconde gemiddeld!!

Dat lange laden lag eraan dat ik in de database geen ID had opgeslagen van degeen die het blokje ingeleverd had. In byhost.php las ik alle data van de laatste 5 dagen in, en ging bij de IP's de namen zoeken. Allemaal wel redelijk geoptimaliseerd de query's, maar niet toen er 50 losse IP's instonden!

Dus, mijn idee was het sneller te maken (doh :P). De update moet het ID al in de database zetten als ie aan het updaten is. De vorige update groepeerde alle regels in de log als het IP, datum, OS, CPU en version gelijk was. Vergelijkbaar met striplog voor de intimi ;) De laatste unieke code die bij een regel gevonden was werd ook opgeslagen. Bij de volgende update keek ik gewoon naar de allerlaatste unieke code in de database, de datum, en opende het logbestand (niet rekening houdend met de verschillende rotations), las elke regel in totdat ie die block-code ergens tegenkwam. Dát was het startpunt om te zoeken.

Ja, da's traag ja :P Dus, op advies van iedereen (thanx GoT mainly), sla ik nu de offset en de filename op in de database. Er wordt ge fopend, fseekt, while (fgetcsv)'t, ftellt en de offset geupdated. In het while-loopje van fgetcsv maak ik die multidimentional array aan (zie ook weer dit draadje), die ervoor zorgt dat er gegroepeerd wordt, door array-keys te vormen adhv de regel uit de logfile en dieper daarin de units op te tellen (en zo units bij bestaande array elements op te tellen, of een nieuw array element te maken als de combo date, ip, email, os, cpu en version nog niet gezien is).
Als alle logfiles doorlopen zijn (dat is het langdurigste deel) heb ik dus een multidimentional array $getid.
$getid[IP][sortkey][0] datetime
$getid[IP][sortkey][1] units
sortkey = YYYYMMDD,email,os,cpu,version
Die dorloop ik met een foreach, en bouw daar een mysql-query van, en die rag ik dan naar de databeest (die duurt niet zo lang, 0,003 seconde >:))

Sow.. Nu heb ik wel weer teveel getikt ;) Nu mogen jullie weer als jullie nog zin hebben. Vraag maar raak, je mag alles van me weten (behalve me pincode en me w8woord :P)

  • DRvDijk
  • Registratie: Juni 2001
  • Laatst online: 12-02 15:52
Ow ja, de bedoeling is dat dit geintje ook precies hetzelfde werkt voor OGR, aangezien RC5 wel eens afgelopen gaat zijn denk ik zo :)

Verwijderd

Ik zou elke minuut een cronjobje laten draaien die deze data in de DB gooit. De logfile eerst moven en je programma eventueel -HUP'en zodat hij weer een nieuwe logfile aanmaakt.

In dit jobje zou ik dan zo min mogelijk logica zetten en al helemaal niet met dat substr gepiel. Ik zou alvast het date field netjes omzetten en eventueel die IP nummers met ip2long wegschrijven ofzo.

Ik zou dan ook kijken of ik dit jobje eventueel kan starten vlak voordat iemand de statestieken wil gaan bekijken. Op deze manier ben je amper data aan het opsparen en kun je nog steeds spreken van 'realtime'.

Vervolgens zou ik het rekenwerk zoveel mogelijk in de queries zelf doen. Met wat slimme indices gaat dat allemaal veel sneller en vooral makkelijker.

Verwijderd

Oh.. en mocht je toch met die arrays door willen gaan.. Ik heb wel eens zitten klooien met array_diff. Is wel niet zo netjes maar wel zo makkelijk. Gewoon de oude iedere keer opslaan, allebei naar binnen trekken met file() en de nieuwe vergelijken met de vorige.
Pagina: 1