Вопрос по random, postgresql, ruby-on-rails-3, ruby-on-rails – Rails 3, will_paginate, случайные, повторяющиеся записи, Postgres, сбой setseed

5

У меня есть база фильмов с атрибутами. Я хотел бы вернуть запрошенную партию этих фильмов в случайном порядке на шаблон с нумерацией страниц. Я использую will_paginate. Я попробовал следующее:

## MoviesController

movies = Movie.get_movies(query_string)   # a method in Movie model that takes in 
                                          # a query_string and fetches movies 
                                          # with user-set params

@movies = movies.order('random()').page(params[:page]).per_page(16)

Это прекрасно работает, за исключением того, что фильмы повторяются от страницы к странице. Решения этой проблемы были опубликованыВот а такжеВот, Эти ссылки объясняют это, потому чтоrandom() семя сбрасывается со страницы на страницу, нет согласованности иOFFSET становится бесполезным. Они предлагают отличные решения для пользователей MySQL, так какrand(n) функция берет семяn, Однако Postgres этого не делает. Вы должны объявитьsetseed(n) вSELECT до выдачиrandom() вORDER.

Итак, я попробовал Postgres способ установить семя:

@movies = movies.select('setseed(.5)').order('random()').page(params[:page]).per_page(16)

Любопытно, что это возвращало объекты фильма без каких-либо атрибутов. Следующее было поднято из шаблона:

ActiveModel::MissingAttributeError in Movies#action

missing attribute: some_movie_attribute

Я отладил это и, как только стек достиг action_controller / metal, @movies содержал:

[#<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >]

Это количество объектов Movie (18) соответствует количеству фильмов, возвращаемых по запросу.

Я также попробовал следующее, чтобы увидеть, еслиsetseed(n) Была проблема с удалением метода случайного порядка:

@movies = movies.select('setseed(.5)').page(params[:page]).per_page(16)

Это вернуло те же объекты фильма без атрибутов, которые выложены выше. Итак, похоже, чтоsetseed(n) это действительно проблема.

Я попробовал пару обходных путей, например:

# MoviesController

movies = Movie.get_movies(query_string)
shuf_movs = movies.shuffle  ## effectively turns shuf_movs into an array

@movies = shuf_movs.paginate(:page => params[:page], :per_page => 16)

Это также вернуло страницы с повторяющимися фильмами. Я думал, что это потому, что нумерация страниц нуждалась в упорядочении объектовsomethingи вы не можете устанавливать семена в Array # shuffle. Поэтому я попытался написать свой собственный код рандомизации, который бы временно сохранял идентификатор для упорядочивания в объектах Movie. (Пожалуйста, извините за небрежный код):

# Movie model

attr_accessor :rand_id

# MoviesController

movies = get_movies(query_string)
movies_count = movies.count
r = Random.new
nums = []
rand_movs = []
id = 1
while nums.count != movies_count
  num = r.rand(0..movies_count - 1)
  if !(nums.include?(num))
    movie = movies[num]
    movie.rand_id = id
    rand_movs << movie
    nums      << num
    id += 1
  end
end

@movies = rand_movs.sort_by { |a| a.rand_id }.paginate(:page => params[:page], :per_page => 16)

Это все еще производило повторяющиеся фильмы на разных страницах. На данный момент я понимаю, что will_paginate не принимает то, что вы сортировали доpaginate называется. Итак, я попробовал это:

@movies = rand_movs.paginate(:order => 'rand_id', :page => params[:page], :per_page => 16)

Это все еще повторяет записи.:order -> 'rand_id' игнорируется, потому что:order имеет значение только тогда, когда вы имеете дело с объектами ActiveRecord, а не с массивами.

Такsetseed(n) Похоже, это моя единственная надежда на получение рандомизированных неповторяющихся записей с помощью will_paginate. Есть идеи?

Спасибо!

Error: User Rate Limit Exceeded.select('*, setseed(1)') Matzi

Ваш Ответ

2   ответа
18

Movie.connection.execute "select setseed(0.5)"
Movie.where(...).order('random()').page(params[:page]).per_page(15)

Array#shuffleKernel.randKernel.srand

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded jkym
1

select:

@movies = movies.select(['setseed(.5)', 'some_movie_attribute']).order('random()').page(params[:page]).per_page(16)

some_movie_attribute

Error: User Rate Limit Exceededmovies.select(['setseed(.5)', '*']).order('random()').page(params[:page]).per_page(16) Error: User Rate Limit Exceeded jkym

Похожие вопросы