简体   繁体   English

Rails选择随机记录

[英]Rails select random record

I don't know if I'm just looking in the wrong places here or what, but does active record have a method for retrieving a random object? 我不知道我是否只是在这里查找错误的地方或者是什么,但是活动记录是否有检索随机对象的方法?

Something like? 就像是?

@user = User.random

Or... well since that method doesn't exist is there some amazing "Rails Way" of doing this, I always seem to be to verbose. 或者......好吧,因为那个方法不存在是有一些惊人的“Rails方式”这样做,我似乎总是冗长。 I'm using mysql as well. 我也在使用mysql。

Most of the examples I've seen that do this end up counting the rows in the table, then generating a random number to choose one. 我见过的大多数例子最终会计算表中的行数,然后生成一个随机数来选择一行。 This is because alternatives such as RAND() are inefficient in that they actually get every row and assign them a random number, or so I've read (and are database specific I think). 这是因为RAND()类的替代方案效率低下,因为它们实际上得到每一行并为它们分配一个随机数,或者我已经阅读过了(我认为这是数据库特定的)。

You can add a method like the one I found here . 你可以添加一个我在这里找到的方法。

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

This will make it so any Model you use has a method called random which works in the way I described above: generates a random number within the count of the rows in the table, then fetches the row associated with that random number. 这将使你所使用的任何模型都有一个名为random的方法,它按照我上面描述的方式工作:在表中的行计数内生成一个随机数,然后获取与该随机数相关联的行。 So basically, you're only doing one fetch which is what you probably prefer :) 所以基本上,你只需要一次取,这是你可能更喜欢的:)

You can also take a look at this rails plugin . 你也可以看看这个rails插件

We found that offsets ran very slowly on MySql for a large table. 我们发现在MySql上,对于一个大表,偏移运行得非常慢。 Instead of using offset like: 而不是使用偏移量:

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

...we found the following technique ran more than 10x faster (fixed off by 1): ...我们发现以下技术运行速度提高了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)

In Rails 4 I would extend ActiveRecord::Relation : 在Rails 4中,我将扩展ActiveRecord::Relation

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

This way you can use scopes: 这样你就可以使用范围:

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

I'd use a named scope. 我使用命名范围。 Just throw this into your User model. 把它扔进你的用户模型吧。

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

The random function isn't the same in each database though. 然而,随机函数在每个数据库中都不相同。 SQLite and others use RANDOM() but you'll need to use RAND() for MySQL. SQLite和其他人使用RANDOM()但你需要为MySQL使用RAND()

If you'd like to be able to grab more than one random row you can try this. 如果您希望能够抓取多个随机行,您可以试试这个。

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

If you call User.random it will default to 1 but you can also call User.random(3) if you want more than one. 如果您调用User.random ,它将默认为1,但如果您需要多个,也可以调用User.random(3)

If you would need a random record but only within certain criteria you could use "random_where" from this code: 如果您需要随机记录但仅在某些条件下,您可以使用此代码中的“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

For eg : 例如:

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

This function is very useful for displaying random products based on some additional criteria 此功能对于根据一些其他标准显示随机产品非常有用

Here is the best solution for getting random records from database. 这是从数据库中获取随机记录的最佳解决方案。 RoR provide everything in ease of use. RoR提供易于使用的一切。

For getting random records from DB use sample , below is the description for that with example. 为了从DB使用样本中获取随机记录,下面是示例的描述。

Backport of Array#sample based on Marc-Andre Lafortune's github.com/marcandre/backports/ Returns a random element or n random elements from the array. 基于Marc-Andre Lafortune的阵列#sample的后端github.com/marcandre/backports/返回数组中的随机元素或n个随机元素。 If the array is empty and n is nil, returns nil. 如果数组为空且n为nil,则返回nil。 If n is passed and its value is less than 0, it raises an ArgumentError exception. 如果传递了n并且其值小于0,则会引发ArgumentError异常。 If the value of n is equal or greater than 0 it returns []. 如果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)  # => []     

You can use condition with as per your requirement like below example. 您可以根据您的要求使用条件,如下例所示。

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

it will return randomly 5 active user's from User table 它将从User表中随机返回5个活动用户

For more help please visit : http://apidock.com/rails/Array/sample 如需更多帮助,请访问: http//apidock.com/rails/Array/sample

Strongly Recommend this gem for random records, which is specially designed for table with lots of data rows: 强烈推荐这个gem用于随机记录,这是专为具有大量数据行的表而设计的:

https://github.com/haopingfan/quick_random_records https://github.com/haopingfan/quick_random_records

Simple Usage: 简单用法:

@user = User.random_records(1).take


All other answers perform badly with large database, except this gem: 除了这个gem之外,所有其他答案都对大型数据库表现不佳:

  1. quick_random_records only cost 4.6ms totally. 4.6ms总共花费了4.6ms

在此输入图像描述

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

在此输入图像描述

  1. the offset approach cost 245.4ms totally. offset方法总共花费245.4ms

在此输入图像描述

  1. the User.all.sample(10) approach cost 573.4ms . User.all.sample(10)方法的成本为573.4ms

在此输入图像描述

Note: My table only has 120,000 users. 注意:我的表只有120,000个用户。 The more records you have, the more enormous the difference of performance will be. 您拥有的记录越多,性能差异就越大。


UPDATE: 更新:

Perform on table with 550,000 rows 在表上执行550,000行

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

在此输入图像描述

  1. gem: quick_random_records only cost 6.4ms totally gem: quick_random_records只需要6.4ms

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM