gpt4 book ai didi

mongodb - Mongodb Mapreduce - 半径内用户的热门场所

转载 作者:可可西里 更新时间:2023-11-01 10:01:12 25 4
gpt4 key购买 nike

我的 MapReduce 函数有问题 - 目标是在特定的纬度/经度范围内获取顶级场所列表,按 vid 分组,按不同的 user_id< 排序.

这是一个示例数据集:

  { "_id" : ObjectId("51f9234feb97ff0700000046"), "checkin_id" : 39286249, "created_at" : ISODate("2013-07-31T14:47:11Z"), "loc" : { "lat" : 42.3672, "lon" : -86.2681 }, "icv" : 1, "ipv" : 1, "vid" : 348442, "user_id" : 151556, "bid" : 9346, "pid" : 549 }
{ "_id" : ObjectId("51f9234b488fff0700000006"), "checkin_id" : 39286247, "created_at" : ISODate("2013-07-31T14:47:07Z"), "loc" : { "lat" : 55.6721, "lon" : 12.5576 }, "icv" : 1, "ipv" : 1, "vid" : 3124, "user_id" : 472486, "bid" : 7983, "pid" : 2813 }
...

这是我的 map 功能:

map1 = function() {
var tempDoc = {};
tempDoc[this.user_id] = 1;

emit(this.vid, {
users: tempDoc,
count: 1
});
}

并减少:

reduce1 = function(key, values) {

var summary = {
users: {},
total: 0
};

values.forEach(function (doc) {

// increment total for every value
summary.total += doc.count;

// Object.extend() will only add keys from the right object that do not exist on the left object
Object.extend(summary.users, doc.user);

});


return summary;
};

我的地理查询:

var d = Date("2013-07-31T14:47:11Z");
var geo_query = {loc: {$near: [40.758318,-73.952985], $maxDistance: 25}, "icv":1, "created_at": {$gte: d}};

最后是 mapReduce 查询:

var res = db.myColelction.mapReduce(map1, reduce1,  { out : { inline : 1 }, query : geo_query });

返回的结果与 reduce 函数匹配,但未命中 finalize1 函数:

...
{
"_id" : 609096,
"value" : {
"users" : {
"487586" : 1
},
"count" : 1
}
},
{
"_id" : 622448,
"value" : {
"users" : {
"313755" : 1,
"443180" : 1
},
"total" : 4
}
},
...

在这一点上,我认为我有一个很好的结果集,但是 $near 函数只扫描附近的 100 个 field ,我想扫描 ALL field (匹配的所有文档这个半径(25 米),并查看所有 field - 将它们分组,并计算该时间段内的唯一用户数。我四处搜索,查看了文档,但我不确定是否有解决方案。有人接受吗?

对我来说,最终结果是按“总计”属性对结果进行排序和限制。理想情况下,我希望按总描述排序并限制为 15。

最佳答案

我会做以下事情。首先,你的坐标是错误的。 MongoDB 需要 longitude, latitude,最好是 GeoJSON 格式:

loc: { type: 'Point', coordinates: [-73.952985, 40.758318] },

MongoDB 不关心 latlon 字段名称,并将忽略它们。

但是您还应该避免使用 Map/Reduce,因为它既慢又复杂。相反,我们可以使用聚合框架来做类似的事情:

db.so.aggregate( [
// search for all the (well, million) venues within **250**km
{ $geoNear: {
near: { type: 'Point', coordinates: [-73.952985, 40.758318] },
spherical: true,
distanceField: 'd',
maxDistance: 250 * 1000,
limit: 1000000
} },
// find only the items where icv=1
{ $match: { icv: 1 } },
// group by venue and user
{ $group: {
_id: { vid: '$vid', user_id: '$user_id' },
count: { $sum: 1 } }
},
// then regroup by just venue:
{ $group: {
_id: '$_id.vid',
users: { $addToSet: { user_id: '$_id.user_id', count: '$count' } },
total: { $sum: '$count' }
} },
// now we sort by "total", desc:
{ $sort: { 'total': -1 } },
// and limit by 15:
{ $limit: 15 }
] );

我使用 $geoNear 作为第一阶段,$icv 上的匹配作为第二阶段,因为 $geoNear index 会比 $icv 好很多(正如我猜测的那样,无论如何它只会有值 0 或 1)。

请注意,对于此示例,我使用的是 250 公里(250 * 1000 米)而不是 25 公里。

使用以下输入:

db.so.insert( { "_id" : ObjectId("51f9234feb97ff0700000046"), "loc" : { type: 'Point', coordinates: [ -73.2681, 40.3672 ] }, "vid" : 348442, "user_id" : 151556 } );
db.so.insert( { "_id" : ObjectId("51f9234b488fff0700000006"), "loc" : { type: 'Point', coordinates: [ -73.5576, 40.6721 ] }, "vid" : 3124, "user_id" : 472486 } );
db.so.insert( { "_id" : ObjectId("51f92345488fff0700000006"), "loc" : { type: 'Point', coordinates: [ -73.5576, 40.6721 ] }, "vid" : 3124, "user_id" : 47286 } );
db.so.insert( { "_id" : ObjectId("52f92345488fff0700000006"), "loc" : { type: 'Point', coordinates: [ -73.5576, 40.6721 ] }, "vid" : 3124, "user_id" : 47286 } );

你得到的结果是:

{
"result" : [
{
"_id" : 3124,
"users" : [
{ "user_id" : 472486, "count" : 1 },
{ "user_id" : 47286, "count" : 2 }
],
"total" : 3
},
{
"_id" : 348442,
"users" : [
{ "user_id" : 151556, "count" : 1 }
],
"total" : 1
}
],
"ok" : 1
}

与您想要的输出只有一个区别,那就是 user_id 不是计数的键,而是子文档中的一个额外字段。通常,您无法使用聚合框架将值更改为键或将键更改为值。

关于mongodb - Mongodb Mapreduce - 半径内用户的热门场所,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17973766/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com