按差异总和排序

问题描述 投票:2回答:2

我有一个模型有一个属性与浮动列表:

values = ArrayField(models.FloatField(default=0), default=list, size=64, verbose_name=_('Values'))

目前,我正在获取我的条目并根据所有差异的总和与另一个列表对它们进行排序:

def diff(l1, l2):
    return sum([abs(v1-v2) for v1, v2 in zip(l1, l2)])

list2 = [0.3, 0, 1, 0.5]
entries = Model.objects.all()
entries.sort(key=lambda t: diff(t.values, list2))

如果我的条目数量非常慢,这种方法很快。但我担心有大量条目,所有条目的比较和排序将变慢,因为它们必须从数据库加载。有没有办法让这个更有效率?

django postgresql django-models
2个回答
0
投票

最好的方法是自己编写,现在你在列表上迭代4次!

虽然这种方法看起来很漂亮,但并不好。

你可以做的一件事是:

  1. 有一个名为last_diff的变量并将其设置为0
  2. 遍历所有entries
  3. 遍历每个qazxsw poi
  4. 从i = 0到列表的末尾,计算entry.values
  5. 在一个名为abs(entry.values[i]-list2[i])的变量中对这些值求和
  6. 如果new_diff从内环突破并将new_diff > last_diff推到正确的位置(它被称为entry,请检查出来!)

通过这种方式,在平均情况下,时间复杂度远低于您现在所做的!

也许你也必须有创造力。我要分享一些想法,自己检查一下,以确保它们没问题。

假如说:

  1. Insertion Sort列表元素总是正浮动。
  2. 所有valueslist2总是一样的。

然后你可以说,无论entries中的元素是什么,values中元素的总和越大,diff值就越大。

那么你可能只能忘记整个list2功能。 (测试一下!)


0
投票

使其真正变得更快的唯一方法是尽可能多地将数据移动到数据库,即计算和排序。这并不容易,但在diff的帮助下,我设法在几乎纯粹的Django中实际编写了一个查询:

this answer

class Unnest(models.Func): function = 'UNNEST' class Abs(models.Func): function = 'ABS' class SubquerySum(models.Subquery): template = '(SELECT sum(%(field)s) FROM (%(subquery)s) _sum)' x = [0.3, 0, 1, 0.5] pairdiffs = Model.objects.filter(pk=models.OuterRef('pk')).annotate( pairdiff=Abs(Unnest('values')-Unnest(models.Value(x, ArrayField(models.FloatField())))), ).values('pairdiff') entries = Model.objects.all().annotate( diff=SubquerySum(pairdiffs, field='pairdiff') ).order_by('diff') 函数将unnest的每个元素变成一行。在这种情况下,它会发生两次,但会立即减去两个结果列并使其成为正数。尽管如此,每个values的行数和pk一样多。这些需要总结,但这并不像听起来那么容易。该列不能简单地聚合。这是迄今为止最棘手的部分 - 即使在摆弄了这么久之后,我仍然不太明白为什么Postgres需要这种间接性。在使用它的少数几个选项中,我相信子查询是Django中可以表达的唯一一个(并且只有1.11版本)。

注意,上面的行为与values完全相同,即当一个数组比另一个数组长时,其余部分被忽略。

进一步改进

虽然当你不必再检索所有行并在Python中循环它们时它已经快得多,但它还没有改变它导致全表扫描。每次都必须处理所有行。不过,你可以做得更好。看看zip扩展。使用它来计算L1距离 - 至少,这似乎是你用cube算子直接计算的。这将需要使用<#>或定制RawSQL。然后在SQL表达式Expression上添加GiST索引,或者如果您能够将类型从cube("values")更改为float[],则直接在该字段上添加。如果是后者,你可能也必须实现自己的cube - 我还没有找到任何提供它的包。在任何情况下,在所有这些情况下,最低距离的前N个查询将被完全索引,因此速度极快。

© www.soinside.com 2019 - 2024. All rights reserved.