Rails & postgres collection 随机记录,在特定列上具有分页和自定义权重

Rails & postgres collection of random records with pagination and custom weight on specific column

我想随机检索 collection 个在 created_at 上以特定权重分页的项目。

我成功检索到随机 collection 使用 postgres 选项分页 setseed

问题是,我如何在我的 collection 中结合对 created_at 的某种称重(这将使称重的项目更有可能出现在随机样本中)和这个setseed postgres 选项。

我正在考虑取回物品,将它们添加到我想要的重量,然后执行我的随机请求,但我认为这不会很好 performance-wise。

我陷入了一种死胡同,我不知道如何解决这个问题。

这是我现在所做的: 只需使用 setseed 选项即可在我的每个页面上添加不同批次的随机项目:

Item.connection.execute "select setseed(0.5)"
Item.where(...).order('random()').page(params[:page]).per_page(15)

我建议将您的 created_at 转换为浮点数。这是一个例子

Item.select("*, RANDOM() * to_char(created_at, 'YYYYMMDD')::float AS my_new_order_val").order(my_new_order_val: :desc)

使用一些数学方法可以实现 created_at 时间戳上的权重随机排序。

postgres 中的 random() 函数将始终创建一个值,其中 0.0 <= random() < 1.0.

由于您首先想要最新的项目,因此创建一个新比率,以便刚刚创建的任何项目的比率都为 1/1 或 100%。

比刚才更早的任何内容的新旧率都低于 100%。

例如now()纪元时间为1645955465,昨天为1645869065,一年前为1614419721,则比率为:

now/now is  1645955465/1645955465 = 1.0
yesterday/now is 1645869065/1645955465 = 0.99994
1 year ago/now is 1614419721/1645955465 = 0.98084

上面的比率计算可能对您有用。上面的计算,现在是100%新,昨天是99.994%新,一年前是98.084%新。

接下来,将新旧率乘以一个随机数。这为您提供了一个加权随机数。较新的项目将具有更多的重量。要进行计算,请提取新生率纪元并乘以一个随机数。

Item.where(...)
  .order
  ("(extract(epoch(from created_at)) 
    / extract(epoch from now())) 
    * RANDOM()")
  .page(params[:page])
  .per_page(15)

根据您的数据,比率的差异可能不足以对随机数排序产生显着影响。除了上述方法之外,还有许多方法可以操纵随机排序。例如,您可以通过为随机化器提供比 0 到 1 更小的范围来减少随机数。或者您可以使新比率具有比 0.98084 到 1 更大的范围。