2011-03-23 119 views
3

我在Rails中有一個模型,我想從中選擇一個隨機條目。 到目前爲止,我已經有了這樣的命名範圍內做到了:在ruby/rails中從數組中加權的隨機選擇

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

但現在我已經添加了一個整型字段「重量」,以表示與各行應挑選的概率模型。

我該如何做一個加權隨機選擇?

我發現並嘗試了snippets.dzone.com上的兩種方法,它擴展了Array類並添加了加權隨機函數,但兩者都無效或爲我選取了隨機項。

我正在使用REE 1.8.7和Rails 2.3。

+1

啓發這可能是很好的DB你使用的是什麼補充。在Ruby中做並不難,但在數據庫中做它可能會更有效率。 – 2011-03-23 14:28:50

+0

哦,是的,忘了提及我正在使用MySQL。但我非常專注於解決Ruby中的問題,甚至沒有考慮在查詢級別解決這個問題。 – capsized 2011-03-24 08:02:34

回答

5

也許我明白這是完全錯誤的,但是難道你不能僅僅使用列「權重」作爲隨機數的一個因子嗎? (根據分貝,一些預防措施是必要的,以防止產品溢出。)

named_scope :random, lambda { { :order=>'RAND()*weight', :limit => 1 } } 
+0

你是正確的重量是隨機數的因素。這比我最初想象的要簡單得多!謝謝! – capsized 2011-03-24 08:00:48

+2

這不會按預期工作。假設一張有999條記錄的表格,所有的權重都是1,除了一個是2的情況。你會希望特殊記錄選擇1/500次(因爲它的權重是2,總重量是1000),但實際上它是選擇一半的時間(每次rand()計算大於1)。而且,即使你只記錄一條記錄,它也會執行rand()函數的1000倍。您最好在一個查詢中獲得總數,使用ruby在權重間隔中選擇一個點,然後根據該數字選擇一條記錄。 – rewritten 2012-11-27 15:57:31

0

在一個查詢,你應該:

  • 由隨機因素計算總重量
  • 乘法,給出一個權重閾值
  • 再次通過表格求和,直到達到重量閾值。

在SQL它會sompething這樣(沒試過真正)

SELECT SUM(weight) FROM table INTO @totalwt; 
@lim := FLOOR(RAND() * @totalwt); 
SELECT id, weight, @total := @total + weight AS cumulativeWeight 
    FROM table WHERE cumulativeWeight < @lim, (SELECT @total:=0) AS t; 

通過Optimal query to fetch a cumulative sum in MySQL