4

私は食べ物を提供する場所(カフェ、レストラン、ダイナーなど)を保管するMS SQL Server 2008データベースを持っています。このデータベースに接続されているWebサイトでは、1から3までの位置を評価することができます。ストアドプロシージャの加重(ベイジアン)平均スコア/インデックスを計算しますか?

Webサイトには、トップ25のリストが表示されるページがあります。特定の都市。データベース構造は次のようになります(テーブルに詳細が格納されていますが、関連する情報があります)。 Database structure: Cities->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 

場所に投票がない場合は、ゼロで割り切る必要もあります。これはストアドプロシージャ内で実行され、トップリストに表示する他のデータを取得します。私は、場所に関するデータを必要とする、市はそれはに位置しています -

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 

あなたはそれだけで投票スコアよりもフェッチ見ることができるように:ここでは、最も高い投票スコアがトップ25の場所を取得し、現在のストアドプロシージャがあります等々。これはうまくいきますが、1つの大きな問題があります。投票数は、投票数を考慮しないため、単純すぎます。修正するには

3/1 = 3 
(14*3 + 1*2) = 44/15 = 2.933333333333 

:簡単な計算方法ではスコア3で一票を持っている場所はスコア2でスコア3と一票で14票を持っている場所よりも、リストの上位になってしまいますこれは、私はいくつかの形式の加重平均/加重インデックスを使用して調べてきました。私は有望と思われる真のベイジアン推定の例を見つけました。それは次のようになります。私は、ストアドプロシージャでこの加重評価を実施しようとすると、

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 

問題を開始 - それはすぐに複雑になると、私は、ストアドプロシージャが何の括弧と緩いトラックに絡ま。

今、私は2つの質問をいくつかの助けを必要とする:

が、これは私のサイトのための加重指数を計算するための適切な方法ですか?

ストアドプロシージャに実装した場合、これ(または別の適切な計算方法)はどのように見えますか?

答えて

1

計算に問題はありません。しかし、私はあなたが何度も同じことをしているのを見ることができます。私の提案は、集約を1か所で行うのに役立ち、その選択は非常に簡単です。

;WITH CTE 
(
    SELECT 
     SUM(dbo.Votes.vote_score) AS SumOfVoteScore, 
     COUNT(*) AS CountOfVotes, 
     Votes.place_id 
    FROM 
     Votes 
    GROUP BY 
     Votes.place_id 
) 
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(CTE.SumOfVoteScore,0) AS vote_sum, 
    CTE.CountOfVotes AS vote_count, 
    COALESCE((CONVERT(FLOAT,CTE.SumOfVoteScore)/ 
    (CONVERT(FLOAT,CTE.CountOfVotes))),0) AS vote_score 

FROM dbo.Places INNER JOIN dbo.Cities ON dbo.Places.city_id = dbo.Cities.city_id 
LEFT JOIN CTE ON dbo.Places.place_id=CTE.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 

CTE関数は、計算を再利用するのに役立ちます。したがって、SUM(vote_score)SELECT COUNT(*) FROM Votes WHERE...倍を使用する必要はありません。だから、あなたが計算を選択している時には、それは非常に簡単です。

私はあなたがCTEの表の列を定義する必要はありません

編集これは

に役立ちます願っています。このCTE (SumOfVoteScore, CountOfVotes, place_id) ASはこのCTE ASと同じくらいうまく動作します。再帰的cteを使用する場合は、列を定義する必要があります。あなたは他の部分とunionです。参照hereについては

hereあなたはCTE機能

0

おかげアリオンに関するいくつかの情報を見つけます!

私はCTEのラインに沿って何かを探していましたが、私が探していたことは分かりませんでした。新しいことを学ぶことはいつもうれしいことです。私はCTEを他のプロジェクトで活用することを知っています。

ALTER PROCEDURE dbo.GetTopListByCityCTE 
    (
    @city_id Int 
    ) 
AS 

;WITH CTE (SumOfVoteScore, CountOfVotes, place_id) AS 
(
    SELECT 
     SUM(dbo.Votes.vote_score) AS SumOfVoteScore, 
     COUNT(*) AS CountOfVotes, 
     Votes.place_id 
    FROM 
     Votes 
    GROUP BY 
     Votes.place_id 

) 

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(CTE.SumOfVoteScore,0) AS vote_sum, 
    CTE.CountOfVotes AS vote_count, 
    COALESCE((CONVERT(FLOAT,CTE.SumOfVoteScore)/ 
    (CONVERT(FLOAT,CTE.CountOfVotes))),0) AS vote_score 

FROM dbo.Places INNER JOIN dbo.Cities ON dbo.Places.city_id = dbo.Cities.city_id 
LEFT JOIN CTE ON dbo.Places.place_id = CTE.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, 
     CTE.SumOfVoteScore, 
     CTE.CountOfVotes 
ORDER BY vote_score DESC, vote_count DESC, place_name ASC 

簡単なチェックは、それが前のコードと同じ結果を返しますが、それは読んで従うことがはるかに簡単だし、うまくいけばはるかに効率ことが明らかになった:私は私のストアドプロシージャで、あなたのCTEを実装する場合、私はこのコードを取得します。

