Toon posts:

[SQL/PHP] Random sorteren op prioriteit

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Hi!

Even een vraagje. Ik moet random 1 rij uit een table halen die een veld prioriteit heeft.

Bijvoorbeeld:

ID Naam Prioriteit
-- ---- ----------
2 Lorem 75%
3 Ipsum 30%

Nu moet in bovenstaand voorbeeld de rij met ID = 2 in 75% van de gevallen er uit gehaald worden en die met ID = 3 in 30% van de gevallen.

Ik heb er over nagedacht hoe dit te doen en dacht aan:
SELECT RAND(ID) FROM voorbeeld ORDER BY prioriteit ASC;

Maar dat gaat niet werken natuurlijk. Weet alleen niet hoe ik dit wel moet doen.

Iemand enig idee?

Acties:
  • 0Henk 'm!

  • Terence(x)
  • Registratie: September 2002
  • Laatst online: 07-06 15:24
Kan je niet gewoon je verschillende waardes een range geven.

2 = 1-25
3 = 26-100

Dan gewoon een random 100 doen, en dan 25% van de keren zal ie 2 pakken, en 75% van de keer 3.

Heb het vermoeden dat me oplossing vast niet optimaal is, maar dit is iig hoe ik het zou doen.

Acties:
  • 0Henk 'm!

  • jeroenikke
  • Registratie: Augustus 2003
  • Laatst online: 07-06 12:54
SQL:
1
SELECT * FROM vb WHERE prioriteit > RAND()


Dat geeft 75% record 1 en 30% record 2, maar het is niet volledig random:
Als record 2 gekozen is, is record 1 zeker ook gekozen;

EDIT: Blijkbaar dat de RAND() toch elke keer opnieuw uitgevoerd wordt bij de controle van de WHERE, dus het is toch compleet random, zoals gewenst denk ik.

[Voor 32% gewijzigd door jeroenikke op 01-07-2011 17:40. Reden: RAND() wordt toch herberekend]


Acties:
  • 0Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
70+35 =105. :?

Of mag je ook soms beide rows hebben? Dan is het gewoon triviaal checken op Prio < rand(0,100)
edit:

Maar is de combinatie van rows idd niet random. Maar goed, definieer eerst maar nauwkeuriger wat je wilt.

[Voor 34% gewijzigd door Voutloos op 01-07-2011 17:39]

{signature}


Acties:
  • 0Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 23:10
jeroenikke schreef op vrijdag 01 juli 2011 @ 17:35:
EDIT: Blijkbaar dat de RAND() toch elke keer opnieuw uitgevoerd wordt bij de controle van de WHERE, dus het is toch compleet random, zoals gewenst denk ik.
Kun je zelf bepalen; RAND() neemt een integer parameter (in MySQL, ik neem aan dat je dit gebruikt) als seed. Geef je die dan levert RAND() altijd dezelfde sequence, laat je die weg dan is het een random initialisatie handleiding. :)

//edit
Mea culpa, volgens mij las ik je post verkeerd; maar inderdaad, wordt telkens opnieuw geevalueerd bij het controleren van de WHERE.

[Voor 22% gewijzigd door FragFrog op 01-07-2011 17:55]

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Dank voor de reacties en hulp. Wat ik precies wil is dat in bijvoorbeeld 75% van de keren rij 1 wordt gekozen en 30% van de gevallen rij 2. Ipv procenten is een getal van 1 tot en met 10 een beter voorbeeld.

Rij 1: 9
Rij 2: 3
Rij 3: 5

Dit geeft een prioriteit aan. Wat onmogelijk wordt is om telkens er voor te zorgen dat het in totaal bijv. 10 is (of 100%); Als het bijvoorbeeld in totaal 25 is of 150% dan is 25 = 10 en 150% = 100% in feite.

Ik ben geen topper in uitleggen, sorry hiervoor :o) maar is het wat duidelijker zo?

Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Volgens mij is het een stuk makkelijker als ik gewoon de volgende prioriteiten heb:

1= HIGH
2= MEDIUM
3= LOW

En dan $num = RAND(1,3); Alleen dan anders... ehm.. hoe kan ik ervoor zorgen dat 3 ong. in 60% van de gevallen wordt gekozen, 2 in 25% en 3 in 15% ?

Acties:
  • 0Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 07:35

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Sorteren, cumulatieven berekenen, en de eerste row selecteren waarvoor geldt: cumulatieve_prioriteit > RAND

[Voor 4% gewijzigd door .oisyn op 01-07-2011 18:22]

If I had a dollar for every time I didn't know what was going on, I'd be like: "Why am I always getting all this money?!"


Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Zoiets?

SELECT * FROM nl WHERE prioriteit > 0 ORDER BY RAND() / prioriteit * RAND()

Alleen is rij nu prioriteit = 8 en rij 2 prioriteit = 5 en ik krijg steeds alleen maar rij 1 :(

Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Ah vreemd, op de een of andere manier waren de prioriteit waarden weer op 0 gezet (behalve 1). Die SQL statement lijkt te werken :)

