【问题标题】:Implementing a Leaderboard实施排行榜
【发布时间】:2010-12-31 20:18:29
【问题描述】:

用户on my site 为说唱歌词创建注释 (example)。我想创建一个排行榜来奖励创建注释最多的人。

排行榜应该跟踪每个用户总共创建了多少注释,以及他在过去一周、一天等中创建了多少。

我在实现整体排行榜时没有问题:

@users = User.all

<table>
  <tr>
    <th>Contributor</th>
    <th>Annotations</th>
  </tr>
    <% @users.sort_by{|u| u.annotations.size }.reverse.each do |u| %>
      <tr>
        <td><%= u %></td>
        <td><%= u.annotations.size %></td>
      </tr>
    <% end %>
</table>

但是当我尝试实现(比如说)每日记分牌时,我在重复代码并且操作非常缓慢(因为它必须遍历内存中的每个注释,而不是依赖于数据库排序/计数):

<table>
  <tr>
    <th>Contributor</th>
    <th>Annotations</th>
  </tr>
    <% @users.sort_by{|u| u.annotations.select{|a| a.created_at > 1.day.ago }.size }.reverse.each do |u| %>
      <tr>
        <td><%= u %></td>
        <td><%= u.annotations.select{|a| a.created_at > 1.day.ago }.size %></td>
      </tr>
    <% end %>
</table>

实施每日/每周记分牌的最佳方式是什么?

【问题讨论】:

    标签: ruby-on-rails leaderboard


    【解决方案1】:

    排行榜作为一个整体很难实施。嗯,根据我的经验,实际的实现是相当简单的,只是它们很难扩展。您经常会发现自己不得不运行许多数据库密集型的数据库查询。要处理每日/每周报告,可能会查询日期时间列,但这意味着您在所述列上有索引。该索引实际上只对排行榜查询有用,它使该表上的所有其他写入都付出了代价,因为必须重新计算索引。

    另一种方法是按计划的时间间隔生成统计信息,然后将该数据写入单独的表格,供排行榜查询使用。例如,您有一个每天晚上运行查询的后台作业(可能是一个昂贵的作业,因为它不使用日期时间索引,但由于它只运行一次并且通过后台作业,费用是“好的”),该查询依次写入 确实 在 datetime 列上有索引的统计表,然后重写排行榜页面以达到预先计算的统计数据。根据您的需要,您可能会让该 cron 脚本还执行其他数据处理和预计算,因此排行榜页面必须根据需要执行尽可能少的计算。

    此时,您的排行榜页面已经正常工作,当它访问带有索引的表时,它仍然需要读取大量行。这是假设您有不错的流量。让索引查询在每个页面上命中大量行仍然很昂贵。所以现在你考虑实现页面缓存,也许将数据存储在 memcached 中。也就是说,由于每日排行榜数据至少每天都在变化,根据定义,在每个页面视图上重新运行这些数据库查询的成本很高。将每日数据缓存在 memcached 中更有意义,并且每个页面视图只命中 memcached。

    所以你可以看到它是一个进化的过程。如果您的流量比您没有单独的表并且只在您的日期时间列上有一个索引而侥幸逃脱。运行总和、计数和平均值可能没问题。但它没有规模。因此,您必须考虑将其分解为更优化的结构。然后您会发现,每天一遍又一遍地运行相同的查询,而基础数据在 24 小时内不发生变化是昂贵的,因此您转向缓存设置。有很多活动部件,它会变得很复杂,嗯,真的很乏味。

    在排行榜方面,我是一个久经沙场的愤世嫉俗者,虽然它们非常适合游戏机制和激励人们(每个人都喜欢看到分数!),但要大规模开展工作是一件很痛苦的事情。

    【讨论】:

      【解决方案2】:

      您是否考虑过将这些统计信息保存在由观察者更新的单独表/模型中?您在此处的视图中做了很多繁重的工作,这通常不是好的做法。

      【讨论】:

        【解决方案3】:

        我建议使用 Redis。您可以运行一个 cron 类型的任务,从数据库中提取数据,然后将其放入 Redis 排序集中。排序集功能可能是存储排行榜的最佳实用程序。 http://redis.io/topics/data-types

        【讨论】:

          【解决方案4】:

          除了 Jeff 对使用 redis 的建议之外,还有一个我一直在使用 redis 进行排行榜工作的 ruby​​ gem:https://github.com/agoragames/leaderboard

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-01
            • 1970-01-01
            • 2021-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多