simenss Skrevet 11. september 2007 Del Skrevet 11. september 2007 Jeg har et system hvor brukere kan stemme på flere tusen objekter. Det er veldig viktig at hver bruker ikke kan stemme på samme objekt mer enn en gang per dag. Hvordan løser jeg dette på en praktisk og ytelsesvennlig måte? Alle brukere har hver sin unike ID, noe hvert object også har. Jeg ønsker hovedsaklig en løsning som ikke er avhengig av sessions og cookies, da dette ikke er sikkert nok. Noen innspill? Lenke til kommentar
NorskFirefox Skrevet 11. september 2007 Del Skrevet 11. september 2007 Har du innlogging? Om du har det må du jo også ha en form for sessions eller cookies. Men det du kan gjøre er at du lager en database (blir ganske stor, så kreves vedlikehold) hvor du har fire rader. id bare for å ha noe unikt i alle radene, bruker-id, objekt-id, og tid. Her kan du velge to forskjellige tider: Enten time() hvor du så må regne ut om det er en dag senere eller ikke, eller du kan bruke date("z"). Ganske likegyldig hvilke du bruker. Lenke til kommentar
simenss Skrevet 11. september 2007 Forfatter Del Skrevet 11. september 2007 Har innlogging ja, og benytter da selvfølgelig både sessions og cookies. Grunnen til at jeg ikke ønsker å benytte sessions og cookies til denne funksjonen, er at brukeren lett kan fjerne både sessions og cookies. Ideen om en egen tabell i databasen har jeg tenkt på, men tenkte også at siden det er snakk om veldig mange bilder og brukere, vil datamengden bli stor, og mye resurser vil gå med til å sjekke om brukeren allerede har stemt på bildet samme dagen (men kanskje jeg tar feil?). Si at det er snakk om alt fra 5.000 til 1.000.000 brukere. Vil løsningen din da holde mål? Lenke til kommentar
NorskFirefox Skrevet 11. september 2007 Del Skrevet 11. september 2007 Det viktigste om du bruker en løsning som det er at du må sørge for å vedlikeholde databasen. Viktig at du tar med dato/tid og sletter innlegg som er for gamle. Satt opp en database nå med godt over 600 000 innlegg, og tok 0.7 sekunder og hente 1000 tilfeldige innlegg. (Med en ny spørring pr. innlegg). Men er det 1 000 000 som stemmer samme dag? Eller totalt? Lenke til kommentar
simenss Skrevet 11. september 2007 Forfatter Del Skrevet 11. september 2007 (endret) Har allerede et script som rydder diverse tabeller, de fleste to ganger per døgn. Å fjerne rader som i dette tilfellet er over et døgn, er en selvfølge. Men hvor mye en database/server klarer vet jeg veldig lite om. Jeg tenkte på at om det finnes 1.000.000 registrerte brukere, og 30 % av disse avlegger i gjennomsnitt 10 stemmer hvert døgn, må løsningen takle dette. Det er kun et tenkt eksempel, men systemet må som sagt takle det. Vil en løsningen med et innlegg per stemme være aktuellt? EDIT: Og forresten, gratulerer med dagen NorskFirefox Endret 11. september 2007 av simenss Lenke til kommentar
Martin A. Skrevet 11. september 2007 Del Skrevet 11. september 2007 (endret) Du kan legge inn et serialisert array i et felt som tilhører bildet. Indeksen på arrayet kan være brukeriden, så setter du timestamp på når han stemte som en av verdiene. feks: Array { [123] => array => [timestamp] => idag } $arr = serialize( array( $userid => array('timestamp' => time(), ) ) ); Så sjekker du med in_array (etter unserialize) om brukeren finnes i arrayet, og/eller har stemt i løpet av siste 24 timer. Så kan man bruke array_merge() for å legge til nye brukere, hvor du igjen bruker serialize() før du oppdaterer databasen. Endret 11. september 2007 av M4rTiN Lenke til kommentar
Ernie Skrevet 12. september 2007 Del Skrevet 12. september 2007 (endret) Dette burde vel være ganske straight forward med en koblingstabell mellom bruker og objekt hvor man også legger til tidspunkt for siste stemme. For å holde antall rader i tabellen nede kan man passe på å sette primærnøkkel til brukerid og objektid, og iallfall i MySQL kan man så kjøre REPLACE-spørringer slik at det aldri blir mer enn en rad pr. bruker-objekt-kombinasjon. Edit: REPLACE blir et dumt valg. Bruk heller INSERT ... ON DUPLICATE KEY UPDATE Endret 12. september 2007 av Ernie Lenke til kommentar
simenss Skrevet 16. september 2007 Forfatter Del Skrevet 16. september 2007 (endret) Dette burde vel være ganske straight forward med en koblingstabell mellom bruker og objekt hvor man også legger til tidspunkt for siste stemme. For å holde antall rader i tabellen nede kan man passe på å sette primærnøkkel til brukerid og objektid, og iallfall i MySQL kan man så kjøre REPLACE-spørringer slik at det aldri blir mer enn en rad pr. bruker-objekt-kombinasjon. Edit: REPLACE blir et dumt valg. Bruk heller INSERT ... ON DUPLICATE KEY UPDATE 9478197[/snapback] Har gått for løsningen med en egen tabell for stemmene. For å forklare problemet under bruker jeg følgende struktur på tabellen: vote_user = ID-en til brukeren som har gitt stemmen vote_object = ID-en til objektet brukeren har stemt på vote_datetime = stemmens dato og klokkelsett ...og følgende variabler: $user = brukeren som prøver å stemme $object = objektet brukeren ønsker å stemme på Har støtt på et problem når jeg benytter meg av INSERT ... ON DUPLICATE KEY UPDATE. MySQL skal kun oppdatere vote_datetime dersom $user allerede har gitt en stemme til $object. Om ikke, må en ny rad settes inn i tabellen. Det jeg må få til er derfor noe som: INSERT INTO `votes` (`vote_user`, `vote_object`, `vote_datetime`) VALUES ('$user', '$object', NOW()) ON DUPLICATE KEY UPDATE `vote_datetime` = NOW() MySQL må altså "oppfatte" at det blir en duplikat dersom det allerede finnes en rad hvor både vote_user = $user OG vote_object = $object. Noen tips? Endret 16. september 2007 av simenss Lenke til kommentar
Ernie Skrevet 16. september 2007 Del Skrevet 16. september 2007 Hva er primærnøkkelen? Den bør i dette tilfellet være satt til vote_user og vote_object. Ev. kan de være unique. Lenke til kommentar
simenss Skrevet 16. september 2007 Forfatter Del Skrevet 16. september 2007 (endret) Hva er primærnøkkelen? Den bør i dette tilfellet være satt til vote_user og vote_object. Ev. kan de være unique. 9509105[/snapback] Det er ikke mulig å definere to primærnøkler, og ingen av de kan være unike da en bruker kan stemme på flere objekter, og et objekt kan blir stemt på av flere brukere. EDIT: Var litt rask her. Man kan ikke definere to primærnøkler, men primærnøkkelen kan bestå av to rader. Problemet er løst Endret 16. september 2007 av simenss Lenke til kommentar
simenss Skrevet 17. september 2007 Forfatter Del Skrevet 17. september 2007 Kom over et nytt problem: Hvordan henter jeg ut de stemmene som er eldre enn et døgn og tilhører brukeren som ønsker å stemme, eller de objektene som brukeren ikke har stemt på ennå? Spørringen min ser foreløpig slik ut: SELECT objects.object_id, objects.object_user, objects.object_title, votes.vote_user_id, votes.vote_object_id, votes.vote_time, users.user_verification FROM `objects` LEFT JOIN `votes` ON (objects.object_id = votes.vote_object_id) RIGHT JOIN `users` ON (objects.object_user = users.user_id) WHERE `user_verification` = '1' AND `user_id` != '$user' AND DATE_FORMAT(NOW(), '%Y%m%d%H%i%S') - DATE_FORMAT(vote_time, '%Y%m%d%H%i%S') >= 1000000 GROUP BY `object_id` ORDER BY RAND() LIMIT 1 Jeg har tabellen users (tabell med alle brukere), objects (alle objektene som kan stemmes på) og votes (alle stemmer som gis). Problemet her er at spørringen ikke klarer hente ut de objektene fra objects som brukeren ikke har stemt på (det finnes ingen rad i votes som inneholder både vote_user_id = bruker som nå prøver og stemme, og vote_object_id = objektet som brukeren nå prøver å stemme på). GROUP BY og ORDER BY er lagt til for å prøve å spre stemmene mest mulig ut over de forskjellige objektene. Kanskje noe vanskelig forklart? Lenke til kommentar
simenss Skrevet 18. september 2007 Forfatter Del Skrevet 18. september 2007 (endret) Tror jeg nå har funnet riktig metode, men løsningen er jeg usikker på. Spørringen i forrige innlegg må ekskludere alle stemmer som er en stemme på det samme objektet. Altså, om bruker B ønsker å stemme på objekt X1, men bruker A allerede har stemt på objektet X1, må spørringen ekskludere stemmen (raden) som A har gitt X1. Med andre ord fjerne duplikater, men beholde stemmen (raden) for aktuell brukers (B) stemme. Dette innlegget ble tungt... Endret 18. september 2007 av simenss Lenke til kommentar
roac Skrevet 19. september 2007 Del Skrevet 19. september 2007 Å finne rader som ikke har match er da såre enkelt, fort og galt blir dette noe i retning av: select a.* from a left outer join on (a.en_id = b.en_id) where b.en_id is null; Dette burde i hvert fall være nok for å kunne løse problemstillingen din. Lenke til kommentar
simenss Skrevet 19. september 2007 Forfatter Del Skrevet 19. september 2007 (endret) Kanskje jeg ikke helt forstår hvordan jeg kan bruke spørringen din, men får det ikke til å fungere. Skal prøve å forklare litt bedre: Si at jeg har to tabeller: votes og objects votes: object_id user_id time 1000 101 9487 1001 101 13544 1003 202 41546 1005 202 1542 objects: object_id 1000 1001 1002 1003 1004 1005 Jeg skal nå hente ut alle objekter som bruker_id 202 ikke har stemt på (gyldige objekter er 1000, 1001, 1002, 1004), og de objektene som bruker_id 202 har stemt på men hvor time <= 10000 (gyldige objekter er 1005). De objektene jeg skal sitte igjen med er dermed 1000, 1001, 1002, 1004 og 1005. EDIT: Med din spørring roac, klarer jeg kun å hente ut de objektene bruker_id 202 ikke har stemt på. Endret 19. september 2007 av simenss Lenke til kommentar
siDDis Skrevet 19. september 2007 Del Skrevet 19. september 2007 Du kan ikkje hente ut ein mengde av ein mengde som brukeren har stemt på av dei han ikkje har stemt på. Men ein annen tankegang er å plukke opp dei som følger de kriteriene logikken blir vell ala: WHERE NOT EXISTS ( SELECT alle objekter bruker id 202 har stemt på) AND EXISTS ( SELECT alle objekter brukeren har stemt på som er <=10000) Lenke til kommentar
roac Skrevet 19. september 2007 Del Skrevet 19. september 2007 Kjapt før jeg går hjem, fyll inn det som mangler: select ... from objects o left outer join votes v ... left outer join users u ... where (u.user_name ... and v.time ...) or v.user_id is null Lenke til kommentar
simenss Skrevet 19. september 2007 Forfatter Del Skrevet 19. september 2007 (endret) Kjapt før jeg går hjem, fyll inn det som mangler: select ... from objects o left outer join votes v ... left outer join users u ... where (u.user_name ... and v.time ...) or v.user_id is null 9527765[/snapback] Jeg ender da opp med følgende spørring: SELECT votes.vote_user_id, votes.vote_time, user_objects.user_object_id, user_objects.user_object_user, user_objects.user_object_title, votes.vote_object_id, votes.vote_time, users.user_gender, users.user_username, users.user_verification FROM `user_objects` left outer join `votes` ON (user_objects.user_object_id = votes.vote_object_id) left outer join `users` ON (user_objects.user_object_user = users.user_id) WHERE (users.user_id = '$user' AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) >=1000000) OR votes.vote_user_id IS NULL Spørringen henter ut de objektene brukeren selv ikke har stemt på (eller tiden er >= 1000000), men den klarer ikke hente ut de objektene som andre brukere har stemt på men som aktuell bruker ikke har stemt på. Spørringen klarer altså ikke å skille aktuell brukers stemmer og andre brukeres stemmer. Det er dette problemet jeg har hatt hele veien. Endret 19. september 2007 av simenss Lenke til kommentar
roac Skrevet 19. september 2007 Del Skrevet 19. september 2007 Nå begynner jeg å ramle av her. Mulig jeg har oversett noe, men jeg trodde du ville hente ut de som brukeren ikke har stemt på, eller det er en gitt tid siden han har stemt på. Uansett mener jeg at du ved å bruke fremgangsmåten i spørringene vil kunne klare å få ut det du vil. Med håndtering av nulls og bruk av outer joins kan du ganske effektivt få ut akkurat det du måtte ønske. Lenke til kommentar
simenss Skrevet 19. september 2007 Forfatter Del Skrevet 19. september 2007 Det er akkurat det jeg vil. Har formulert det slik tidligere: Hvordan henter jeg ut de stemmene som er eldre enn et døgn og tilhører brukeren som ønsker å stemme, eller de objektene som brukeren ikke har stemt på ennå? Prøver å forklare med noen skjermbilder fra phpMyAdmin: 100000008 er aktuell bruker i eksemplene som følger Når jeg kjører følgende spørring mot databasen: SELECT votes.vote_user_id, votes.vote_time, objects.object_id, objects.object_user, votes.vote_object_id, votes.vote_time FROM `objects` LEFT OUTER JOIN `votes` ON ( objects.object_id = votes.vote_object_id ) LEFT OUTER JOIN `users` ON ( objects.object_user = users.user_id ) WHERE ( votes.vote_user_id = '100000008' AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) >=1000000 ) OR votes.vote_user_id IS NULL ...får jeg opp følgende resultat: Om du ser på votes-tabellen ser du at objectet med ID 100000003 også skulle vært blant resultatene, siden aktuell bruker (100000008) ikke har stemt på objektet. Men som du også ser har en annen bruker (100000000) stemt på objektet med ID 100000003. Om jeg fjerner raden fra votes hvor vote_user_id = 100000000 og vote_object_id = 100000003, kommer også objektet 100000003 opp under resultatene fra spørringen over. Om jeg kjører samme spørringen uten WHERE får jeg opp følgende resultat: Her ser du at objektet med ID 100000003 er stemt på av en annen bruker enn 100000008 (som i denne posten er aktuell bruker). Derfor skriver jeg at spørringen ikke klarer å skille mellom aktuell brukers stemmer og andre brukeres stemmer. Lenke til kommentar
roac Skrevet 19. september 2007 Del Skrevet 19. september 2007 Her ser du at objektet med ID 100000003 er stemt på av en annen bruker enn 100000008 (som i denne posten er aktuell bruker). Derfor skriver jeg at spørringen ikke klarer å skille mellom aktuell brukers stemmer og andre brukeres stemmer. 9528388[/snapback] Prøve å bytte ut LEFT OUTER JOIN `users` ON ( objects.object_user = users.user_id) med LEFT OUTER JOIN `users` ON ( votes.vote_user_id = users.user_id ) Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå