0

我有一个包含分析数据的集合(目前拥有超过1000万个文档)。从clicks收集文档的 例子:重新设计数据库以消除聚合

{ 
    serverId: 'srv1', 
    dateVisited: '2014-12-24', 
    campaignId: 'c1', 
    ... 
    landingpageClicks: [ 
    {...}, 
    {...} 
    ], 
    offerTrackings: [ 
    { 
     amount: 10 
    }, 
    { 
     amount: 22 
    } 
    { 
     amount: 18 
    } 
    ] 
} 

我需要拉从这个集合的报告。用户可以请求通过多个字段进行分组,例如按日期组,然后通过serverId,然后通过campaignId和报告应该是这样的:

2014-12-24 | 50 lp clicks | 21 offer clicks | $600 // srv1 + srv2 
    srv1  | 20 lp clicks | 11 offer clicks | $400 // campaign1 + campaign2 
    campaign1 | 10 lp clicks | 6 offer clicks | $100 
    campaign2 | 10 lp clicks | 5 offer clicks | $300 
    srv2  | 30 lp clicks | 10 offer clicks | $200 // campaign3 + campaign4 
    campaign3 | 20 lp clicks | 4 offer clicks | $100 
    campaign4 | 10 lp clicks | 6 offer clicks | $100 

目前我使用下面的查询拉报告,但它是极其缓慢:

db.clicks.aggregate([ 
    {$match: {'_id.dateVisited': '2014-12-24'}}, 
    {$group:{ 
    _id: '$_id.dateVisited', 
    totalLandingpageClicksCount: {$sum: '$value.landingpageClicksCount'}, 
    totalOfferTrackingsCount: {$sum: '$value.offerTrackingsCount'}, 
    totalOfferTrackingsAmount: {$sum: '$value.offerTrackingsAmount'} 
    }} 
]) 

我的想法是为每个可能的字段组合创建单独的集合,并使用find({<search + group fields>})而不是聚合。即如果用户请求特定日期间隔,由serverId分组,然后由campaignId报告,下面的查询将被使用:

//example of doc in dateVisited_serverId collection 
{ 
    _id: { 
    dateVisited: '...', 
    serverId: '..' 
    }, 
    value: { 
    <counts> 
    } 
} 
// get stats for date, grouped by serverId 
db.dateVisited_serverId.find({ 
'_id.dateVisited': { 
    '$gte': dateFrom, 
    '$lte': dateTo 
} 
}) 


//example of doc in dateVisited_serverId_campaignId collection 
{ 
    _id: { 
    dateVisited: '...', 
    serverId: '..', 
    campaignId: '..' 
    }, 
    value: { 
    <counts> 
    } 
} 
// get stats for date, grouped by serverId and then by campaignId 
db.dateVisited_serverId_campaignId.find({ 
dateVisited: { 
    '$gte': dateFrom, 
    '$lte': dateTo 
}, 
serverId: {$in: [<server ids from previous query>]} 
}) 

它的工作,但clicks收集有18场,所以我必须要产生集合来实现我的想法。

这样我需要为我的数据库找到另一个设计。

[更新]真正的文件的例子:

{ 
    "_id": { 
    "dateVisited": ISODate("2014-11-05T00:00:00.0Z"), 
    "campaignId": "4c29dc888be98a9488e6876133852c72", 
    "landingpageId": "c5557aedab04ad1444b0ee28b5ddaab9", 
    "offerId": null, 
    "trafficAccountId": "84d06369b9872e9a2685483b7a532a10", 
    "serverId": "32", 
    "browser": "Safari", 
    "platform": "Android", 
    "c1": "chat", 
    "c2": "au", 
    "c3": "12b-ad1a", 
    "c4": "mtv2", 
    "city": "Perth", 
    "country": "Australia", 
    "deviceType": "mobile", 
    "isp": "Telstra Internet", 
    "netspeedId": NumberLong(3), 
    "set": "" 
    }, 
    "value": { 
    "lpCount": 2, 
    "offersCount": 0, 
    "grandConversionCount": 0, 
    "grandConversionAmount": 0 
    } 
} 
+1

一天有多少份文件?为什么在'_id.dateVisited'上进行分组而不是在'null'或其他常量值上进行分组 - 因为'$ match',所有文档都属于同一个组。与最简单的情况相比,展示更复杂/更逼真的例子会很好,因为它对流水线有很大的影响。为什么你不使用日期字段的日期?比起一个字符串,它会更快。你有什么指标,具体是什么?你需要'_id.dateVisited'上的索引。你能给我们解释一个缓慢的聚合吗? – wdberkeley

+0

〜10 000每天。在'_id.dateVisited'上分组 - 因为我需要按日期分组。在实际收集日期字段中使用。我有'_id.dateVisited'索引 - $匹配工作相当快。但是如果用户选择1年作为日期范围,那么$ group必须处理'365 * 1000 =〜3,650,000'个文档。这是非常缓慢的 –

回答

0

,如果您有任何索引你没有提到。如果您不请在dateVisited上制作和索引,并再次检查您的表现。

根据您网站的流量,您可能会在正常使用期间删除索引,因为它会使插入速度变慢并在您需要创建报告时进行构建。

+0

是的,我有索引,但$组不使用索引数据。我的聚合的瓶颈是$组,而不是$匹配 –