通过elasticsearch(带轮胎)的排行榜排名

时间:2013-08-28 19:29:57

标签: ruby-on-rails elasticsearch tire

我有一个映射,归结为以下(删除了不相关的字段):

mapping 
  indexes :id, type: 'integer', index: :not_analyze        
  indexes :first_name, boost: 5, type: 'string', analyzer: 'snowball'
  indexes :votes, type: 'integer', index: :not_analyzed
end

目前我正在通过postgres计算排名,因此给出以下条目:

| first_name | votes |
----------------------
| Andy       |     5 |
| Barry      |     8 |
| Carl       |     5 |
| Derek      |     1 |

使用postgres,我可以得到以下内容:

| first_name | votes | rank |
-----------------------------
| Barry      |     8 |    1 |
| Andy       |     5 |    2 |
| Carl       |     5 |    2 |
| Derek      |     1 |    4 |

是否有可能以某种方式通过elasticsearch计算此排名?

2 个答案:

答案 0 :(得分:3)

我不相信ElasticSearch可以做到这一点,因为更新单个文档需要重新计算所有排名值。据我所知,这是不可能的。

相反,一旦得到结果,您可以使用Ruby来计算排名,如下所示:

scores = {:a=>5, :b=>8, :c=>5, :d=>1}
scores.values.sort{|a,b| a <=> b}.tap do |sorted_scores|
  sorted_scores.each{|vote| puts sorted_scores.index(vote)+1 }
end

答案 1 :(得分:3)

Redis确实是排行榜的理想解决方案。虽然它引入了另一项技术,但如果您使用的是AWS,请注意ElastiCache管理的Redis是just launched this week

Generic Redis命令将是:

zadd votes 5 "Andy"
zadd votes 8 "Barry"
zadd votes 5 "Carl"
zadd votes 1 "Derek"

然后获得排名最高的排行榜:

zrevrange votes 0 -1

有关详细信息,请参阅Redis docs for ZREVRANGE

对于Ruby on Rails,我建议你看一下受欢迎的redis-objects gem,因为它很容易与ActiveRecord集成。假设您有一个显示votes列的表格,您可以在保存时更新排名:

class User < ActiveRecord::Base
  include Redis::Objects
  sorted_set :rank, global: true

  after_save :update_rank
  def update_rank
    self.class.rank[id] = votes
  end
end

然后检索排行榜:

User.rank.revrange(0, -1)

在此示例中,这将返回id值,然后您可以使用这些值来检索记录,如下所示。 (您还可以存储first_name或其他一些唯一值。)

ids = User.rank.revrange(0, -1)
users = User.where(id: ids).all

您可以通过传递不同的开始/结束值来对结果revrange进行分页:

User.rank.revrange(0, 9)
User.rank.revrange(10, 19)

您可以轻松地将此包装在用户中的self.方法中,该方法从Redis检索排名页面并相应地返回数据库记录。