【发布时间】:2020-12-05 01:43:37
【问题描述】:
我使用 Postgres 作为数据库后端,但我认为这并不重要。另外,我想仍然使用sqlite3 作为本地开发数据库,所以理想情况下,任何方法都适用于两者。
“加权”是指该数据库表中的某些项目比其他项目更有可能出现,基于从0 到+inf 的启发式值,其中0 是“永远不会被挑选” , 1 是“与任何其他实例一样被选中,2 是“被选中的可能性是任何其他实例的两倍”。
我已经 read other SO posts 讨论过拉取模型的随机实例,但据我所知,没有任何方法可以通过权重快速做到这一点。
我的模特:
- 拥有数百万个实例。
- 有一个
weightDecimalField,可以随时更新,甚至在运行时。 - 除了使用这种随机选择算法外,在任何地方都没有被引用(例如,它可以随时删除和重新创建而不会出现问题)。
我追求的是一种比我尝试过的解决方案更快的快速方法,或者解释为什么我尝试过的解决方案之一是我能得到的最快的。
避免 XY 问题
我想从数据库表中选择“新鲜”的内容,但仍然有机会看到一些较旧的内容。如果某些内容被浏览得太频繁或不受欢迎,则应该减少它的出现频率。理想情况下,我可以控制它的频率:“啊,所以这将是网站上其他内容的 1.5 倍。”
我尝试过的东西
根据概率滚动随机选择并重试
- 计算模型实例的总数。例如:100。
- 选择模型的一个随机实例。
- 从
1 * weight / instances_count掷骰子以确定是否应将物品扔回并再次进行随机选择。
这似乎很慢,而且“退回”的随机性可能永远不会终止。一般来说,这真的很笨拙,我不想使用它。把它放在第一位,因为它非常“简单”,我很可能会忽略它。
选择每个元素 ID 和权重,并使用随机权重算法选择 ID
-
SELECT所有行。 - 根据权重为每一行分配一个 ID 范围。
- 动态添加所有权重。
- 掷一个
sum_of_all_weights面的骰子。 - 无论选择什么,根据权重选择一个 ID。
问题是,这个算法对于数百万行来说似乎很慢。这是“幼稚”的解决方案。
根据权重分配一系列 ID 并动态删除/重新创建实例
- 每当添加某些内容或更改权重时,删除所有包含该实例唯一详细信息的实例并创建
weight更多具有相同元信息的实例。 - 正常选择随机实例。
需要注意的是,只有基于整数的权重是可能的。此外,性能问题从SELECT 转移到INSERT 和DELETE 操作。
重新思考整个模型并引入“回归”价值
- 添加
throw_back_probability字段而不是weight。 - 如果概率为
0.0,它将永远不会被退回。否则,根据throw_back_probability掷骰子并在需要时投掷。 - 将算法限制为 3 个“回退”(或任意数量)。
这最终解决了问题,但可能仍需要更多的数据库调用,是一种间接解决方案。
确实如此,所以我确信我忽略了基于 annotation 的巧妙解决方案(或类似的)。提前感谢您的帮助!
【问题讨论】:
-
抽样必须有多准确?
-
不需要那么准确@DavidEisenstat,但最好是粗略的“加权”。
标签: python-3.x django algorithm performance random