Rails选择随机记录

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

就像是?

@user = User.random 

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

在Rails 4中,我将扩展ActiveRecord::Relation

 class ActiveRecord::Relation def random offset(rand(count)) end end 

这样你就可以使用范围:

 SomeModel.all.random.first # Return one random record SomeModel.some_scope.another_scope.random.first 

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

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

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

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

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

我们发现,对于大型表,MySql上的偏移运行速度非常慢。 而不是使用偏移量:

 model.find(:first, :offset =>rand(c)) 

…我们发现以下技术的运行速度提高了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") 

尝试使用Array的示例方法:

 @user = User.all.sample(1) 

我会使用命名范围。 把它扔进你的用户模型吧。

 named_scope :random, :order=>'RAND()', :limit=>1 

然而,随机函数在每个数据库中并不相同。 SQLite和其他人使用RANDOM()但你需要为MySQL使用RAND()

如果你想能够抓住多个随机行,你可以试试这个。

 named_scope :random, lambda { |*args| { :order=>'RAND()', :limit=>args[0] || 1 } } 

如果您调用User.random ,它将默认为1,但如果您需要多个,也可以调用User.random(3)

如果您需要随机记录但仅在某些条件下,您可以使用此代码中的“random_where”:

 module ActiveRecord class Base def self.random if (c = count) != 0 find(:first, :offset =>rand(c)) end end def self.random_where(*params) if (c = where(*params).count) != 0 where(*params).find(:first, :offset =>rand(c)) end end end end 

例如:

 @user = User.random_where("active = 1") 

此function对于根据一些其他标准显示随机产品非常有用

这是从数据库中获取随机记录的最佳解决方案。 RoR提供易用性的一切。

为了从DB使用样本中获取随机记录,下面是对示例的描述。

基于Marc-Andre Lafortune的github.com/marcandre/backports/的Array#sample的Backport返回数组中的随机元素或n个随机元素。 如果数组为空且n为nil,则返回nil。 如果传递了n并且其值小于0,则会引发ArgumentErrorexception。 如果n的值等于或大于0,则返回[]。

 [1,2,3,4,5,6].sample # => 4 [1,2,3,4,5,6].sample(3) # => [2, 4, 5] [1,2,3,4,5,6].sample(-3) # => ArgumentError: negative array size [].sample # => nil [].sample(3) # => [] 

您可以根据您的要求使用条件,如下例所示。

User.where(active:true).sample(5)

它将从User表中随机返回5个活动用户

如需更多帮助,请访问: http : //apidock.com/rails/Array/sample

强烈推荐这个gem用于随机记录,这是专为具有大量数据行的表而设计的:

https://github.com/haopingfan/quick_random_records

简单用法:

@user = User.random_records(1).take


除了这个gem之外,所有其他答案都对大型数据库表现不佳:

  1. quick_random_records只需花费4.6ms

在此处输入图像描述

  1. 接受的答案User.order('RAND()').limit(10) cost 733.0ms

在此处输入图像描述

  1. offset方法总共花费了245.4ms

在此处输入图像描述

  1. User.all.sample(10)方法花费573.4ms

在此处输入图像描述

注意:我的表只有120,000个用户。 您拥有的记录越多,性能差异就越大。


更新:

在表上执行550,000行

  1. Model.where(id: Model.pluck(:id).sample(10))花费1384.0ms

在此处输入图像描述

  1. gem: quick_random_records只需要6.4ms

在此处输入图像描述