ここで、古い(単純な)評価計算方法を投票数を考慮した新しい計算方法に置き換える実験をいくつか行う必要があります。

+0

あなたのお役に立てれば幸いです。あなたは私の答えでうまくいけばそれを受け入れることを検討するかもしれません? – Arion

+0

また、私の答えが表示された場合は – Arion

+0

を更新しました。解決策として回答をマークする前に、CTEが元の問題を解決するのに役立つ(より複雑なスコアインデックスを実装する)ことを確認したいだけです。私は今、新しいストアドプロシージャに取り組んでいます... – tkahn

0

わかりました - ので、ここで私が思い付いたストアドプロシージャです:計算に使用されていない@AverageNumberOfVotesという変数があります

ALTER PROCEDURE dbo.GetTopListByCityCTE 
    (
    @city_id Int 
    ) 
AS 

DECLARE @MinimumNumber float; 
DECLARE @TotalNumberOfVotes int; 
DECLARE @AverageRating float; 
DECLARE @AverageNumberOfVotes float; 

/* MINIMUM NUMBER */ 
SET @MinimumNumber = 1; 

/* TOTAL NUMBER OF VOTES -- ALL PLACES */ 
SET @TotalNumberOfVotes = (
    SELECT COUNT(*) FROM Votes 
); 

/* AVERAGE RATING -- ALL PLACES */ 
SET @AverageRating = (
    SELECT 
     CONVERT(FLOAT,(SUM(dbo.Votes.vote_score)))/CONVERT(FLOAT,COUNT(*)) AS AverageRating 
    FROM 
     Votes); 

/* AVERAGE NUMBER OF VOTES -- ALL PLACES */ 
/* CURRENTLY NOT USED IN INDEX - KEPT FOR REFERENCE */ 
SET @AverageNumberOfVotes = (
    SELECT AVG(CONVERT(FLOAT,NumberOfVotes)) FROM (SELECT COUNT(*) AS NumberOfVotes FROM Votes GROUP BY place_id) AS AverageNumberOfVotes 

); 
/* SUM OF ALL VOTE SCORES AND COUNT OF ALL VOTES -- INDIVIDUAL PLACES */ 
WITH CTE AS (
    SELECT 
     CONVERT(FLOAT, SUM(dbo.Votes.vote_score)) AS SumVotesForPlace, 
     CONVERT(FLOAT, COUNT(*)) AS CountVotesForPlace, 
     Votes.place_id 
    FROM 
     Votes 
    GROUP BY 
     Votes.place_id 
) 

SELECT 
    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(CTE.SumVotesForPlace,0) AS vote_sum, 
    ISNULL(CTE.CountVotesForPlace,0) AS vote_count, 
    COALESCE((CTE.SumVotesForPlace/ 
    CTE.CountVotesForPlace),0) AS vote_score, 
    ISNULL((CTE.CountVotesForPlace/(CTE.CountVotesForPlace + @MinimumNumber)) * (COALESCE((CTE.SumVotesForPlace/CTE.CountVotesForPlace),0)) + (@MinimumNumber/(CTE.CountVotesForPlace + @MinimumNumber)) * @AverageRating,0) AS WeightedIndex 

FROM dbo.Places INNER JOIN dbo.Cities ON dbo.Places.city_id = dbo.Cities.city_id 
LEFT JOIN CTE ON dbo.Places.place_id = CTE.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, 
     CTE.SumVotesForPlace, 
     CTE.CountVotesForPlace 
ORDER BY WeightedIndex DESC, vote_count DESC, place_name ASC 

が、私はそれが必要になることができた場合には、参照のためにそこにそれを保持。

データとの比較これまでに得た結果とは若干異なる結果が得られましたが、革命はなく、必要なものではありません。

vote_sum  vote_count vote_score   WeightedIndex 
1110   409   2,71393643031785 2,7140960047496 
807    310   2,60322580645161 2,60449697749787 
38    15   2,53333333333333 2,56708633093525 
25    10   2,5     2,55442722744881 
2    1   2     2,55188848920863 
2    1   2     2,55188848920863 
2    1   2     2,55188848920863 
2    1   2     2,55188848920863 
2    1   2     2,55188848920863 
2    1   2     2,55188848920863 

ここでの問題は一票があります場所ということのようだとスコアが2である、加重インデックスは2,55188848920863次のようになります?私は上記のSPを実行すると、ここで返された上位10行がありますか

このインデックスを計算するための公式はIMDB(http://www.imdb.com/chart/top)から取られています。私は何か間違ったことをしたか、私のデータベースにあるデータはデータに匹敵しません投票の規模)はIMDBにありますか?

編集

それは私のためにうまく機能して私は、この機能を調整することができます方法はありますか?より優れた機能やアプローチがありますか?私はまだストアドプロシージャで計算を行う必要があります。

+0

私はこの式(IMDBが "真のベイズ推定"と呼んでいる)が私が必要としているものであるかどうかは分かりませんし、批判もありました:http://en.wikipedia.org/wiki/Bayes_estimator#Practical_example_of_misapplication_of_Bayes_estimators – tkahn