Упорядочить результаты базы данных по байесовскому рейтингу - PullRequest
5 голосов
/ 21 ноября 2011

Я не уверен, что это даже возможно, но мне нужно подтверждение, прежде чем делать это "безобразным" способом:)

Итак, «результаты» - это сообщения в базе данных, которые хранятся так:

  • таблица сообщений, которая содержит все важные вещи, такие как идентификатор, заголовок, содержание
  • мета-таблица постов, которая содержит дополнительные данные постов, такие как рейтинг (this_rating) и количество голосов (this_num_votes). Эти данные хранятся в парах, таблица имеет 3 столбца: идентификатор сообщения / ключ / значение. Это в основном структура таблицы WordPress.

Я хочу получить посты с самым высоким рейтингом, отсортированные по формуле:

br = ((avg_num_votes * avg_rating) + (this_num_votes * this_rating)) / (avg_num_votes + this_num_votes)

который я украл из формы здесь .

avg_num_votes и avg_rating - известные переменные (они обновляются при каждом голосовании), поэтому их не нужно вычислять.

Можно ли это сделать с помощью запроса MySQL? Или мне нужно получить все сообщения и выполнить сортировку с помощью PHP?

Ответы [ 3 ]

2 голосов
/ 21 ноября 2011

Обмен данными по стеку данных:

http://data.stackexchange.com/stackoverflow/s/2137/order-database-results-by-bayesian-rating

SELECT id,title,( AVG(this_num_votes) * AVG(this_rating) + this_num_votes * this_rating )
     / ( AVG(this_num_votes) + this_num_votes ) as br
FROM posts
LEFT JOIN (
SELECT DISTINCT post_id,
(SELECT meta_value FROM postmeta WHERE postmeta.post_id = pm.post_id AND meta_key ='this_num_votes') as this_num_votes,
(SELECT meta_value FROM postmeta WHERE postmeta.post_id = pm.post_id AND meta_key ='this_rating') as this_rating
FROM postmeta pm ) as newmeta ON posts.ID = newmeta.post_id
GROUP BY id,title,this_num_votes,this_rating
ORDER BY br DESC
1 голос
/ 14 августа 2016

Я изменил данные и запрос принятого ответа.

Данные теперь являются образцом данных из 5-звездочной рейтинговой системы.
Функция теперь правильно использует средние значения всех сообщений.

Разница заключается в расчете этих средних значений, вместо PHP они рассчитываются в SQL для целей ответа.

Вы можете увидеть это в действии наSQL Fiddle: http://sqlfiddle.com/#!9/84d8b/2/2


Обновленный запрос

Новая скрипта: http://sqlfiddle.com/#!9/3cdfe/1/2

SET @avg_total_votes  := (SELECT AVG(meta_value) FROM postmeta WHERE meta_key ='this_num_votes');
SET @avg_total_rating := (SELECT AVG(meta_value) FROM postmeta WHERE meta_key ='this_rating');

SELECT  posts.ID,
        posts.title, 
        getmeta_votes.meta_value AS votes,
        getmeta_rating.meta_value AS rating,
        ( ( (@avg_total_votes * @avg_total_rating) + (getmeta_votes.meta_value * getmeta_rating.meta_value) ) / ( @avg_total_votes + getmeta_votes.meta_value ) ) AS factor
FROM posts
LEFT JOIN postmeta AS getmeta_votes  ON posts.ID = getmeta_votes.post_id  AND getmeta_votes.meta_key  = 'this_num_votes'
LEFT JOIN postmeta AS getmeta_rating ON posts.ID = getmeta_rating.post_id AND getmeta_rating.meta_key = 'this_rating'
WHERE NOT getmeta_votes.meta_value = 0 AND NOT getmeta_rating.meta_value = 0
ORDER BY factor DESC;

Я обнаружил, что эта конструкция запроса намного быстреепредыдущий работал в течение 2 часов над набором данных более 2000 записей (более 1 000 000 строк wp_postmeta), пока не завершился.

Этот выполняется за 0,04 с.

1 голос
/ 21 ноября 2011

вот это начало:

// Bayesian Rating Calc
$theItem = $_GET[’id’];
if($theItem) {
// all items votes and ratings
$result = mysql_query(”SELECT AVG(item),AVG(vote) FROM itemvotes WHERE vote>’0′ GROUP BY item”) or die(mysql_error());
$row = mysql_fetch_row($result);
$avg_num_votes = $row[0];
$avg_rating = $row[1];

// this item votes and ratings
$result = mysql_query(”SELECT COUNT(item),AVG(vote) FROM itemvotes WHERE item=’$theItem’ AND vote>’0′”) or die(mysql_error());
$row2 = mysql_fetch_row($result);
$this_num_votes = $row2[0];
$this_rating = $row2[1];

if(!$row OR !$row2)
$br = “_”;
else
$br = number_format( ((($avg_num_votes * $avg_rating) + ($this_num_votes * $this_rating))/($avg_num_votes + $this_num_votes)), 1, ‘.’ );
} // end of if item selected
...