1

Я могу получить результат, который хочу, но хотел бы знать, есть ли способы уменьшить время выполнения агрегации, которую я делаю.Сокращение времени выполнения агрегации

Во-первых, вот мои данные:

............................................ ...............................................

стол activites:

{ "_id" : ObjectId("58872a885bd87fa3b7e736cf"), "jour" : "2015-01-01", "sgt_id" : 1, "produit_id" : 1, "affichages" : 1525, "clics" : 16, "consultations" : 20, "ajoutsPanier" : 1, "unites" : 0, "commandes" : 0, "recettes" : 0, "demandeBrute" : 0, "txDispo" : "NULL" } 
{ "_id" : ObjectId("58872a885bd87fa3b7e736d0"), "jour" : "2015-01-01", "sgt_id" : 1, "produit_id" : 3, "affichages" : 519, "clics" : 6, "consultations" : 7, "ajoutsPanier" : 0, "unites" : 0, "commandes" : 0, "recettes" : 0, "demandeBrute" : 0, "txDispo" : "NULL" } 
{ "_id" : ObjectId("58872a885bd87fa3b7e736d1"), "jour" : "2015-01-01", "sgt_id" : 1, "produit_id" : 5, "affichages" : 421, "clics" : 5, "consultations" : 6, "ajoutsPanier" : 1, "unites" : 0, "commandes" : 0, "recettes" : 0, "demandeBrute" : 0, "txDispo" : "NULL" } 

и 14 миллионов записей, как, что ...

......................... .................................................. .......

стол categories2:

{ "_id" : ObjectId("5888609e5bd87fa3b7c72551"), "categorie_id" : 108, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Accessories", "categorie" : "Accessories", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 867, 2943, 6443, 6447, 6525 ] } 
{ "_id" : ObjectId("5888609e5bd87fa3b7c7259f"), "categorie_id" : 110, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Jewelry & watches", "categorie" : "Jewelry & watches", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 2849, 2853, 2857, 2867, 2873, 2885, 2891, 2893, 2897, 2903, 2907, 2913, 2919, 2927, 2945, 2957, 2963, 3531, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3549, 3551, 3553, 3555, 3557, 3559, 3561, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3579, 3581, 3583, 3585, 3587, 3589, 3591, 3593, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609, 3611, 3613, 3615, 3617, 3619, 3621, 3623, 3625, 3627, 3629, 3631, 6441, 6443, 6445, 6449, 6451, 6453, 6455, 6457, 6459, 6461, 6463, 6465, 6467, 6469, 6471, 6473, 6475, 6477, 6479, 6481, 6483, 6485, 6487, 6489, 6491, 6493, 6495, 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, 6513, 6515, 6517, 6519, 6521, 6523, 6527 ] } 
{ "_id" : ObjectId("5888609e5bd87fa3b7c725a2"), "categorie_id" : 106, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Clothing", "categorie" : "Clothing", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 1485, 1487, 1489, 1491, 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509, 1511, 1513, 1515, 1517, 1519, 1521, 1523, 1525, 1527, 1681, 1683, 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1707, 1709, 1711, 1713, 1715, 1717, 1721, 1723, 1725, 1727, 1729, 1731, 1733, 1735, 1737, 1739, 1741, 1743, 1745, 1747, 1749, 1751, 1753, 1755, 1757, 1759, 1761, 1763, 1765, 1767, 1769, 1771, 1773, 1775, 1777, 1779, 1781, 1783, 1785, 1787, 1789, 1791, 1793, 1795, 1797, 1799, 1801, 1803, 1805, 1807, 1809, 1811, 1813, 1815, 1817, 1819, 1821, 1823, 1825, 1827, 1829, 1831, 1833, 1835, 1837, 1839, 1841, 1843, 1845, 1847, 1849, 1851, 1853, 1855, 1857, 1859, 1861, 1863, 1867, 1869, 1871, 1873, 1875, 1877, 1879, 1881, 2845, 2851, 2855, 2859, 2863, 2869, 2871, 2877, 2879, 2881, 2887, 2895, 2905, 2909, 2911, 2917, 2923, 2925, 2929, 2933, 2935, 2939, 2941, 2947, 2951, 2953, 2959, 3849, 3851, 3853, 3855, 3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3885, 3887, 3889, 3891, 3893, 3895, 3897, 3899, 3901, 3903, 3905, 4969, 4971, 4973, 4975, 4977, 4979, 4981, 4983, 4985, 4987, 4989, 4991, 4993, 4995, 4997, 4999, 5001, 5003, 5005, 5007, 5009, 5011, 5013, 5015, 5017, 5019, 5021, 5023, 5025, 5027, 5029, 5031, 5033, 5035, 5037, 5039, 5041, 5043, 5045, 5047, 5049, 5743, 5745, 5747, 5749, 5751, 5753, 5755, 5757, 5759, 5761, 5763, 5765, 5767, 5769, 5771, 5773, 5775, 5777, 5779, 5781, 5783, 5785, 5787, 5789, 5791, 5793, 5795, 5797, 5799, 5801, 5803, 5805, 5807, 5809, 5811, 5813, 5815, 5817, 5819, 5821, 5823, 5825, 5827, 5829, 5831, 5833, 5835, 5837, 5839, 5841, 5843, 5845, 5847, 5849, 5851, 5853, 5855, 5857, 5859, 5861, 5863, 5865, 5867, 5869, 5871, 5873, 5875, 5877, 5879, 5881, 5883, 5885, 5887, 5889, 5891, 5893, 5895, 5897, 5899, 5901, 5903, 5905, 5907, 5909, 5911, 5913, 5915, 5917, 5919, 5921, 5923, 5925, 5927, 5929, 5931, 5933, 5935, 5937, 5939, 5941, 5943, 5945, 5947, 5949, 5951, 5953, 5955, 5957 ] } 
{ "_id" : ObjectId("5888609e5bd87fa3b7c725c0"), "categorie_id" : 107, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Shoes", "categorie" : "Shoes", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 1719, 1865, 2861, 2875, 2883, 2889, 2899, 2901, 2915, 2921, 2931, 2937, 2949, 2955, 2961, 5487, 5489, 5491, 5493, 5495, 5497, 5499, 5501, 5503, 5505, 5507, 5509, 5511, 5513, 5515, 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, 5533, 5535, 5537, 5539, 5541, 5543, 5545, 5547, 5549, 5551, 5553, 5555, 5557, 5559, 5561, 5563, 5565, 5567, 5569 ] } 
{ "_id" : ObjectId("5888609e5bd87fa3b7c725ea"), "categorie_id" : 109, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Handbags", "categorie" : "Handbags", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 845, 847, 849, 851, 853, 855, 857, 859, 861, 863, 865, 2847, 2865 ] } 
{ "_id" : ObjectId("5888609e5bd87fa3b7c725f9"), "categorie_id" : 111, "type" : 1, "niveau" : 2, "hierarchie" : 2, "cat_id_client" : "Health & beauty", "categorie" : "Health & beauty", "label" : "NULL", "createur_id" : "NULL", "produit_id" : [ 3249, 3251, 3253, 3255, 3257, 3259, 3261, 3263, 3265 ] } 

То, что я хотел бы иметь в результате в том, что:

{ "_id" : 106, "categorie" : "Clothing", "consultations" : 185507, "recettes" : 1592183.49 } 
{ "_id" : 107, "categorie" : "Shoes", "consultations" : 53636, "recettes" : 277869.81 } 
{ "_id" : 110, "categorie" : "Jewelry & watches", "consultations" : 47071, "recettes" : 116746.03 } 
{ "_id" : 109, "categorie" : "Handbags", "consultations" : 7149, "recettes" : 90921.05 } 
{ "_id" : 111, "categorie" : "Health & beauty", "consultations" : 4542, "recettes" : 7671.51 } 
{ "_id" : 108, "categorie" : "Accessories", "consultations" : 1718, "recettes" : 15689.43 } 

Для каждой категории, имеют сумму consultations и recettes для каждого продукта который принадлежит этой категории.


Мой код, чтобы получить этот результат:

db.categories2.aggregate([ 
    { 
     $match: { 
      type: 1, 
      niveau: 2, 
      hierarchie: 2 
     } 
    }, 
    { 
     "$unwind": "$produit_id" 
    }, 
    { 
     $lookup: { 
      from: "activites", 
      localField: "produit_id", 
      foreignField: "produit_id", 
      as: "activites" 
     } 
    }, 
    { 
     $project: { 
      _id: 1, 
      categorie_id: 1, 
      categorie: 1, 
      produit_id: 1, 
      activites : { 
       $filter: { 
        input: "$activites", 
        as: "activite", 
        cond : { $and: [ 
         { $gte: [ "$$activite.jour", "2016-09-01" ] }, 
         { $lte: [ "$$activite.jour", "2016-11-03" ] }, 
         { $eq : [ "$$activite.sgt_id", 1] } 
        ] } 
       } 
      } 
     } 
    }, 
    { 
     $unwind: "$activites" 
    }, 
    { 
     $group: { 
      _id: "$categorie_id", 
      consultations: { $sum: "$activites.consultations" }, 
      recettes: { $sum: "$activites.recettes" } 
     } 
    }, 
    { 
     $sort: { "consultations" : -1 } 
    } 
]) 

Объяснение:

  • Матч категории, заданные пользователем. Каждая категория содержит produits поля, которое является массив продуктов ID
  • Расслабиться этим массив
  • Для каждой строки (так что каждый продукт), смотреть в activites таблицу, чтобы получить consultations и recettes поля
  • Фильтра на видах спорта приводит к совпадают даты, заданные пользователем
  • Анвайнд все виды спорта, найденные иметь одну строку на activité в день
  • Group результат по categorie_id сделать сумму consultations и recettes

Проблема заключается в том:

  • $lookup из activites занимает приблизительно 1 ~ 2 секунды (я не думаю, что мы можем сделать лучше, потому что из 14 миллионов записей этой таблицы)
  • последний $group take something like 5 seconds to group all the categorie_id` и сделать сумму

Таким образом, в общей сложности, запрос делается в 7,5 секунд.

Есть ли способ сделать лучше, с другим видом просьбы, может быть?

Большое спасибо за помощь!

UPDATE: Я думал, может быть, есть способ группы детей activites после $project, и поэтому избежать $unwind и $group после этого?

+0

Какова ваша версия MongoDB сервер? – chridam

+0

Привет, Chridam! Я в 3.4.1 – Toma

ответ

0

я добиваюсь, чтобы сократить время выполнения до 300 мс, путем расщепления двух функций и делает сумму вручную в Javascript:

var before = new Date() 

var pdtCat = db.categories2.aggregate([ 
    { 
     $match: { 
      type: 1, 
      niveau: 2, 
      hierarchie: 2 
     } 
    }, 
    { 
     "$unwind": "$produit_id" 
    } 
]); 

var produits_id = []; 
var categories = []; 
var prev = []; 

pdtCat.forEach(produit => { 
    produits_id.push(produit.produit_id); 

    var index = prev.indexOf(produit.categorie_id); 

    if(index > -1) { 
     categories[index].produits_id.push(produit.produit_id); 
    } 
    else { 
     prev.push(produit.categorie_id); 
     categories.push({ 
      categorie_id: produit.categorie_id, 
      categorie: produit.categorie, 
      consultations: 0, 
      recettes: 0, 
      produits_id : [ produit.produit_id ] 
     }); 
    } 
}); 

var produits = db.activites.find({ 
    "jour" : { 
     $gte: "2016-09-01", 
     $lte: "2016-11-03" 
    }, 
    sgt_id: 1, 
    produit_id : { $in: produits_id } 
}).forEach(produit => { 
    for(var i=0; i < categories.length; i++) { 
     if(categories[i].produits_id.indexOf(produit.produit_id) > -1) { 
      categories[i].consultations += produit.consultations; 
      categories[i].recettes += produit.recettes; 
     } 
    }  
}); 

categories.sort(function(a, b) { 
    return b.consultations - a.consultations; 
}); 

categories.forEach(categorie => { 
    delete categorie.produits_id; 
    print(JSON.stringify(categorie)); 
}); 

var after = new Date() 
execution_mills = after - before