PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [PHP/MySQL] doppelspeicherung v. Einträgen von ausgelesener Textdatei verhindern


mii
2009-02-18, 11:22:25
Eingesetzt wird: php und mysql

Problem:

Eine Text-Datei welche sich ständig aktualisiert wird zeilenweise ausgelesen

form:
userid aktionsid

- die Datei wird alle 60 sekunden von einem php-script geöffnet
- die Daten werden in einer MySQL-Tabelle gespeichert:

fortlaufendeid, aktionsid, userid, timestamp

Wie schaffe ich es am besten, das ich nur neue Einträge in die mysql-Tabelle aufnehme und nicht noch alte Daten mehrfach in die Tabelle schreibe?

Selbe userid und aktionsid kommt natürlich immer wieder vor, so wie es in der tabelle steht, nur ist der Zeitpunkt entscheidend.

Mein Ansatz ist bisher:
Ich erzeuge aus den letzten 3 Einträgen eine Prüfsumme (aktions-id und user-id) werden zusammengerechnet.
Wenn ich dann die Datei erneut durchlaufe, wird nach diesen 3 einträgen gesucht, die die selbe prüfsumme haben und ab da werden die neu gelesenen Einträge in die Datenbank übernommen.

Tommes
2009-02-18, 11:25:22
Nur speichern, wenn der timestamp > als der des letzten Eintrages in der DB ist.

Gast
2009-02-18, 11:25:49
die textdatei um timestamps erweitern.

mii
2009-02-18, 11:30:38
xD wenns meine Text-Datei wäre, wäre ich auch schon auf die idee gekommen ^^ Das wäre das naheliegenste gewesen.

Es ist eine Text-Datei die von einem entfernten server ausgelesen wird, keinen Timestamp enthält und ich kann diese auch nicht ändern.

Tommes
2009-02-18, 11:56:40
Dann merke dir zu jedem gespeichertem Datensatz die Zeile in der Datei und beim nächsten Durchlauf weißt du dann, wo du weitermachen musst.

mii
2009-02-18, 13:12:38
Es bringt leider nichts sich die zeile zu merken, denn die Datei verändert sich ständig ohne das alte Datensätze beibehalten werden.

Tommes
2009-02-18, 13:17:46
Dann musst du wohl einen Hash aus jedem Datensatz bilden, diesen Speichern und beim erneuten einlesen der Datei abfragen, ob der Hash der aktuellen Zeile bereits in der Datenbank steht.

mii
2009-02-18, 13:35:00
nein, das geht auch nicht, da die hashs mehrfach vorkommen würden in der Datenbank und das wäre dann auch richtig so.

ich glaube die möglichkeiten sind beschränkt -.-

Berni
2009-02-18, 14:29:10
Evtl. die alte Datei speichern und dann ein "diff" erstellen?

Trap
2009-02-18, 14:37:10
Wie genau weißt du, was das Skript macht?

Du kannst versuchen Doppeleintragungen zu verhindern, aber das geht nicht vollständig und dabei werden unter Umständen auch fälschlicherweise neue Aktionen ignoriert.
Wenn du 2 mal die gleiche Datei geschickt bekommst, kannst du nicht entscheiden, ob das neue Einträge sind oder nicht (bei allen oder nur bei bestimmten Dateien, je nach Aktualisierungsart).

Tommes
2009-02-18, 15:11:43
nein, das geht auch nicht, da die hashs mehrfach vorkommen würden in der Datenbank und das wäre dann auch richtig so.

ich glaube die möglichkeiten sind beschränkt -.-

Dann sehe ich in dem von dir beschriebenen Szenario keine Möglichkeit. Hast du vielleicht was übersehen?

BoneDaddy
2009-02-18, 15:20:07
- Aus der Datei den Timestamp auslesen, das sollte doch irgendwie möglich sein.
- Timestamp in den Dateinamen bringen
- Datei nach dem Verarbeiten löschen.

Tommes
2009-02-18, 15:24:04
Naja so wie ich es verstanden habe, hat er eine Texdatei die so (in etwa) aussieht:

1,43
1,556
1,43
5,64
5,76
3,65

usw. ohne Timestamps. Der Inhalt dieser Datei ändert sich anscheinend sekündlich (ist wohl ein Logfile, wer was macht). Jetzt speichert er die Daten mit aktuellem Timestamp (auch ein wenig sinnlos oder) in der DB. In 60 Sekunden macht er das gleiche, weiß aber nicht mehr wo er war. Und das kann man sich auch nicht merken. Auch nicht mit dem Ansatz aus dem Startposting, denn es ist nicht garantiert, dass beim nächsten Öffnen die gemerkte Position überhaupt noch vorhanden ist.

Fazit: Ohne Timestamps/Uhrzeiten in der Textdatei ist das ganze einfach nur sinnlos und unmöglich.