Bedankt allemaal!

Acties:
  • 0Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 07:35

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Euh nee, die statement werkt voor geen meter

Wat ik bedoel is, als je cumulatieven hebt, dan is je tabel zo:

<naam> <prio> <cumulatief>
aap 50% 50%
noot 25% 75%
mies 15% 90%
vis 10% 100%

En dan kun je gewoon een random waarde verzinnen tussen de 0 en de 100 (0 inclusief, 100 exlusief), en dan de eerste rij selecteren waarvoor geldt "cumulatief > random".

Je kunt er dus voor kiezen om die kolom te inserten en dat bij te houden (of een view definieren als je DB dat ondersteunt), het met een subquery op te lossen (langzaam), of gewoon in PHP zelf.

[Voor 20% gewijzigd door .oisyn op 01-07-2011 18:26]

If I had a dollar for every time I didn't know what was going on, I'd be like: "Why am I always getting all this money?!"


Acties:
  • 0Henk 'm!

Anoniem: 265264

Topicstarter
Dank je voor de hele uitleg .oisyn! Omdat dat een beetje te ingewikkeld voor mij werd (ben niet zo een geweldige programmeur) heb ik deze oplossing verzonnen (misschien later handig voor iemand met hetzelfde probleem).

$numbers = array(1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9);
$nrand = rand(0, count($numbers));
$pickednum = $numbers[$nrand];

$res = mysql_query("SELECT * FROM $country WHERE prioriteit >= '$pickednum' ORDER BY RAND() LIMIT 0,1");

Acties:
  • 0Henk 'm!

Anoniem: 149146

[b][message=36330204,noline]heb ik deze oplossing verzonnen (misschien later handig voor iemand met hetzelfde probleem).
Lijkt een prima oplossing voor dit probleem, echter zou ik
WHERE prioriteit >= '$pickednum'
veranderen naar
WHERE prioriteit = '$pickednum'

Op die manier gaat het echt op prioriteit, als je >= doet, is de kans dat getalletje 9 gepakt wordt veel groter dan de prioriteit die je schept in de array.

Acties:
  • 0Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Laatst online: 02:24

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

Anoniem: 265264 schreef op vrijdag 01 juli 2011 @ 18:37:
Dank je voor de hele uitleg .oisyn! Omdat dat een beetje te ingewikkeld voor mij werd (ben niet zo een geweldige programmeur) heb ik deze oplossing verzonnen (misschien later handig voor iemand met hetzelfde probleem).
Leuk voor als het aantal items (of de totale prio (weight)) laag/klein blijft.

[google=weighted random] >> http://www.perlmonks.org/?node_id=242751

code:
1
2
3
4
5
6
7
8
9
$totalweight = get_from_db_scalar('select sum(weight) from items ... where...')
$items = get_from_db('select id, name, weight from items... where ... order by ....')

$r = rand(0, $totalweight)
$i = -1
do {
  $r -= $items[++$i]->weight
} while ($r > 0)
return $items[i]


Rocket science :Y)
Min of meer wat .oisyn zegt, maar dan iets anders :P Zet overigens wel een "order by" in je 'get_from_db'; je moet wel kunnen garanderen dat de volgorde van de items altijd hetzelfde is, anders zou je DB zélf (onbedoeld) een effect op het weight kunnen gaan geven. En zo zul je ook dezelfde predicate (where...) in beide query's moeten hanteren natuurlijk. En ervoor zorgen dat er tussen die 2 queries door niemand nog records gaat inserten :P
Een stukje veiliger is dan ook:

code:
1
2
3
4
5
6
7
8
9
10
11
12
$items = get_from_db('select id, name, weight from items... where ... order by ....')

$totalweight = 0
foreach $items as $item
  $totalweight += $item->weight

$r = rand(0, $totalweight)
$i = -1
do {
  $r -= $items[++$i]->weight
} while ($r > 0)
return $items[i]

[Voor 102% gewijzigd door RobIII op 01-07-2011 20:41]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
Dit moet je inderdaad niet met SQL willen. Dit komt omdat alle rijen van elkaar afhankelijk worden door het gewogen gemiddelde.

Stel je maakt:
a: 10
b: 90

Dan zou je voor a 0-9 moeten reserveren en voor b 10-89. In theorie kan het, maar de complexiteit van de query zal te hoog zijn. Rob3 heeft wat dat betreft een prima alternatief. Dit maakt het een stuk minder complex. Ik zou in deze situatie wel kiezen om op ID te sorteren (in elk geval op een index). Op RAND() sorteren is traag.

Acties:
  • 0Henk 'm!

  • n3ck
  • Registratie: Mei 2002
  • Laatst online: 04-06 05:50
Je kunt toch gewoon zoiets doen:
select * from tabel where prioriteit / (select sum(prioriteit) from tabel) > rand()

of is dat performancetechnisch niet zo handig ivm de grootte..

Acties:
  • 0Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Laatst online: 02:24

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

Probeer het eens en zie of je het gewenste gedrag krijgt ;)

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij

Pagina: 1


Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee