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

是的,我有索引,但$組不使用索引數據。我的聚合的瓶頸是$組,而不是$匹配 –