Rails: получить определенное количество случайных записей

#ruby-on-rails #ruby-on-rails-3 #activerecord #random #limit

#ruby-on-rails #ruby-on-rails-3 #activerecord #Случайный #ограничение

Вопрос:

Итак, в моем приложении есть фотографии, принадлежащие коллекциям. Я хочу иметь возможность показывать 13 фотографий из определенной коллекции на странице.

Я пробовал это:

 c = Collection.first
@photos = c.photos.offset(rand(c.photos.count)).limit(13)
  

Это работает, вроде как. Проблема в том, что если в коллекции не намного больше 13 фотографий, то она не обязательно возвращает 13 фотографий. Мне нужно конкретно получить ровно 13 фотографий.

FWIW В случае моего приложения коллекция создается только администраторами / модниками, поэтому мы можем обеспечить, чтобы ни в одной коллекции не было меньше 13 фотографий. Что мне нужно, так это иметь возможность начать выбирать фотографии случайным образом, как только будет доступно более 13.

Как я мог это сделать?

Ответ №1:

Вы могли бы сначала выбрать 13 случайно связанных идентификаторов фотографий, а затем выполнить запрос к базе данных для их извлечения:

 c = Collection.first
random_ids = c.photo_ids.sort_by { rand }.slice(0, 13)
@photos = Photo.where(:id => random_ids)
  

Комментарии:

1. В вашем комментарии сказано «до 13 фотографий», вернет ли это РОВНО 13 фотографий? Я не могу использовать его, если он возвращает меньше.

2. Ну, он не может вернуть 13 фотографий, если в коллекции меньше 13 идентификаторов photo_ids. В остальном, да, так и есть.

Ответ №2:

Просто отсортируйте их случайным образом в sql и возьмите первые 13. так что делайте:

 c.photos.order("RAND()").limit(13)
  

Комментарии:

1. Работает ли это в SQLite и PostgreSQL? Я не очень хорошо разбираюсь в SQL, но в прошлом у меня были проблемы между моей средой разработки и производственной средой из-за различий в SQL.

2. Вы всегда можете попробовать и выяснить. Я почти уверен, что RAND() работает в большинстве реализаций SQL.

3. Будьте осторожны, потому что это НЕВЕРОЯТНО неэффективно и на больших наборах данных займет гораздо больше времени, чем необходимо для выполнения.

4. POSTGRES и SQLite3 используют ‘RANDOM()’. Это зависит от базы данных.

5. Это, по-видимому, чрезвычайно медленно.

Ответ №3:

Вот быстрое решение.. в настоящее время использует его с более чем 1,5 миллионами записей и получает приличную производительность. Лучшим решением было бы кэшировать один или несколько наборов случайных записей, а затем обновлять их с помощью фонового рабочего с желаемым интервалом.

Созданный random_records_helper.rb файл:

 module RandomRecordsHelper

 def random_user_ids(n)
    user_ids = []
    user_count = User.count
    n.times{user_ids << rand(1..user_count)}
    return user_ids
 end
  

в контроллере:

 @users = User.where(id: random_user_ids(10))