3

我有一个 activerecord 模型Event,我想按等级排序。排名将是加权属性的总和。例如,我可能想使用以下逻辑对事件进行排名:

LOG(number of followers) + (7 - number of days from now)

以下工作,但并不令人满意,因为它返回结果集而不是关系对象。因此,我将无法将其视为范围。(仅供参考,我正在使用带有 PostGIS 扩展的 Postgres)

x = Event.find_by_sql("
            SELECT   
                (
                    CASE WHEN COUNT(follows.*) = 0 
                    THEN 0 
                    ELSE LOG(COUNT(follows.*)) END

                    +

                    SIGN(7 - (EXTRACT(EPOCH FROM start) - EXTRACT(EPOCH FROM NOW())) / 86400) * LOG(ABS(7 - (EXTRACT(EPOCH FROM start) - EXTRACT(EPOCH FROM NOW())) / 86400))
                ) as score,
                events.*
            FROM events
            LEFT OUTER JOIN follows 
                ON events.id = follows.followable_id AND follows.followable_type = 'Event' AND follows.blocked = 'f'
            WHERE (events.start > NOW()) AND (ST_DWithin(st_setsrid(st_point(#{@location[:lng]}, #{@location[:lat]}), 4326), st_transform(loc, 4326), 48280.2, true))
            GROUP BY events.id
            ORDER BY 1 DESC
            ")

我知道我可以在Events表中添加一个计数器缓存并避免加入,但将来我会想通过其他一些关联来计算排名,所以知道如何做会很有帮助。

谢谢

4

2 回答 2

3

这实际上很容易拆分为ActiveRecord::Relation查询。

x = Event.select("(
                CASE WHEN COUNT(follows.*) = 0 
                THEN 0 
                ELSE LOG(COUNT(follows.*)) END

                +

                SIGN(7 - (EXTRACT(EPOCH FROM start) - EXTRACT(EPOCH FROM NOW())) / 86400) * LOG(ABS(7 - (EXTRACT(EPOCH FROM start) - EXTRACT(EPOCH FROM NOW())) / 86400))
            ) as score,
            events.*")

x = x.joins("LEFT OUTER JOIN follows 
            ON events.id = follows.followable_id AND follows.followable_type = 'Event' AND follows.blocked = 'f'")

x = x.where("(events.start > NOW()) AND (ST_DWithin(st_setsrid(st_point(#{@location[:lng]}, #{@location[:lat]}), 4326), st_transform(loc, 4326), 48280.2, true))")

x = x.group('events.id')

x = x.order('1 desc')

当然,我建议将它们分成不同的范围,但这至少应该让你朝着正确的方向前进。

于 2013-05-06T01:44:31.480 回答
-1

我认为这不能回答您的问题,但我想使用格式。

我会让事情变得更容易,因为我更喜欢 ruby​​,我会在你的 Event 类中创建一个新方法:

def rank
  # you rank computation according model columns and associations
  Math.log(followers_count) + (7 - number_of_days_from_now)
end

def self.by_rank(order = 'desc')
  all.sort{ |event, event1| order == 'desc' ? event1 <=> event : event <=> event1 }
end

然后您可以扩展缓存计算,在事件表中创建一个排名列,然后您可以执行以下操作:

Event.order('rank desc')
Event.order('rank asc')
于 2013-05-06T01:47:31.957 回答