我有许多事件文档,每个事件都有若干字段,但与我的查询相关的字段是:
- person_id - 触发事件的人员的引用 - event - 用于识别事件的字符串键 - occurred_at - 事件发生的UTC时间
我的目标是:
- 对于事件键列表(例如 `['event_1','event_2', 'event_3']`),获取执行每个事件以及之前所有事件的人数计数,按顺序排列。即: - 执行 event_1 的人数 - 执行 event_1 后,再执行 event_2 的人数 - 执行 event_1、event_2 再执行 event_3 的人数 - 等等 - 次要目标是能够获取每个事件的平均 occurred_at 日期,以便我可以计算每个事件之间的平均时间差。
我最好的解决方案是以下两个映射规约:
并且:
我希望能够通过聚合框架实时实现这个目标,但是我找不到任何方法来做到。对于数万条记录,这需要花费10几秒的时间,虽然我可以以增量方式运行它,这意味着对于新数据来说足够快,但是如果我想修改原始查询(如更改事件链),则无法在单个请求中完成,我希望它能够完成。
使用Cursor.forEach(),我成功地在这方面取得了巨大的进展(基本上消除了第一个映射减少的要求)。
- person_id - 触发事件的人员的引用 - event - 用于识别事件的字符串键 - occurred_at - 事件发生的UTC时间
我的目标是:
- 对于事件键列表(例如 `['event_1','event_2', 'event_3']`),获取执行每个事件以及之前所有事件的人数计数,按顺序排列。即: - 执行 event_1 的人数 - 执行 event_1 后,再执行 event_2 的人数 - 执行 event_1、event_2 再执行 event_3 的人数 - 等等 - 次要目标是能够获取每个事件的平均 occurred_at 日期,以便我可以计算每个事件之间的平均时间差。
我最好的解决方案是以下两个映射规约:
db.events.mapReduce(function () {
emit(this.person_id, {
e: [{
e: this.event,
o: this.occurred_at
}]
})
}, function (key, values) {
return {
e: [].concat.apply([], values.map(function (x) {
return x.e
}))
}
}, {
query: {
account_id: ObjectId('52011239b1b9229f92000003'),
event: {
$in: ['event_a', 'event_b', 'event_c','event_d','event_e','event_f']
}
},
out: 'people_funnel_chains',
sort: { person_id: 1, occurred_at: 1 }
})
并且:
db.people_funnel_chains.mapReduce(function() {
funnel = ['event_a', 'event_b', 'event_c','event_d','event_e','event_f']
events = this.value.e;
for (var e in funnel) {
e = funnel[e];
if ((i = events.map(function (x) {
return x.e
}).indexOf(e)) > -1) {
emit(e, { c: 1, o: events[i].o })
events = events.slice(i + 1, events.length);
} else {
break;
}
}
}, function(key,values) {
return {
c: Array.sum(values.map(function(x) { return x.c })),
o: new Date(Array.sum(values.map(function(x) { return x.o.getTime() }))/values.length)
};
}, { out: {inline: 1} })
我希望能够通过聚合框架实时实现这个目标,但是我找不到任何方法来做到。对于数万条记录,这需要花费10几秒的时间,虽然我可以以增量方式运行它,这意味着对于新数据来说足够快,但是如果我想修改原始查询(如更改事件链),则无法在单个请求中完成,我希望它能够完成。
使用Cursor.forEach(),我成功地在这方面取得了巨大的进展(基本上消除了第一个映射减少的要求)。
var time = new Date().getTime(), funnel_event_keys = ['event_a', 'event_b', 'event_c','event_d','event_e','event_f'], looking_for_i = 0, looking_for = funnel_event_keys[0], funnel = {}, last_person_id = null;
for (var i in funnel_event_keys) { funnel[funnel_event_keys[i]] = [0,null] };
db.events.find({
account_id: ObjectId('52011239b1b9229f92000003'),
event: {
$in: funnel_event_keys
}
}, { person_id: 1, event: 1, occurred_at: 1 }).sort({ person_id: 1, occurred_at: 1 }).forEach(function(e) {
var current_person_id = e['person_id'].str;
if (last_person_id != current_person_id) {
looking_for_i = 0;
looking_for = funnel_event_keys[0]
}
if (e['event'] == looking_for) {
var funnel_event = funnel[looking_for]
funnel_event[0] = funnel_event[0] + 1;
funnel_event[1] = ((funnel_event[1] || e['occurred_at'].getTime()) + e['occurred_at'].getTime())/2;
looking_for_i = looking_for_i + 1;
looking_for = funnel_event_keys[looking_for_i]
}
last_person_id = current_person_id;
})
funnel;
new Date().getTime() - time;
我想知道是否有一些自定义的内存数据处理方式可以改善这个问题?从MongoDB中获取数十万条记录并将其加载到内存中(在不同的计算机上)会成为瓶颈,是否有我不知道的技术可以解决这个问题?