Radon
2009-02-18, 15:29:33
Wenn ich mir das hier oben so durchlese verstehe ich entweder was falsch oder die aktionsid und userid kombinationen sind nicht eindeutig... wozu braucht man da Hashes oder extra Timestamps in der Datei, wenn man das auch so machen kann?

Du kannst bei SQL abfragen ob es solche Einträge schon gibt.
Du müsstest dann die beiden spalten aktionsid und userid als Key setzen, hier müsste was dazu stehen

http://dev.mysql.com/doc/refman/5.1/de/create-table.html

Und dann entweder mit INSERT... ON DUPLICATE KEY UPDATE oder gleich mit REPLACE

http://dev.mysql.com/doc/refman/5.1/de/insert.html


Falls ich hier was falsch verstehe, schreib doch bitte mal dazu, was es mit den UserIDs und AktionsIDs auf sich hat...

Tommes
2009-02-18, 15:44:28
Natürlich sind userid und aktionsid zusammen nicht eindeutig ;) Es ist wohl ein Logfile und ein User kann eine Aktion mehrmals machen. Oft bestimmt sogar direkt hintereinander.

mii
2009-02-18, 15:46:57
Nochmal genauer:
Konkret handelt es sich um einen "Ticker" der Anzeigt, welcher User gerade welche Aktion auf der Seite ausführt.
Da der selbe User die selbe Aktion später nochmal ausführen kann, sollte user-aktion-kombination doppelt in der Datenbank vorkommen können, nur mit einem anderen Eintragungszeitpunkt.
Die DB loggt also die Aktionen.
Der Ticker entfernt alte Anzeigen und blendet neue ein, die Zahl der gerade eingeblendeten Aktionen ist jedoch variabel.

Später soll man sehen können, was wer wann gemacht hat.

Das ganze is soweit schon fertig, bzw. der rest ein kinderspiel. Das einzige was mir zu kopfzerbrechen bereitet ist diese Postitionsfindung.

Das mit dem diff ist vielleicht noch ein Ansatz mit dem ich was anfangen kann.

edit: bzw. die letzten 3 oder 5 Einträge in der Datenbank zur positionsfindung nutzen. Wenn beim parsen also diese kombination vorkommt, dann mit folgend geparsten Einträgen weiter arbeiten.


@Radon
das vorkommen, doppelter Einträge ist gewünscht. Nur zum richtigen zeitpunkt.

@Tommes

Nein, der Timestamp ist nicht sinnlos. siehe oben.

Tommes
2009-02-18, 15:48:36
Und wieso ist es nicht möglich, auch den Zeitpunkt mit in die Textdatei zu schreiben? Mit einem Ansatz sieht man ja nur, wer was wann in welcher Minute gemacht hat. Nicht den exakten Zeitpunkt.

Radon
2009-02-18, 16:01:18
Na gut, dann ist vom Designstandpunkt her die Logdatei aber ziemlich suspekt, denn wenn man sie zu irgendeinem Zeitpunkt öffnet steht halt irgendwas darin ohne richtigen Bezug.

Die Sache mit den hashwerten der letzten X Werte ist halt auch nur "Glück" (natürlich ist die Warscheinlichkeit gering, dass so eine Reihenfolge bei genügend großem X mehrmals vorkommt, aber trotzdem gegeben)

Wenn der Ticker die Datei aller paar Minuten nur schreiben und die alten Einträge dann löschen würde könnte man das Datum der Datei auslesen und vergleichen.
Nach welchem Kriterium werden denn die alten Einträge gelöscht?

Oder halt die Dateieinträge nach dem Eintrag in die Datenbank löschen (Sofern es da keine Kollisionen gibt wenn der Ticker schreiben will und die Datei noch geöffnet ist, dass er wartet bis es wieder geht)

daflow
2009-02-18, 16:05:27
Na gut, dann ist vom Designstandpunkt her die Logdatei aber ziemlich suspekt, denn wenn man sie zu irgendeinem Zeitpunkt öffnet steht halt irgendwas darin ohne richtigen Bezug.

Die Sache mit den hashwerten der letzten X Werte ist halt auch nur "Glück" (natürlich ist die Warscheinlichkeit gering, dass so eine Reihenfolge bei genügend großem X mehrmals vorkommt, aber trotzdem gegeben)


So isset. Wenn in der Textdatei pro Zeile immer nur Userid und Aktionsid drin steht ist nunmal eine eindeutige Identifizierung der Datensätze nicht möglich.

mii
2009-02-18, 16:22:45
Um noch was klar zu stellen ^^
Also ich wollte das ganze hier schematisch vereinfacht darstellen. ^^ Anscheinend bietet das immer noch zuviele interpretationsmöglichkeiten weiterer möglichkeiten. :D

Also es handelt sich nicht in dem sinne um eine text-datei in welcher nur die user-id und aktions-id gespeichert werden.

Es ist eine html-Datei, welche mit CURL von mir abgerufen wird ,in welcher user-bild, user-name, user-id, Aktion als Text und wann diese Aktion statt fand ABER


