Использование хранимых процедур для социального ранжирования с MySQL - PullRequest
0 голосов
/ 08 июня 2011

Я работаю над механизмом социального ранжирования для предметов в базе данных. Я думаю, что у меня есть логика решена (в любом случае, в моей голове), и сейчас я работаю над реализацией. Я надеюсь либо на «Хорошо, это выглядит правильно», либо, если я полностью на неправильном пути, «Вы идиот, удалите». В зависимости от того, что применимо.

По сути, у меня есть несколько таблиц, настроенных следующим образом (намного проще, [...] указывает на другие столбцы, которые не показаны)

Users
id (int, primary)
email (varchar 64)
[...]

Items
id (int, primary)
URI (varchar 128)
date (timestamp)
[...]
rank (int)

Votes
id (int, primary)
user_id
item_id

Теперь цель состоит в том, чтобы, когда пользователь вошел в систему и «проголосовал» за определенный элемент, он добавляет строку в таблицу «Голосования», но также автоматически обновляет ранг элемента за кулисами, используя (я бы предположил) хранимая процедура, основанная на алгоритме, аналогичном другим сайтам социального ранжирования, таким как алгоритмы «горячей» и «верхней» сортировки reddit.

Мое собственное предположение / решение проблемы заключается в том, чтобы сделать что-то вроде следующего:

DELIMITER //
DROP PROCEDURE IF EXISTS updateRank//
CREATE PROCEDURE updateRank(IN itemId INT())
COMMENT 'Generates a new rank and updates the Items table'
BEGIN
   DECLARE  vote_sum,published_date INT DEFAULT 0;

   SELECT COUNT(id) INTO vote_sum,
   FROM Votes
   WHERE item_id = itemId;

   SELECT date INTO published_date
   FROM Items
   WHERE id = itemId;

   SET @o  = log(max(abs(vote_sum), 1), 10);
   SET @ts = published_date - 1307557809;
   SET @r  = round(@0 + 1 * @ts / 45000, 7);

   UPDATE Items
   SET rank = @r
   WHERE id = itemId;
END;
//
delimiter ;

Затем в моем запросе PDO добавьте следующее:

INSERT INTO Votes (user_id,item_id) values (:userid,:itemid ) CALL updateRank(:itemid);

Если это выглядит отсталым, то это потому, что я довольно зелен от хранимых процедур (в лучшем случае), и полный нуб (в худшем случае).

Мои вопросы в основном: есть ли лучший способ сделать это? Мой синтаксис полностью на обед? Можно ли это сделать негласно (то есть, не вызывая процедуру в моем запросе)? И стоит ли мне использовать InnoDB или MyISAM в качестве основного движка? У меня есть причины хотеть использовать InnoDB для этого конкретного проекта (по крайней мере, несколько таблиц), однако все, что я читаю, говорит мне никогда не использовать InnoDB ... что минусы перевешивают плюсы.

EDIT

Рекомендуется заменить

SELECT COUNT(id) INTO vote_sum
FROM Votes
WHERE item_id = itemId;

со следующим

SELECT vote_count INTO vote_sum
FROM Votes
WHERE item_id = itemId;

Это имеет больше смысла? Затем увеличьте поле voice_count вместо простого обновления счета?

1 Ответ

1 голос
/ 09 июня 2011

Не знаю, знаете ли вы об этом, но есть более простой способ,

, просто добавьте Score и VoteCount к вашему предмету-сущности,

new vote:
Score = (Score*VoteCount+NewVote) / (VoteCount + 1) 
VoteCount++;

Вы проиграли трекиз которых использует, проголосовал за какие элементы, но которые могут быть добавлены в качестве своей собственной сущности.

Это легкая работа для вашего mysql, так как нет счета.

// edit

items:
  ItemID
  ...
  VoteSum
  VoteCount
  VoteAvg (computed field, Sum/Count, index to sort fast for "five-stars")

Track of votes - to avoid double-votes and let user delete their vote.
votes:
  UserID (PK)
  ItemID (PK)
  Rating

По голосованию:

 insert into votes(...
 update item set VoceCount=VotCount+1,VoteSum=VoteSum+X

С уважением,

// t

...