Получить массив, содержащий количество постов, созданных за последние 2 недели - PullRequest
4 голосов
/ 03 марта 2010

Я хочу создать спарклайны, которые иллюстрируют количество постов, созданных в моем блоге за последние 2 недели. Для этого мне нужно сначала сгенерировать массив, содержащий количество сообщений, созданных в каждый день в течение рассматриваемого периода.

Например, этот массив:

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

генерирует этот спарклайн: (я использую оболочку Googlecharts вокруг API Google Charts )

image

Мой вопрос заключается в том, как создать эти массивы. Вот что я делаю сейчас: (Я использую 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

Этот подход уродлив и медленен - ​​должен быть лучший способ!

Ответы [ 5 ]

7 голосов
/ 03 марта 2010

Это даст вам даты сопоставления хешей для количества записей:

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
1 голос
/ 03 марта 2010

Попробуйте:

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 минут.

1 голос
/ 03 марта 2010

Вам необходимо правильно проиндексировать данные, иначе это не будет эффективно работать.Если вы используете гранулярность "день", то стоит иметь столбец Дата.Затем вы можете использовать стандартную операцию 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

Имейте в виду, что если вы потенциально пропускаете день, вам придется учесть это, вставив нулевое значение в свои результаты.Дата здесь возвращается, поэтому вы должны быть в состоянии вычислить пропущенные значения и заполнить их. Как правило, это делается путем итерации по группе дней с помощью метода collect.

Когда вам нужно получить тонкий фрагментданные быстро, загрузка экземпляров моделей всегда будет огромным узким местом.Часто вам нужно перейти непосредственно к SQL, если нет простого способа получить то, что вам нужно.

0 голосов
/ 03 марта 2010

Большую часть времени тратят на выполнение 14 запросов к базе данных, каждый из которых должен сканировать каждую строку в таблице, чтобы проверить дату (при условии, что вы не индексируете с помощью creat_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

Я также рекомендую добавить индекс, как рекомендовано Тадманом, но в этом случае в поле create_at в таблице сообщений.

0 голосов
/ 03 марта 2010

В дополнение к ответу tadman, если у вас есть требуемый доступ администратора, вы можете исследовать разбиение по дате, особенно если вы получаете чрезвычайно большое количество сообщений в день.

...