如何在Django ORM中按查询集分组使用PostgreSQL ArrayAgg函数?

时间:2018-01-24 06:33:09

标签: django postgresql performance join array-agg

为了简单起见我有四个表(A,B,类别和关系),关系表在B中存储A的强度,而类别存储B的类型。

A <--- Relation ---> B ---> Category

我正在尝试使用PostgreSQL的ArrayAgg和基于此gist的数据库索引功能来消除查询中的连接以减少计算时间。 (由于有18000个关系,4000个B和1500个类别,我对每个报告的计算将花费近两个小时) 我得到的错误是:     psycopg2.ProgrammingError:GROUP BY中不允许使用聚合函数 第1行:...... U0。“id”,U2。“B”有U0。“id”= ANY((ARRAY_AGG(...

我已使用Brad Martsberger solution到我的previous question来计算B中按B类别分组的每个A强度的总和, 每个B类别中计算的强度和的最小值和最大值以及每个B类别中每个A的发生率以及该类别中B本身的出现次数:

annotation0 = {
        'SumIntensity': Sum('ARelation__Intensity'),
        'A_Ids': ArrayAgg('id')
    } 
annotation1 = {
        'BOccurrence' : Count('id', distinct=True),
    }
sub_filter0 = Q(id__any=OuterRef('A_Ids'))
sub_filter1 = Q(Category_id=OuterRef('ARelation__B__Category_id'))
subquery0 = A.objects.filter(sub_filter0).values('id','ARelation__B__Category_id').annotate(**annotation0).order_by('-SumIntensity').values('SumIntensity')[:1]
subquery1 = A.objects.filter(sub_filter0).values('id','ARelation__B__Category_id').annotate(**annotation0).order_by('SumIntensity').values('SumIntensity')[:1]
subquery2 = B.objects.filter(sub_filter1).values('Category_id').annotate(**annotation1).values('BOccurrence')[:1]
result = A.objects.values(
        'id','id','ARelation__B__Category_id'
    ).annotate(
        **annotation0
    )
result = result.annotate(MaxAIntensity=Subquery(subquery0))
result = result.annotate(MinAIntensity=Subquery(subquery1))
result = result.annotate(BOccurrence=Subquery(subquery2))
result = result.annotate(
        AOccurrence=Count('id', distinct=False)
)

我该如何解决这个问题?

还有其他有效的替代品吗?

0 个答案:

没有答案