2011-03-23 8 views
3

임의의 항목을 선택하려는 레일스 모델이 있습니다.루비/레일의 배열에서 가중치를 적용한 무작위 선택

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

을하지만 지금은 각 행이 포착해야되는 확률을 나타내는 모델의 정수 필드 '무게'를 추가했습니다 : 지금까지이 같은 명명 된 범위와 함께 일을했습니다.

이제 어떻게 가중치 임의 선택을 수행 할 수 있습니까?

snippets.dzone.com에서 Array 클래스를 확장하고 가중치 임의 함수를 추가하는 두 가지 메소드를 찾아서 사용해 보았습니다. 그러나 둘 다 작동하지 않거나 임의 항목을 선택했습니다.

저는 REE 1.8.7과 Rails 2.3을 사용하고 있습니다.

+1

에서 영감을 (진짜 시도하지). Ruby에서는 어렵지 않지만 DB에서 처리하는 것이 훨씬 효율적입니다. –

+0

오, 예, mysql을 사용하는 것을 잊어 버렸습니다. 하지만 저는 루비에서 그것을 해결하는 데 너무 집중했습니다. 나는 쿼리 레벨에서 그것을 해결하는 것을 고려조차하지 않았습니다. – capsized

답변

5

어쩌면 나는 이것을 완전히 잘못 이해하고 있지만 "무게"열을 난수에 대한 요인으로 사용할 수는 없을까? (DB를에 따라 일부 사항은 넘쳐에서 제품을 방지 할 필요가있을 것이다.) 당신이해야 하나 개의 쿼리에서

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

당신은 체중이 난수에 영향을 미치는 것이 옳습니다. 이것은 처음에 생각했던 것보다 훨씬 간단했습니다! 고맙습니다! – capsized

+2

예상대로 작동하지 않습니다. 999 개의 레코드가있는 테이블을 가정 해보십시오. 모든 가중치는 2인데 1을 제외하고는 1입니다. 특수 레코드가 1/500 회 선택됩니다 (해당 가중치가 2이고 총 가중치가 1000이기 때문에). 실제로 선택된 절반의 시간 (rand()가 1을 초과 할 때마다). 또한, 하나의 레코드 만 남겨도 rand() 함수의 1000 배를 실행합니다. 하나의 쿼리에서 합계를 얻고, 루비를 사용하여 가중치 간격의 포인트를 선택한 다음 해당 숫자를 기반으로 한 레코드 만 선택하는 것이 좋습니다. – rewritten

0

:

  • 가 임의의 배수를 곱하여 총 중량
  • 을 계산 , 중량 임계 값에 도달 할 때까지 테이블 합산을 통해 다시 스캔하여 중량 임계 값을 제공하십시오 (
  • ). 이 같은 sompething 될 SQL에서

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; 

DB가 사용하고있는 추가하는 것이 좋을 것 Optimal query to fetch a cumulative sum in MySQL