簡體   English   中英

Rails選擇隨機記錄

[英]Rails select random record

我不知道我是否只是在這里查找錯誤的地方或者是什么,但是活動記錄是否有檢索隨機對象的方法?

就像是?

@user = User.random

或者......好吧,因為那個方法不存在是有一些驚人的“Rails方式”這樣做,我似乎總是冗長。 我也在使用mysql。

我見過的大多數例子最終會計算表中的行數,然后生成一個隨機數來選擇一行。 這是因為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)

在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

我使用命名范圍。 把它扔進你的用戶模型吧。

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")

此功能對於根據一些其他標准顯示隨機產品非常有用

這是從數據庫中獲取隨機記錄的最佳解決方案。 RoR提供易於使用的一切。

為了從DB使用樣本中獲取隨機記錄,下面是示例的描述。

基於Marc-Andre Lafortune的陣列#sample的后端github.com/marcandre/backports/返回數組中的隨機元素或n個隨機元素。 如果數組為空且n為nil,則返回nil。 如果傳遞了n並且其值小於0,則會引發ArgumentError異常。 如果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. 4.6ms總共花費了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

在此輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM