4

過去 2 週間にブログで作成された投稿の数を示すスパークラインを作成したいと考えています。これを行うには、最初に、問題の期間中に毎日作成された投稿の数を含む配列を生成する必要があります。

たとえば、次の配列です。

[40, 18, 0, 2, 39, 37, 22, 25, 30, 60, 36, 5, 2, 2]

このスパークラインを生成します: ( Google Charts APIの周りに Googlecharts ラッパーを使用しています)

私の質問は、これらの配列を作成する方法です。これが私が今やっていることです: (私はSearchlogicを使用してクエリを実行していますが、使用したことがなくても理解できるはずです)

  history = []
  14.downto(1) do |days_ago|
    history.push(Post.created_at_after((days_ago + 1).day.ago.beginning_of_day).created_at_before((days_ago - 1).days.ago.beginning_of_day).size)
  end

このアプローチは醜くて遅いです - もっと良い方法があるはずです!

4

5 に答える 5

7

これにより、日付を投稿数にマッピングするハッシュが得られます。

counts = Post.count(
  :conditions => ["created_at >= ?", 14.days.ago],
  :group => "DATE(created_at)"
)

次に、これを配列に変換できます。

counts_array = []
14.downto(1) do |d|
  counts_array << (counts[d.days.ago.to_date.to_s] || 0)
end
于 2010-03-02T21:49:54.403 に答える
1

これを試して:

n_days_ago, today = (Date.today-days_ago), Date.today

# get the count by date from the database  
post_count_hash = Post.count(:group => "DATE(created_at)", 
             :conditions => ["created_at BETWEEN ? AND ? ", n_days_ago, today])

# now fill the missing date with 0   
(n_days_ago..today).each{ |date| post_count_hash[date.to_s] ||=0 }

post_count_hash.sort.collect{|kv| kv[0]}

注1:このメソッドにインデックスを追加すると、適切にcreated_atスケーリングできるはずです。毎日数百万のレコードに遭遇した場合は、投稿数を日ごとに別のテーブルに保存することをお勧めします。

注2:パフォーマンスを向上させるために、結果をキャッシュしてエージングすることができます。私のシステムでは、通常、TTLを10〜15分に設定します。

于 2010-03-02T21:41:00.747 に答える
1

データを適切にインデックス化する必要があります。そうしないと、効率的に機能しません。「日」の粒度を使用している場合は、日付列が必要です。次に、標準の SQL GROUP BY 操作を使用して、必要な値を直接取得できます。

たとえば、移行は次のように実行できます。

self.up
  add_column :posts, :created_on_date
  add_index :posts, :created_on_date

  execute "UPDATE posts SET created_on_date=created_at"
end

インデックスを実行できるため、取得は非常に高速です。

def sparkline_data
  self.class.connection.select_values("
    SELECT created_on_date, COUNT(id) FROM posts
      WHERE created_on_date>DATE_SUB(UTC_TIMESTAMP(), INTERVAL 14 DAY)
      GROUP BY created_on_date
  ").collect(&:to_i)
end

1 日を逃す可能性がある場合は、結果にゼロの値を挿入することでそれを考慮する必要があることに注意してください。日付がここに返されるので、欠落している値を計算して埋めることができるはずです。通常、これは、collect を使用して一連の日数にわたって反復することによって行われます。

データの薄いスライスをすばやく取得する必要がある場合、モデルのインスタンスのロードは常に大きなボトルネックになります。必要なものを取得する簡単な方法がない場合、多くの場合、SQL に直接アクセスする必要があります。

于 2010-03-02T21:36:30.680 に答える
0

費やされる時間の大部分は、日付を確認するためにテーブルのすべての行をスキャンする必要がある14のデータベースクエリの実行です(created_atでインデックスを作成していないと仮定します)。

これを最小限に抑えるために、単一のデータベースクエリを実行して関連する行を取得し、それらを並べ替えることができます。

history = []
14.times { history << 0 }
recent_posts = Post.created_at_after(14.days.ago.beginning_of_day)
recent_posts.each do |post|
  history[(Date.today - post.created_at.to_date).to_i] += 1
end

また、tadmanが推奨するようなインデックスを追加することをお勧めしますが、この場合は、postsテーブルのcreated_atフィールドに追加します。

于 2010-03-02T21:59:46.077 に答える
0

tadmanの回答に加えて、必要な管理者アクセス権がある場合、特に1日あたりの投稿数が非常に多い場合は、日付に基づいてパーティション分割を調査することをお勧めします。

于 2010-03-02T21:40:03.137 に答える