Я создаю рекламную систему, которая чаще показывает объявления, предлагающие самую высокую цену.
Вот пример структуры таблицы, которую я использую, но упрощенной …
+----+----------+------------------------+----------------------+-----+
| id | name | image | destination | bid |
+----+----------+------------------------+----------------------+-----+
| 1 | abc, co | htt.../blah | htt...djkd.com/ | 3 |
+----+----------+------------------------+----------------------+-----+
| 2 | facebook | htt.../blah | htt...djkd.com/ | 200 |
+----+----------+------------------------+----------------------+-----+
| 3 | google | htt.../blah | htt...djkd.com/ | 78 |
+----+----------+------------------------+----------------------+-----+
Сейчас, прямо сейчас я выбираю значения из базы данных, а затем вставляю их в массив и выбираю случайным образом, как показано ниже:
$ads_array = [];
$ads = Ad::where("active", "=", 1)->orderBy("price", "DESC");
if ($ads->count() > 0) {
$current = 0;
foreach ($ads->get() as $ad) {
for ($i = 0; $i <= ($ad->price == 0 ? 1 : $ad->price); $i++) {
$ads_array[$current] = $ad->id;
$current++;
}
}
$random = rand(0,$current-1);
$ad = Ad::where("id", "=", $ads_array[$random])->first();
...
}
Итак, по сути, это то, что он вставляет идентификатор объявления в массив 1*$bid
раз. К сожалению, это очень неэффективно (по очевидным причинам), но это был лучший способ сделать это.
Есть ли лучший способ выбрать случайное объявление из моей базы данных; в то же время давая более высокую цену более высокую вероятность быть показанным?
Похоже, что это может помочь (но вся заслуга в этом парень в комментариях)
SELECT ads.*
FROM ads
ORDER BY -log(1.0 - rand()) / ads.bid
LIMIT 1
Скрипт для проверки этого:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;', 'test', 'test');$times = array();
// repeat a lot to have real values
for ($i = 0; $i < 10000; $i++) {
$stmt = $pdo->query('SELECT ads.* FROM ads ORDER BY -log(1.0 - rand()) / bid LIMIT 1');
$bid = $stmt->fetch()['bid'];
if (isset($times[$bid])) {
$times[$bid] += 1;
} else {
$times[$bid] = 1;
}
}
// echoes the number of times one bid is represented
var_dump($times);
Цифры, которые приходят ко мне из этого теста, довольно хороши:
// key is the bid, value is the number of times this bid is represented
array (size=3)
200 => int 7106
78 => int 2772
3 => int 122
Дальнейшая ссылка на математическое объяснение
Многие важные одномерные распределения могут быть выбраны путем инверсии с использованием простых выражений в замкнутой форме. Некоторые из наиболее полезных из них перечислены здесь.
Пример 4.1 (Экспоненциальное распределение). Стандартное экспоненциальное распределение имеет плотность f (x) = e − x на x> 0. Если X имеет это распределение, то E (X) = 1, и мы пишем X ∼ Exp (1). Кумулятивная функция распределения: F (x) = P (X x) = 1-e-x, причем F-1 (u) = -log (1-u). Поэтому, принимая X = — log (1 — U) для U ∼ U (0, 1), генерирует стандартные экспоненциальные случайные величины. Дополнительная инверсия использует X = — log (U).
Экспоненциальное распределение со скоростью λ> 0 (и средним θ = 1 / λ) имеет PDF λexp (−λx) для 0 x < ∞. Если X имеет это распределение, то мы пишем X ∼ Exp (1) / λ или, что эквивалентно, X ∼ θExp (1), в зависимости от того, сформулирована ли задача более естественно в терминах скорости λ или среднего θ. Мы можем сгенерировать X, взяв X = — log (1 — U) / λ.
приходящий из http://statweb.stanford.edu/~owen/mc/Ch-nonunifrng.pdf
Других решений пока нет …