Kom ihåg mig?
Home Menu

Menu


MySQL, random + biased/weighted mot äldsta?

 
Ämnesverktyg Visningsalternativ
Oläst 2014-03-13, 08:45 #1
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
Standard MySQL, random + biased/weighted mot äldsta?

Skulle behöva en skön & enkel query som väljer ut random rader i databasen men "väger" mer mot dom äldre raderna då det är viktigt att dom äldsta raderna inte "glöms" bort.

Tabellen innehåller fler kolumner än det jag nämner, men det är dom kolumnerna jag har att använda för queryn, tyvärr. Har googlat på biased & weighted queries i MySQL men dom flesta jag hittat använder en tabell med "score", "multiplier" osv för att använda som "tyngd" i queryn, någon sådan har jag alltså inte.

Kolumnerna som skall användas för detta är:

Kod:
CREATE TABLE `TestTable` (
  `PostID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `PostTitle` varchar(250) DEFAULT NULL,
  `PostDate` datetime DEFAULT NULL,
  PRIMARY KEY (`PostID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Prestandaproblemen med en random query är inget problem i mitt fall, tabellen innehåller inte tillräckligt med rader för att vara ett problem.

Skulle vilja få ut 10st random rader från hela tabellen men med mer vikt mot dom äldre, några förslag på en smidig lösning?
JesperA är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:00 #2
Kimppas avatar
Kimppa Kimppa är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jul 2010
Inlägg: 793
Kimppa Kimppa är inte uppkopplad
Mycket flitig postare
Kimppas avatar
 
Reg.datum: Jul 2010
Inlägg: 793
En enklare lösning skulle väl kunna vara att göra följande i ett programmeringsspråk:

- Räkna antalet rows i tabellen.
- Slumpa tal mellan 0 och antalet rows i tabellen.
- Skriv ut och sortera efter "datum DESC" så de äldsta syns först.

Vet tyvärr inte om det går att göra i SQL direkt (kanske går).
Kimppa är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:15 #3
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
Citat:
Ursprungligen postat av Kimppa Visa inlägg
En enklare lösning skulle väl kunna vara att göra följande i ett programmeringsspråk:

- Räkna antalet rows i tabellen.
- Slumpa tal mellan 0 och antalet rows i tabellen.
- Skriv ut och sortera efter "datum DESC" så de äldsta syns först.

Vet tyvärr inte om det går att göra i SQL direkt (kanske går).
Tyvärr, det skulle inte ge viktad/biased output, det är i princip bara en helt vanlig "ORDER BY rand(), PostDate ASC" i MySQL, således har varenda rad i databasen lika stor chans att visas.
JesperA är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:25 #4
Johnny Viking Johnny Viking är inte uppkopplad
Medlem
 
Reg.datum: Aug 2011
Inlägg: 273
Johnny Viking Johnny Viking är inte uppkopplad
Medlem
 
Reg.datum: Aug 2011
Inlägg: 273
I väntan på en SQL-expert som kan skapa en funktion som löser det åt dig så skulle du ju kunna splitta upp det hela i t.ex 3 queries som du mergar i efterhand. T.ex query 1 med "äldre än X", och 2 "äldre än x" osv. På så sätt styr du själv på ett ungefär det förväntade resultatet.
Johnny Viking är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:25 #5
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
Du gör nog bäst i att köra viktningen i scriptet. Det blir mer flexibelt och när du har så få rader så kan du som du säger göra lite som du själv vill med datan. Alternativt kan du ju bara lägga in ett extra viktningsfält i databasen som du uppdaterar en gång per dygn eller liknande beroende på hur ofta din tabell ändras.
__________________
Full-stack developer, free for smaller assignments
tartareandesire är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:30 #6
HenrikAI HenrikAI är inte uppkopplad
Flitig postare
 
Reg.datum: Nov 2004
Inlägg: 331
HenrikAI HenrikAI är inte uppkopplad
Flitig postare
 
Reg.datum: Nov 2004
Inlägg: 331
Något i stil med detta, kanske:

Kod:
SELECT col1, col2, ..., -RAND()*UNIX_TIMESTAMP(PostDate) AS random_value
FROM TestTable
ORDER BY random_value ASC
Vet inte hur bra det är rent prestandamässigt dock.

Annars kan du lösa det med lite kod i ditt favoritspråk. Ta ut ett slumptal, t.ex. mellan 2000 och 2013 (eller vad du nu har för årtal på raderna i databasen), och kör något i stil med:

Kod:
SELECT col1, col2, ...
FROM TestTable
WHERE YEAR(PostDate) <= $slumptal
ORDER BY RAND()
HenrikAI är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 09:51 #7
Nerix Nerix är inte uppkopplad
Flitig postare
 
Reg.datum: Oct 2010
Inlägg: 398
Nerix Nerix är inte uppkopplad
Flitig postare
 
Reg.datum: Oct 2010
Inlägg: 398
http://stackoverflow.com/questions/1...-probabilities
Nerix är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 15:47 #8
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
JesperA JesperA är inte uppkopplad
Medlem
 
Reg.datum: Jul 2008
Inlägg: 214
Tack för svaren


Citat:
Ursprungligen postat av Johnny Viking Visa inlägg
I väntan på en SQL-expert som kan skapa en funktion som löser det åt dig så skulle du ju kunna splitta upp det hela i t.ex 3 queries som du mergar i efterhand. T.ex query 1 med "äldre än X", och 2 "äldre än x" osv. På så sätt styr du själv på ett ungefär det förväntade resultatet.
Jao det skulle nog gå rätt bra ja, om jag tänker rätt dvs. Går ju lösa enkelt på min 2 olika sätt i MySQL, antingen med subqueries eller med UNION.

Tex om jag gör 3st "brytpunkter" där jag väljer ut tex 100st rader av dom 33% äldsta raderna, 50st rader av 33% av dom mellersta raderna och 25st av dom 33% senaste raderna i databasen och därefter gör ett random urval på dom sammanställda raderna. Då är ju oddsen större att rand() tar någon av dom 100 äldsta än av dom 25st senaste, skall testa.



Citat:
Ursprungligen postat av tartareandesire Visa inlägg
Du gör nog bäst i att köra viktningen i scriptet. Det blir mer flexibelt och när du har så få rader så kan du som du säger göra lite som du själv vill med datan. Alternativt kan du ju bara lägga in ett extra viktningsfält i databasen som du uppdaterar en gång per dygn eller liknande beroende på hur ofta din tabell ändras.
Skulle helst inte vilja ha ett viktningsfält då det ökar komplexiten ett redan komplext script & vill helst undvika småupdates så mycket det går då jag kör databasen på ett par SSD:er. Skulle iofs kunna skapa en dedikerad MEMORY tabell just för viktningen så är de ju inget problem egentligen. Sliter ju inte överdrivet extra att göra en update på alla rader en gång om dagen men ändå, varje liten grej för att förlänga livslängden på SSD:erna



Citat:
Ursprungligen postat av HenrikAI Visa inlägg
Något i stil med detta, kanske:

Kod:
SELECT col1, col2, ..., -RAND()*UNIX_TIMESTAMP(PostDate) AS random_value
FROM TestTable
ORDER BY random_value ASC
Vet inte hur bra det är rent prestandamässigt dock.

Annars kan du lösa det med lite kod i ditt favoritspråk. Ta ut ett slumptal, t.ex. mellan 2000 och 2013 (eller vad du nu har för årtal på raderna i databasen), och kör något i stil med:

Kod:
SELECT col1, col2, ...
FROM TestTable
WHERE YEAR(PostDate) <= $slumptal
ORDER BY RAND()
Hmm, första exemplet vet jag inte riktigt hur det fungerar, ser inte huruvida den lägger extra vikt på äldre eller inte, skall testa.

Exempel 2 skulle nog inte fungera som tänkt för om jag slumpar ett årtal så kommer den bara hämta rader äldre/nyare än slumptalet, alltså alla 10 av dom raderna jag vill ha, men jag vill ha så att 2st av dom 10 skulle kunna vara bland dom 5 senaste raderna i tabellen, 2st i mitten av tabellen och 6st mot dom allra äldsta i tabellen.

Citat:
Ursprungligen postat av Nerix Visa inlägg
Tack men tror inte att WITH fungerar eller har någon motsvarighet i MySQL och exemplet har ett viktningsfält vilket jag helst skulle vilja slippa om det är möjligt.
JesperA är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 16:10 #9
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
En enkel lösning:
- Räkna antalet rader (select count(*) om du använder myisam, via cachad räknare om du använder innodb)
- I ditt script vikta dina slumpnummer (Google: weighted random generator eller något i den stilen om du behöver en färdig algoritm)
- Kör en select med order by PostDate och LIMIT på dina slumpnummer (Kontrollera huruvida du kan köra unions/subquerys och ändå använda index, med vanilla MySQL bör det nog vara bättre med en query per rad)
Clarence är inte uppkopplad   Svara med citatSvara med citat
Oläst 2014-03-13, 18:02 #10
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
Citat:
Ursprungligen postat av JesperA Visa inlägg
Skulle helst inte vilja ha ett viktningsfält då det ökar komplexiten ett redan komplext script & vill helst undvika småupdates så mycket det går då jag kör databasen på ett par SSD:er. Skulle iofs kunna skapa en dedikerad MEMORY tabell just för viktningen så är de ju inget problem egentligen. Sliter ju inte överdrivet extra att göra en update på alla rader en gång om dagen men ändå, varje liten grej för att förlänga livslängden på SSD:erna
Jag gav ju två förslag i ett, det första var att bara köra viktningen direkt i scriptet, det är definitivt enklast. Varför göra det krångligt för sig i onödan?
__________________
Full-stack developer, free for smaller assignments
tartareandesire är inte uppkopplad   Svara med citatSvara med citat
Svara


Aktiva användare som för närvarande tittar på det här ämnet: 1 (0 medlemmar och 1 gäster)
 

Regler för att posta
Du får inte posta nya ämnen
Du får inte posta svar
Du får inte posta bifogade filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är GMT +2. Klockan är nu 20:36.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson
 
Copyright © 2017