Я пытаюсь преобразовать свой запрос агрегации в Map-Reduce один в MongoDB
(используя драйвер Ruby).В моем исходном запросе я ищу элементы на определенном расстоянии от точки, а затем группирую их по значению NEIGHBORHOOD
.
Образец документа
{
"_id":"5b01a2c77b61e58732920f86",
"YEAR":2004,
"NEIGHBOURHOOD":"Grandview-Woodland",
"LOC":{"type":"Point","coordinates":[-123.067654,49.26773386]}
}
Запрос агрегации
crime.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [ -123.0837633, 49.26980201 ]
},
"query": { "YEAR": 2004 },
"distanceField": "distance",
"minDistance": 10,
"maxDistance": 10000,
"num": 100000,
"spherical": true
}},
{ "$group": {
"_id": "$NEIGHBOURHOOD",
"count": { "$sum": 1 }
}}
])
Таким образом, фрагмент вывода выглядит следующим образом:
Вывод
{"_id"=>"Musqueam", "count"=>80}
{"_id"=>"West Point Grey", "count"=>651}
{"_id"=>"Marpole", "count"=>1367}
Теперь я пытаюсь сделать что-то подобное в MapReduce.В моем map function
я пытаюсь проверить, находятся ли документы на правильном расстоянии (основываясь на ответе НАСТОЯЩЕГО ВОПРОСА ) и, если это так, передать их reduce function
, в котором они будут засчитаны.Но что-то не так, и я не получаю желаемого результата - значения count
слишком велики.Что я делаю не так?
Функция карты
map = "function() {" +
"var rad_per_deg = Math.PI/180;" +
"var rm = 6371 * 1000;" +
"var dlat_rad = (this.LOC.coordinates[0] - (-123.0837633)) * rad_per_deg;" +
"var dlon_rad = (this.LOC.coordinates[1] - (49.26980201)) * rad_per_deg;" +
"var lat1_rad = -123.0837633 * rad_per_deg;" +
"var lon1_rad = 49.26980201 * rad_per_deg;" +
"var lat2_rad = this.LOC.coordinates[0] * rad_per_deg;" +
"var lon2_rad = this.LOC.coordinates[1] * rad_per_deg;" +
"var a = Math.pow(Math.sin(dlat_rad/2), 2) + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.pow(Math.sin(dlon_rad/2), 2);" +
"var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));" +
"if( rm * c < 10000) { " +
" emit(this.NEIGHBOURHOOD, {count: 1});" +
"}" +
"};"
Функция уменьшения
reduce = "function(key, values) { " +
"var sum = 0; " +
"values.forEach(function(f) { " +
" sum += f.count; " +
"}); " +
"return {count: sum};" +
"};"
Запрос
opts = {
query:{ "YEAR": 2004 },
:out => "results",
:raw => true
}
Выход
crime.find().map_reduce(map, reduce, opts)
{"_id"=>"", "value"=>{"count"=>2257.0}}
{"_id"=>"Arbutus Ridge", "value"=>{"count"=>6066.0}}
{"_id"=>"Central Business District", "value"=>{"count"=>110947.0}}