Es werden alle elemente aus dem Quelltext geparst und parallel eine user-tabelle aufgebaut mit den gefundenen usern (username und userid) und die aktion wird in eine seperate tabelle mit nem timestamp gespeichert.
Die userid aus der usertabelle und aktionstabelle sind identisch und so später verknüpft.
Diese Ticker-html-Datei wird sekundlich auf dem anderen Server aktualisiert.

Mein Script könnte ich auch in ner Schleife laufen lassen, welche sekündlich die Daten ausliest, was aber nicht erforderlich wäre. Alle 10 oder 30 sekunden würden auch reichen.

Der Zeiptunkt der in der Tickerseite angegeben wird ist "blöd" zum parsen und als bezugswert zu verwenden, da dort keine uhrzeit steht, sondern "gerade eben", "vor einer Minute", "vor 15 Minuten" etc.

Die Einträge in der Tickerseite werde nach einer bestimmten Zeit entfernt oder wenn eine bestimmte anzahl erreicht ist.

daflow
2009-02-18, 17:16:49
[...]
Es werden alle elemente aus dem Quelltext geparst und parallel eine user-tabelle aufgebaut mit den gefundenen usern (username und userid) und die aktion wird in eine seperate tabelle mit nem timestamp gespeichert.
[...]

Und jetz nochmal für die ganze blödene wie mich... Äh, was spricht dagegen die passende Aktion incl. Timestamp, dann aus dieser Tabelle wieder auzulesen? ;(

mii
2009-02-18, 19:34:23
vielleicht bischen kompliziert ausgedrückt von mir. ^^

die tabelle mit

aktion, userid und timestamp

ist MEINE Tabelle. Ich versehe erst die Daten mit einem Timestamp. Die haben vorher also keinen timestamp. Was icht in MEINE Tabelle als letztes eingefügt habe, weiß ich allein schon wegen der fortlaufenden id und dem ende der tabelle :D

wenn die ich diese ticker-datei erneut aufrufe muss ich wissen welche "Datensätze" ich da zuletzt rausgezogen und meine Tabelle geschrieben habe.
Bei den geparsten Daten aus der html-Seite habe ich keine zeitliche orientierung.

Tommes
2009-02-18, 20:59:26
Ich glaube, was du machen willst und woher die Daten kommen versteht hier keiner :) Am besten erklärst du noch mal ganz genau was du hast und was du willst, ich werde daraus nämlich nicht schlau :D

Berni
2009-02-18, 21:28:14
Also soweit ich das jetzt verstanden habe sieht es so aus: Er möchte eine externe Seite parsen (bzw. wohl eine Web2.0-Seite komplett crawlen/überwachen). Auf dieser gibt es etwas ala
Aktionen der letzten Minute
====================
Thomas (userid 1) hat das Profil geklickt
Thomas (userid 1) hat eine Nachricht im Gästebuch hinterlassen
Markus (userid 2) hat sich eingeloggt
.....
Diese Infos (userid und AktionsID) möchte er in der Datenbank speichern, so dass er die genaue Abfolge der Aktionen lückenlos und ohne Duplikate hat.

mii
2009-02-18, 22:12:03
@berni

danke :D

genau das und im prinzip sieht es auch schematisch genauso aus.

mir geht es einzig und allein nur noch darum, das einträge nicht versehentlich doppelt protokolliert werden.

Berni
2009-02-18, 23:13:47
Wie wärs denn wenn dus folgendermaßen machst:
Du speicherst die userIDs/aktionsIDs des letzten Durchlaufs zeilenweise in einer Datei old.txt.
Beim Laden einer neuen "Datei" lädst du diese Datei mit "$old = file('old.txt')" ein, so dass du sie als Array hast. Nun suchst du in der neuen "Datei" nach dem letzten Eintrag in $old ("$old[count($old)-1]"; bzw. ersten je nachdem wie rum dus speicherst). Sobald der Eintrag gefunden wurde, vergleichst du entsprechend mit der vorletzten Zeile weiter usw. bis Arrayeintrag 0 der neuen (!) Datei erreicht ist. Wenn davor ein Unterschied gefunden wird, muss man weiter nach diesem letzten Eintrag suchen, ansonsten hat man den Einstiegspunkt gefunden.

Das setzt natürlich voraus, dass nicht zwischendrin was gelöscht wurde, aber normalerweise sollte das auch nicht vorkommen weil es sonst ein fast unmögliches Problem ist.

mii
2009-02-19, 13:58:56
das ist eine interessante lösung.
Sowas ähnliches ging mir gestern abend auch noch durch den kopf.
ich muss das nur mal umsetzen.

Jedenfalls bleibt einem nichts anderes übrig, als sich an der reihenfolge der vorherigen einträge zu orientieren, was nicht 100%ig sicher ist, aber besser als nichts. :D