У меня есть база данных MS SQL Server 2008, где я храню места, где подают еду (кафе, рестораны, закусочные и т. Д.). На веб-сайте, связанном с этой базой данных, люди могут оценивать места по шкале от 1 до 3.
На веб-сайте есть страница, на которой люди могут просматривать топ-лист с топ-25 (по рейтингу) мест в определенном городе. Структура базы данных выглядит примерно так (в таблицах хранится больше информации, но есть соответствующая информация):
Places->Votes">
Место находится в городе, и голоса размещаются на месте.
До сих пор я только что подсчитал средний балл за каждое место, где я делю сумму всех голосов за определенное место на количество голосов за это место, что-то вроде этого (псевдокод):
vote_count = total number of votes for the place
vote_sum = total sum of all the votes for the place
vote_score = vote_sum/vote_count
Я также должен обрабатывать деление на ноль, если у места нет голосов. Все это делается внутри хранимой процедуры, которая выбирает другие данные, которые я хочу отобразить в верхнем списке. Вот текущая хранимая процедура, которая выбирает 25 лучших мест с наибольшим количеством голосов:
ALTER PROCEDURE [dbo].[GetTopListByCity]
(
@city_id Int
)
AS
SELECT TOP 25 dbo.Places.place_id,
dbo.Places.city_id,
dbo.Places.place_name,
dbo.Places.place_alias,
dbo.Places.place_street_address,
dbo.Places.place_street_number,
dbo.Places.place_zip_code,
dbo.Cities.city_name,
dbo.Cities.city_alias,
dbo.Places.place_phone,
dbo.Places.place_lat,
dbo.Places.place_lng,
ISNULL(SUM(dbo.Votes.vote_score),0) AS vote_sum,
(SELECT COUNT(*) FROM dbo.Votes WHERE dbo.Votes.place_id = dbo.Places.place_id) AS vote_count,
COALESCE((CONVERT(FLOAT,SUM(dbo.Votes.vote_score))/(CONVERT(FLOAT,(SELECT COUNT(*) FROM dbo.Votes WHERE dbo.Votes.place_id = dbo.Places.place_id)))),0) AS vote_score
FROM dbo.Places INNER JOIN dbo.Cities ON dbo.Places.city_id = dbo.Cities.city_id
LEFT OUTER JOIN dbo.Votes ON dbo.Places.place_id = dbo.Votes.place_id
WHERE dbo.Places.city_id = @city_id
AND dbo.Places.hidden = 0
GROUP BY dbo.Places.place_id,
dbo.Places.city_id,
dbo.Places.place_name,
dbo.Places.place_alias,
dbo.Places.place_street_address,
dbo.Places.place_street_number,
dbo.Places.place_zip_code,
dbo.Cities.city_name,
dbo.Cities.city_alias,
dbo.Places.place_phone,
dbo.Places.place_lat,
dbo.Places.place_lng
ORDER BY vote_score DESC, vote_count DESC, place_name ASC
RETURN
Как вы можете видеть, это приносит больше, чем просто голосование - мне нужны данные о месте, городе, в котором он находится, и так далее. Это хорошо работает, но есть одна большая проблема: подсчет голосов слишком прост, потому что он не учитывает количество голосов. При использовании простого метода подсчета место, имеющее один голос с результатом 3, окажется в списке выше, чем место с четырнадцатью голосами с результатом 3 и одним голосом с результатом 2:
3/1 = 3
(14*3 + 1*2) = 44/15 = 2.933333333333
Чтобы исправить это, я пытался использовать некую форму средневзвешенного / взвешенного индекса. Я нашел пример истинной байесовской оценки, которая выглядит многообещающей. Это выглядит так:
weighted rating (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C
where:
R = average for the place (mean) = (Rating)
v = number of votes for the place = (votes)
m = minimum number of votes required to be listed in the Top 25 (unsure how many, but somewhere between 2-5 seems realistic)
C = the mean vote across the whole database
Проблемы начинаются, когда я пытаюсь реализовать этот взвешенный рейтинг в хранимой процедуре - он быстро усложняется, и я запутываюсь в скобках и теряю представление о том, что делает хранимая процедура.
Теперь мне нужна помощь с двумя вопросами:
Подходит ли этот метод для расчета взвешенного индекса для моего сайта?
Как это (или другой подходящий метод вычисления) будет выглядеть при реализации в хранимой процедуре?