我刚开始使用mongo,但对关系数据库有丰富的经验。
我有大约85000个事件托管在位置,每个事件都有一个相关的权重。对于热图,我现在需要对纬度/经度区域内事件的累积权重进行分组。
在mongo中,它目前看起来是这样的(没有索引,尝试了没有成功):
events: {
latitude: Number,
longitude: Number,
weight: Number
}
db.events.mapReduce(function() {
emit({
latitudeGroup: Math.floor(this.latitude / 1.2),
longitudeGroup: Math.floor(this.longitude / 1.8)
}, this.weight);
}, function(key, values) {
return Array.sum(values)
}, { out: 'inline' })
请注意,1.2和1.8是任意的和动态的,缓存每个可能的组合的结果将非常消耗内存。查询需要1500ms,这对于实时web应用程序来说太长了。
来自关系世界,我在Postgres:
中尝试了同样的方法。CREATE TABLE event (
id BIGSERIAL NOT NULL PRIMARY KEY,
latitude NUMERIC NOT NULL,
longitude NUMERIC NOT NULL,
weight INTEGER NOT NULL
);
SELECT floor(latitude / 1.2) AS latitudeGroup, floor(longitude / 1.8) AS longitudeGroup, SUM(weight) FROM event GROUP BY latitudeGroup, longitudeGroup;
这需要一个更可接受的400ms,而不使用任何Postgres的GiST功能。
我只是想知道我是否错过了一些关于蒙古的东西。我已经研究了聚合框架,但不认为我正在做的是可能的。
我将非常高兴,如果有一些方法使这个工作与合理的性能。这是我正在开发的原型的一个关键功能,在这个阶段,数据库切换不会太昂贵。
首先,您应该使用index进行测试。
您是否也尝试过使用聚合框架而不是MapReduce?
db.events.aggregate([
{ $group : {
_id : { "latitude" : "$latitude", "longitude" : "$longitude" } ,
weight : { "$sum" : { $multiply : ["$weight",1.2]} }
}}
])
聚合框架使用与数据库核心查询引擎相同的机制(不像使用V8引擎的MapReduce)
你可以试试下面的方法,看看是否有效。
db.events.aggregate([
{ $project : {
weight:1,
lat: {$divide:["$latitude",1.2]},
long: {$divide:["$longitude",1.8]}
}},
{ $group : {
_id : { "lat" : "$lat", "long" : "$long" } ,
weight : { "$sum" : "$weight"} }
}}
])