0

我为mongodb写了一个mapreduce,但结果有一些问题

日期:

mongos> db.perGoods.find()

{ "_id" : ObjectId("514bf6428f43a9fee9cef526"), "id" : 1, "goods_id" : "1234", "keywords" : [   {   "keyword" : "lianyiqun",    "price" : 3.52 },   {   "keyword" : "nvzhuang",     "price" : 4.27 },   {   "keyword" : "chunkuan",     "price" : 3.12 },   {   "keyword" : "chaoliu",  "price" : 8.32 },   {   "keyword" : "duanzhuang",   "price" : 4.92 } ] }
{ "_id" : ObjectId("514bf65d8f43a9fee9cef527"), "id" : 2, "goods_id" : "5678", "keywords" : [   {   "keyword" : "lianyiqun",    "price" : 9.26 },   {   "keyword" : "nvzhuang",     "price" : 4.52 } ] }
{ "_id" : ObjectId("514bf6768f43a9fee9cef528"), "id" : 3, "goods_id" : "5612", "keywords" : [   {   "keyword" : "lianyiqun",    "price" : 7.42 },   {   "keyword" : "nvzhuang",     "price" : 6.52 } ] }
{ "_id" : ObjectId("514bf6968f43a9fee9cef529"), "id" : 4, "goods_id" : "9612", "keywords" : [   {   "keyword" : "lianyiqun",    "price" : 3.12 },   {   "keyword" : "nvzhuang",     "price" : 6.57 },   {   "keyword" : "chunzhuang",   "price" : 5.55 } ] }

地图功能:

mongos> var mapFunction = function() {
...                        for (var index = 0; index < this.keywords.length; index++) {
...                            var key = this.goods_id;
...                            var value = {
...                                          count: 1,
...                                          price: this.keywords[index].price
...                                        };
...                            emit(key, value);
...                        }
...                     };

减少功能:

mongos> var reduceFunction = function(key, priceCountObjects) {
...                           reducedValue = { count: 0, sumprice: 0 };
... 
...                           for (var index = 0; index < priceCountObjects.length; index++) {
...                               reducedValue.count += priceCountObjects[index].count;
...                               reducedValue.sumprice += priceCountObjects[index].price;
...                           }
... 
...                           return reducedValue;
...                       };

编码:

mongos> db.perGoods.mapReduce(
...                      mapFunction,
...                      reduceFunction,
...                      { out: "map_reduce_test" }
...                    )
{
    "result" : "map_reduce_test",
    "timeMillis" : 5,
    "counts" : {
        "input" : 4,
        "emit" : 12,
        "reduce" : 4,
        "output" : 4
    },
    "ok" : 1,
}

结果:

mongos> db.map_reduce_test.find()
{ "_id" : "1234", "value" : { "count" : 5, "sumprice" : 24.15 } }
{ "_id" : "5612", "value" : { "count" : 2, "sumprice" : 13.94 } }
{ "_id" : "5678", "value" : { "count" : 2, "sumprice" : 13.78 } }
{ "_id" : "9612", "value" : { "count" : 3, "sumprice" : 15.240000000000002 } }
mongos> 

为什么最后一个结果是 15.240000000000002?

4

1 回答 1

0

由于 MongoDB 中的 map/reduce 是基于 JavaScript 的,所以它使用 JavaScript 的数字运算,本质上是一种双精度IEEE 754 浮点运算

浮点数(本质上,有关详细信息,请参阅维基百科文章)存储为

mantissa * base ^ exponent

在这种情况下,基数为 2(称为 10 基浮点数decimal),如果值的精度有限,则某些数字(包括有理数)根本无法以这种格式精确表示。

按照目前的情况,您最好的选择可能是在操作结束时进行舍入。不幸的是,并非所有货币都有两位小数,因此国际化可能会变得很痛苦,并且仍然存在舍入变得重要的风险 - 可以肯定的是,请确保您知道每个计算机科学家应该了解的关于浮点运算的知识

您也可以在 10gen 的 Jira 中为这个功能投票

于 2013-03-22T08:58:06.273 回答