Rails选择随机记录

JP *_*shy 17 ruby mysql ruby-on-rails

我不知道我是否只是在这里查找错误的地方或者是什么,但是活动记录是否有检索随机对象的方法?

就像是?

@user = User.random
Run Code Online (Sandbox Code Playgroud)

或者......好吧,因为那个方法不存在是有一些惊人的"Rails方式"这样做,我似乎总是冗长.我也在使用mysql.

Jor*_*eña 39

我见过的大多数例子最终会计算表中的行数,然后生成一个随机数来选择一行.这是因为它们之类的替代方案RAND()效率很低,因为它们实际上得到了每一行并为它们分配了一个随机数,或者我已经阅读过了(我认为这是数据库特定的).

你可以添加一个我在这里找到的方法.

module ActiveRecord
  class Base
    def self.random
      if (c = count) != 0
        find(:first, :offset =>rand(c))
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这将使你所使用的任何模型都有一个方法random,它以我上面描述的方式工作:在表中的行计数内生成一个随机数,然后获取与该随机数相关联的行.所以基本上,你只需要一次取,这是你可能更喜欢的:)

你也可以看看这个rails插件.

  • 这很好.我喜欢它,因为它不是特定于ORM的.干得好,谢谢! (3认同)

Ben*_*son 7

我们发现在MySql上,对于一个大表,偏移运行得非常慢.而不是使用偏移量:

model.find(:first, :offset =>rand(c))
Run Code Online (Sandbox Code Playgroud)

...我们发现以下技术运行速度提高了10倍以上(固定为1):

max_id = Model.maximum("id")
min_id = Model.minimum("id")
id_range = max_id - min_id + 1
random_id = min_id + rand(id_range).to_i
Model.find(:first, :conditions => "id >= #{random_id}", :limit => 1, :order => "id")
Run Code Online (Sandbox Code Playgroud)

  • 如果删除了任何记录,则方法不会生成均匀分布的结果,这通常是人们所期望的.想象一下除了id 5之外存在id 1-10的情况.在这种情况下,当随机数生成器产生5或6(20%的时间)时,将返回id为6的模型,而每个其他现有ID仅在10%的时间内被选中.也许不是交易破坏者,而是需要注意的事情. (3认同)

kus*_*tel 5

尝试使用Array的示例方法:

@user = User.all.sample(1)
Run Code Online (Sandbox Code Playgroud)

  • 如果您有大量数据,您绝对不应该这样做 - 它会尝试将所有用户加载到内存中。如果您使用的是 Rails 4 和 Postgres,请使用 User.order("RANDOM()").limit(10)(来自 http://stackoverflow.com/a/17373279/1298553)。 (3认同)

joo*_*ost 4

在 Rails 4 中我会扩展ActiveRecord::Relation

class ActiveRecord::Relation
  def random
    offset(rand(count))
  end
end
Run Code Online (Sandbox Code Playgroud)

这样您就可以使用范围:

SomeModel.all.random.first # Return one random record
SomeModel.some_scope.another_scope.random.first
Run Code Online (Sandbox Code Playgroud)