Ruby on rails RubyonRails-计算排名

Ruby on rails RubyonRails-计算排名,ruby-on-rails,activeadmin,Ruby On Rails,Activeadmin,在轨道4上。我正在构建一个竞赛应用程序。我有三个与此用例相关的表: 提交-属性包括: :竞赛年-创建提交的年份 :类别\u id-分配提交内容的竞赛类别 :赛区id-分配参赛作品的竞赛赛区(共五个) 分数-属性包括: :用户id-评分法官的id :提交id-分数绑定到的提交id :总分-评委提供的整数作为参赛分数;通常十有八九 评委-属性包括: :用户id-法官的用户id :类别\u id-分配给评委评分的类别 :分区\u id-分配给法官评分的分区 一次提交可以有多个分数(因为有多

在轨道4上。我正在构建一个竞赛应用程序。我有三个与此用例相关的表:

提交-属性包括:

  • :竞赛年
    -创建提交的年份
  • :类别\u id
    -分配提交内容的竞赛类别
  • :赛区id
    -分配参赛作品的竞赛赛区(共五个)
分数-属性包括:

  • :用户id
    -评分法官的id
  • :提交id
    -分数绑定到的提交id
  • :总分
    -评委提供的整数作为参赛分数;通常十有八九
评委-属性包括:

  • :用户id
    -法官的用户id
  • :类别\u id
    -分配给评委评分的类别
  • :分区\u id
    -分配给法官评分的分区
一次提交可以有多个分数(因为有多个评委被分配到其类别/部门)

应用程序必须做的第一件事是从各个评委给它的所有孩子分数中找出提交的综合最终分数。我使用submission.rb中的计算进行此操作:

  def calculate_final_score
    self.scores.average(:total_score)
  end
所以基本上,它会找到提交的所有孩子的分数,然后取这些分数的平均值来找到最终的分数。此最终分数不是提交表的更新属性,它是方法计算结果

现在,我的问题就在这里。我需要找到一种方法,通过比较上述最终分数计算结果,计算出与其他具有相同
:contest\u year
:category\u id
:division\u id
的参赛作品相比,该作品的排名。当提交的最终分数相同(平局)时,排名系统必须给出相同的排名

tl;博士,我需要这样的排名行为(示例提交表):


此排名信息将放在我的Active Admin submissions索引表页面中(也是CSV表输出的一部分)。

我对Rails(或Ruby)不太熟悉。但在Django应用程序中,我们遇到了类似的情况,需要根据一些计算数据计算秩。当我们使用PostgreSQL作为DB后端时,我们使用Postges的窗口函数(,)进行排名计算。下面是一个示例PostgresSQL查询,它可以生成问题所需的结果

sql_query = %Q{SELECT 
   *, dense_rank() OVER (
       PARTITION BY contest_year, category_id, division_id
       ORDER BY final_score DESC
   )
FROM (
    SELECT 
        Submissions.id, 
        Submission.contest_year AS contest_year, 
        Submission.category_id AS category_id, 
        Submission.division_id AS division_id, 
        AVG(Scores.total_score) AS final_score
    FROM Submissions 
        INNER JOIN Scores ON (Submissions.id = Scores.submission_id)
    GROUP BY 
        Submissions.id, 
        Submission.contest_year, 
        Submission.category_id, 
        Submission.division_id
) AS FinalScores}

submissions_by_rank = Submission.find_by_sql(sql_query)

注意:如果要以特定方式对结果排序,则需要在查询中添加
orderby
子句。

在Ruby中,假设已经设置了
\calculate\u final\u score
方法:

class Submission < ActiveRecord::Base
  def self.rank_all_submissions_by_group
    keys = [ :contest_year, :category_id, :division_id ]
    submission_groups = Submission.all.group_by do |sub|
      values = keys.map { |k| sub.send(key) }
      Hash[key.zip(values)]
    end

    return ranked_submissions_by_group = submission_groups.map do |group, submissions|
      group[:ranked_submissions] = submissions.map do |s|
        [s, s.calculate_final_score]
      end.sort_by(&:last)
    end
  end
end
类提交
将返回的数据如下所示:

[
  {
    :contest_year => 2013,
    :division_id => 1,
    :category_id => 1,
    :ranked_submissions => [
      [ <Submission>, 10 ],
      [ <Submission>, 10 ],
      [ <Submission>, 8  ],
      [ <Submission>, 6  ],
      [ <Submission>, 5  ],
    ],
  },
  {
    :contest_year => 2013,
    :division_id => 2,
    :category_id => 1,
    :ranked_submissions => [
      [ <Submission>, 8 ],
    ],
  },
  {
    :contest_year => 2014,
    :division_id => 1,
    :category_id => 2,
    :ranked_submissions => [
      [ <Submission>, 9 ],
      [ <Submission>, 7 ],
    ],
  },
]
[
{
:竞赛年=>2013年,
:分区id=>1,
:category_id=>1,
:排名的提交=>[
[ , 10 ],
[ , 10 ],
[ , 8  ],
[ , 6  ],
[ , 5  ],
],
},
{
:竞赛年=>2013年,
:分区id=>2,
:category_id=>1,
:排名的提交=>[
[ , 8 ],
],
},
{
:竞赛年=>2014年,
:分区id=>1,
:category_id=>2,
:排名的提交=>[
[ , 9 ],
[ , 7 ],
],
},
]
不过,它的性能不会很好,因为它只会一直浏览所有提交的内容,生成大量副本(我想是吧?),而且我没有使用正确的排序算法

如果您有任何问题/顾虑,请告诉我,我可以更新我的答案

其他帮助

如果你正在寻找一种在Ruby中运行原始查询的方法,请考虑这个简单的例子:

full_submissions_table_as_hash = ActiveRecord::Base.connection.select_all(<<-mysql)
  SELECT *
  FROM #{Submissions.table_name}
mysql
full\u submissions\u table\u as\u hash=ActiveRecord::Base.connection。选择所有提交(Submission.rank\u all\u submissions\u by\u group
结束
结束

如果分数低于某个阈值,比如说100个条目,我会用ruby进行计算。有趣的是,你能在回答或类似示例的链接中进一步阐述吗?我只知道基本的ruby计算。我使用SQLite3进行开发,最终将使用PostgreSQL进行生产。我遇到了一些问题了解如何将此语句放置/格式化为RoR模型方法。我尝试的任何方法都不起作用(至少对于开发)。也许更熟悉Ruby的人可以跳到这里,我如何格式化此语句,以便将其放置在我的提交模型中?如果我不使用PostgreSQL进行开发,此语句在开发中是否有效?SQLite没有此处所述的窗口函数:(.我们在应用程序中对prod和dev都使用postgres!我很害怕!嗯,所以我想现在真的没有办法在开发中测试这一点(现在不想从SQLite切换).我想奖励奖金,但是…我现在无法知道这是否有效!如果有人至少能插手告诉我如何为模型中的方法设置格式(而不是像现在这样的原始查询),我将不胜感激!也许稍后我会用Postgresql作为数据库制作一个快速测试应用程序,看看这是否有效。嘿@Rachel9494,你可以使用rails的find_by_sql方法进行此查询..例如submissions=Submission.find_by_sql()…作为参考,请看这里:哦,天哪!!这看起来很有用!一些问题,其中一个有点愚蠢:如何插入这个int
full_submissions_table_as_hash = ActiveRecord::Base.connection.select_all(<<-mysql)
  SELECT *
  FROM #{Submissions.table_name}
mysql
# assuming routes are properly set up to actions in HomeController
class HomeController < ActionController::Base
  def ranked_submissions_text
    render :text => Submission.rank_all_submissions_by_group
  end
  def ranked_submissions_json
    render :json => Submission.rank_all_submissions_by_group
  end
end