将大型SQL查询移动到NumPy

2024-09-17 02:14:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我的web应用程序中有一个非常大的MySQL查询,如下所示:

query = 
SELECT video_tag.video_id, (sum(user_rating.rating) * video.rating_norm) as score 

FROM video_tag 
JOIN user_rating ON user_rating.item_id = video_tag.tag_id
JOIN video ON video.id = video_tag.video_id 

WHERE item_type = 3 AND user_id = 1 AND rating != 0 AND video.website_id = 2 
AND rating_norm > 0 AND video_id NOT IN (1,2,3) GROUP BY video_id 
ORDER BY score DESC LIMIT 20"

这个查询连接三个表(video、video_tag和user_rating),对结果进行分组,并进行一些基本的数学运算来计算每个视频的分数。由于表很大,这需要大约2秒才能运行。在

与其让SQL完成所有这些工作,我怀疑使用NumPy数组进行这种计算会更快。“video”和“video_tag”中的数据是恒定的-所以我只需将这些表加载到内存中一次,而不必每次ping SQL。在

然而,虽然我可以将这三个表加载到三个单独的数组中,但是我要花大量时间复制上面的查询(特别是JOIN和groupby parts)。有没有人有过使用NumPy数组复制SQL查询的经验?在

谢谢!在


Tags: andnumpyidnormsqlbyontag
1条回答
网友
1楼 · 发布于 2024-09-17 02:14:40

使这个练习尴尬的是NumPy数组的单一数据类型约束。例如,groupby操作隐式地要求(至少)一个连续值的字段/列(用于聚合/求和),以及一个用于分区或分组依据的字段/列。在

当然,NumPyrecarray可以表示一个2D数组(或SQL表),对每一列使用不同的数据类型(也称为“Field”),但我发现这些复合数组的使用非常麻烦。所以在下面的代码片段中,我只使用了传统的ndarray类来复制OP问题中突出显示的两个SQL操作。

要在NumPy中模拟SQL JOIN

首先,创建两个NumPy数组(A&B),每个数组表示一个SQL表。A的主键在第1列;B的外键也在第1列中。在

import numpy as NP
A = NP.random.randint(10, 100, 40).reshape(8, 5)
a = NP.random.randint(1, 3, 8).reshape(8, -1)    # add column of primary keys      
A = NP.column_stack((a, A))

B = NP.random.randint(0, 10, 4).reshape(2, 2)
b = NP.array([1, 2])
B = NP.column_stack((b, B))


现在(尝试)使用NumPy array对象复制JOIN

^{pr2}$


要在NumPy中模拟SQL GROUP BY

def group_by(AB, col_id) :
    '''
    returns 2D NumPy array aggregated on the unique values in column specified by col_id;
    pass in a 2D NumPy array and the col_id (integer) which holds the unique values to group by
    '''
    uv = NP.unique(AB[:,col_id]) 
    temp = []
    for v in uv :
        ndx = AB[:,0] == v          
        temp.append(NP.sum(AB[:,1:][ndx,], axis=0))
    temp = NP. row_stack(temp)
    uv = uv.reshape(-1, 1)
    return NP.column_stack((uv, temp))



对于测试用例,它们返回正确的结果:

>>> A
  array([[ 1, 92, 50, 67, 51, 75],
         [ 2, 64, 35, 38, 69, 11],
         [ 1, 83, 62, 73, 24, 55],
         [ 2, 54, 71, 38, 15, 73],
         [ 2, 39, 28, 49, 47, 28],
         [ 1, 68, 52, 28, 46, 69],
         [ 2, 82, 98, 24, 97, 98],
         [ 1, 98, 37, 32, 53, 29]])

>>> B
  array([[1, 5, 4],
         [2, 3, 7]])

>>> join(A, B)
  array([[  1.,  92.,  50.,  67.,  51.,  75.,   5.,   4.],
         [  2.,  64.,  35.,  38.,  69.,  11.,   3.,   7.],
         [  1.,  83.,  62.,  73.,  24.,  55.,   5.,   4.],
         [  2.,  54.,  71.,  38.,  15.,  73.,   3.,   7.],
         [  2.,  39.,  28.,  49.,  47.,  28.,   3.,   7.],
         [  1.,  68.,  52.,  28.,  46.,  69.,   5.,   4.],
         [  2.,  82.,  98.,  24.,  97.,  98.,   3.,   7.],
         [  1.,  98.,  37.,  32.,  53.,  29.,   5.,   4.]])

>>> group_by(AB, 0)
  array([[   1.,  341.,  201.,  200.,  174.,  228.,   20.,   16.],
         [   2.,  239.,  232.,  149.,  228.,  210.,   12.,   28.]])

相关问题 更多 >