3

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

これであなたの質問に答えられるとは思いませんが、フォーマットを使用したいと思います。

私はルビーに慣れているので、何かを簡単にします。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 に答える