Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 如何为多个文档加速大型数组的聚合 总结_Mongodb_Pymongo - Fatal编程技术网

Mongodb 如何为多个文档加速大型数组的聚合 总结

Mongodb 如何为多个文档加速大型数组的聚合 总结,mongodb,pymongo,Mongodb,Pymongo,我有500万用户的每小时数据(10年=87600小时),例如每个用户每小时的点击次数。我试图聚合以获得每小时(所有用户)的总点击数,但它非常慢(超过5天) 非技术性解释 我问题的数据来源于熊猫。每个用户都由一个用户ID标识,并有若干条与之相关的信息。为了说明的目的,我将考虑用户使用 USER ID 15512。我有一个User\u视图DataFrame,它有两列: Hour Views ----- ------ 11 5 15512 11 82215

我有500万用户的每小时数据(10年=87600小时),例如每个用户每小时的点击次数。我试图聚合以获得每小时(所有用户)的总点击数,但它非常慢(超过5天)

非技术性解释 我问题的数据来源于熊猫。每个用户都由一个
用户ID
标识,并有若干条与之相关的信息。为了说明的目的,我将考虑用户使用<代码> USER ID 15512。我有一个
User\u视图
DataFrame,它有两列:

Hour     Views
-----   ------
11           5
15512       11
82215        2
其中,
小时
从固定的开始日期(2008年1月1日)开始计算。此表中仅包括用户具有非零
视图的小时数。不幸的是,对于大多数用户来说,数据帧包含超过80000行

第二条数据是
User\u点击次数
DataFrame,每个用户每小时点击次数:

Hour     Clicks
-----   ------
5511         1
34412        3
51241        2
66615       10
我想在所有用户中聚合
视图
,以获得每小时的总视图数(在所有用户中)。我希望对
单击操作执行相同操作

技术说明 为此,我使用以下模式将上述数据存储到MongoDB中:

schema = [
    {
        'User_ID': 15512,
        'User_Name': 'Jack Daniels',
        'Information_Type': 'Views',
        'User_Views': [
            {'Hour': 11, 'Views': 5},
            {'Hour': 15512, 'Views': 11},
            {'Hour': 82215, 'Views': 2},
        ]
    },
    {
        'User_ID': 15512,
        'User_Name': 'Jack Daniels',
        'Information_Type': 'Clicks',
        'User_Clicks': [
            {'Hour': 5511, 'Clicks': 1},
            {'Hour': 34412, 'Clicks': 3},
            {'Hour': 51241, 'Clicks': 2},
            {'Hour': 66615, 'Clicks': 10},
        ]
    },
    # The above is then repeated for every User_ID.
]
为了在模式中获得
User\u视图
,我在Python中的
User\u视图
DataFrame上做了
df.to\u dict(orient='records')
。类似地,对于
用户单击

理想情况下,我有
User\u单击
User\u视图
位于同一文档中,但我无法为该设置快速创建聚合,因此我从视图中拆分单击,如上面的模式所示

我已经为
信息类型
编制了索引。我已经设置了
allowDiskUse=True

我用于聚合视图的管道是:

pipeline = [
    # Get only Views documents
    {"$match": {"Information_Type": "Views"}},  

    # Return only Hours and Views
    {"$project": {"User_Views.Hour": 1, "User_Views.Views": 1}},   

    # Unwind/flatten User_Views, since it's an array of documents         
    {"$unwind": "$User_Views"},      

    # Group by Hour across all documents and sum the Views          
    {"$group": {"_id": "$User_Views.Hour", "Total_Views": {"$sum": "$User_Views.Views"}}}
类似的点击

问题和目标 目前,500万用户和87600小时的运行时间大约为一周

我试着做两件事:

1) 通过深入了解模式和管道的改进,减少运行时间


2) 理想情况下,使用模式时,每个用户的视图和单击不会被分割到两个文档中。

问题在于,您无法通过单个管道足够快地通过5mm用户X 87600条数据。当索引可以用来查找人口中相对较小的子集时,数据库(大多数)是非常棒的。当你想查看所有数据时,它们就没有那么好了。这个问题确实有地图/缩小的感觉

但在MongoDB中,实现这一点的一种方法是线程化并使用多个查询同时工作。每个线程的时间范围为
小时
,例如,在伪代码中:

nthreads = 20
incr = 87600 / nthreads 
curr = 0
while nthreads > 0:
    exec_query (curr, curr+incr)
    curr += incr
    nthreads--

exec_query(start, end):
   spawn{
db.foo.aggregate([
{$match: {'Information_Type': 'Views'}}

,{$project: {X: {$filter: {
        input: "$User_Views",
        as: "zz",
        cond: {$and:[
{$gte: ['$$zz.Hour', start]}
,{$lt: ['$$zz.Hour', end]}
                     ]
                }
            }}
    }}

,{$unwind: "$X"}
,{$group: {_id:"$X.Hour", total: {$sum: "$X.Views"} }}
]);


会有大量数据读取,是的,
$filter
操作符最终会抛出大量数据,但您将获得更多并行运行的
$group
操作。

问题是,您无法通过单个管道足够快地通过5mm用户X 87600条数据。当索引可以用来查找人口中相对较小的子集时,数据库(大多数)是非常棒的。当你想查看所有数据时,它们就没有那么好了。这个问题确实有地图/缩小的感觉

但在MongoDB中,实现这一点的一种方法是线程化并使用多个查询同时工作。每个线程的时间范围为
小时
,例如,在伪代码中:

nthreads = 20
incr = 87600 / nthreads 
curr = 0
while nthreads > 0:
    exec_query (curr, curr+incr)
    curr += incr
    nthreads--

exec_query(start, end):
   spawn{
db.foo.aggregate([
{$match: {'Information_Type': 'Views'}}

,{$project: {X: {$filter: {
        input: "$User_Views",
        as: "zz",
        cond: {$and:[
{$gte: ['$$zz.Hour', start]}
,{$lt: ['$$zz.Hour', end]}
                     ]
                }
            }}
    }}

,{$unwind: "$X"}
,{$group: {_id:"$X.Hour", total: {$sum: "$X.Views"} }}
]);

将有大量数据读取,是的,
$filter
操作符最终会抛出大量数据,但您将得到更多并行运行的
$group
操作