zoukankan      html  css  js  c++  java
  • Mongodb的mapreduce

    简单的看了一下mapreduce,我尝试不看详细的api去做一个group效果,结果遇到了很多问题,罗列在这里,如果别人也遇到了类似的bug,可以检索到结果。

    1. //先看person表的数据
    2. > db.person.find();
    3. { "_id" : ObjectId("593011c8a92497992cdfac10"), "name" : "xhj", "age" : 30, "address" : DBRef("address", ObjectId("59314b07e693aae7a5eb72ab")) }
    4. { "_id" : ObjectId("59301270a92497992cdfac11"), "name" : "zzj", "age" : 2 }
    5. { "_id" : ObjectId("593015fda92497992cdfac12"), "name" : "my second child", "age" : "i do not know" }
    6. { "_id" : ObjectId("592ffd872108e8e79ea902b0"), "name" : "zjf", "age" : 30, "address" : { "province" : "河南省", "city" : "南阳市", "building" : "桐柏县" } }
    7. //使用聚合来做一个group by
    8. > db.person.aggregate({$group : {_id: '$age', count : {$sum : 1}}})
    9. { "_id" : "i do not know", "count" : 1 }
    10. { "_id" : 2, "count" : 1 }
    11. { "_id" : 30, "count" : 2 }
    12. //下面尝试用map reduce来做同样的group by效果
    13. //很简单的逻辑 定义map函数 和reduce函数
    14.  
    15. > var m = function(){ emit(this.age,1) };
    16. > var r = function(key,values){
    17. ... var sum = 0;
    18. ... values.forEach(function(val){
    19. ... sum += val;
    20. ... });
    21. ... return sum;
    22. ... }
    23.  
    24. //然后在person上执行mapreduce 这样会报错 需要一个optionsOrOutString
    25. > db.person.mapReduce( m, r ).find();
    26. assert failed : need to supply an optionsOrOutString
    27. Error: assert failed : need to supply an optionsOrOutString
    28.     at Error (<anonymous>)
    29.     at doassert (src/mongo/shell/assert.js:11:14)
    30.     at assert (src/mongo/shell/assert.js:20:5)
    31.     at DBCollection.mapReduce (src/mongo/shell/collection.js:1343:5)
    32.     at (shell):1:11
    33. 2017-06-03T12:42:06.704+0800 E QUERY Error: assert failed : need to supply an optionsOrOutString
    34.     at Error (<anonymous>)
    35.     at doassert (src/mongo/shell/assert.js:11:14)
    36.     at assert (src/mongo/shell/assert.js:20:5)
    37.     at DBCollection.mapReduce (src/mongo/shell/collection.js:1343:5)
    38.     at (shell):1:11 at src/mongo/shell/assert.js:13
    39. //加了一个而空的option 又说要有一个string或者object的out参数
    40. > db.person.mapReduce( m, r,{} ).find();
    41. 2017-06-03T12:42:24.726+0800 E QUERY Error: map reduce failed:{
    42.    "errmsg" : "exception: 'out' has to be a string or an object",
    43.    "code" : 13606,
    44.    "ok" : 0
    45. }
    46.     at Error (<anonymous>)
    47.     at DBCollection.mapReduce (src/mongo/shell/collection.js:1353:15)
    48.     at (shell):1:11 at src/mongo/shell/collection.js:1353
    49. //我尝试定义一个变量 不行
    50. > var outstr;
    51. > db.person.mapReduce( m, r,{out:outstr} ).find();
    52. 2017-06-03T12:42:45.502+0800 E QUERY Error: map reduce failed:{
    53.    "errmsg" : "exception: 'out' has to be a string or an object",
    54.    "code" : 13606,
    55.    "ok" : 0
    56. }
    57.     at Error (<anonymous>)
    58.     at DBCollection.mapReduce (src/mongo/shell/collection.js:1353:15)
    59.     at (shell):1:11 at src/mongo/shell/collection.js:1353
    60. //后来我了解到out需要的一个collection 于是我加了一个字符串 'outt'作为保存数据的集合名字
    61.  
    62. > db.person.mapReduce( m, r,{out:'outt'} ).find();
    63. { "_id" : 2, "value" : 1 }
    64. { "_id" : 30, "value" : 2 }
    65. { "_id" : "i do not know", "value" : 1 }
    66. //此时outt中也保存了数据 我不明白的是 不定义out参数 不是应该可以直接find就可以了吗 为什么要多此一举呢
    67. > db.outt.find();
    68. { "_id" : 2, "value" : 1 }
    69. { "_id" : 30, "value" : 2 }
    70. { "_id" : "i do not know", "value" : 1 }

    因为遇到了这么多问题,所以看了Mongodb的文档(https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/),翻译并梳理了一下,总结如下:

    命令方式:

    1. db.runCommand(
    2.                {
    3.                  mapReduce: <collection>,
    4.                  map: <function>,
    5.                  reduce: <function>,
    6.                  finalize: <function>,
    7.                  out: <output>,
    8.                  query: <document>,
    9.                  sort: <document>,
    10.                  limit: <number>,
    11.                  scope: <document>,
    12.                  jsMode: <boolean>,
    13.                  verbose: <boolean>,
    14.                  bypassDocumentValidation: <boolean>,
    15.                  collation: <document>
    16.                }
    17.              )

    简单方式:

    1. db.collection.mapReduce(
    2.                          <map>,
    3.                          <reduce>,
    4.                          {
    5.                            out: <collection>,
    6.                            query: <document>,
    7.                            sort: <document>,
    8.                            limit: <number>,
    9.                            finalize: <function>,
    10.                            scope: <document>,
    11.                            jsMode: <boolean>,
    12.                            verbose: <boolean>,
    13.                            bypassDocumentValidation: <boolean>
    14.                          }
    15.                        )

    db.collection.mapReduce()使用起来更加方便一点,它的参数如下:

    Parameter

    Type

    Description

    map

    function

    A JavaScript function that associates or "maps" a value with akey and emits the key and value pair.

    一个根据查询数据生成键值对的js函数

    reduce

    function

    A JavaScript function that "reduces" to a single object all the values associated with a particular key.

    一个将特定的键的所有值 reduces成一个值的js函数。

    options

    document

    A document that specifies additional parameters todb.collection.mapReduce().

    一个配置方法参数的对象

    bypassDocumentValidation

    boolean

    Optional. Enables mapReduce to bypass document validation during the operation. This lets you insert documents that do not meet the validation requirements.

    可选是否绕过文档验证

    其中:

    Map函数:

    map函数负责将每个输入文档转换为零个或多个文档。 它可以访问范围参数中定义的变量,并具有以下原型:

    1. function() {
    2.    ...
    3.    emit(key, value);
    4. }
    • 在map函数中,在函数内使用this来引用当前文档。
    • map函功能应该是纯粹的,不应由于任何原因访问数据库。也不能对函数之外有任何影响。
    • map函数可以可选地调用emit(key,value)任意次数来创建将值与值相关联的输出文档。

    Map函数可能会调用emit零次:

    1. function() {
    2.     if (this.status == 'A')
    3.         emit(this.cust_id, 1);
    4. }

    也能是多次:

    1. function() {
    2.     this.items.forEach(function(item){ emit(item.sku, 1); });
    3. }

    Reduce函数:

    Reduce的结构:

    1. function(key, values) {
    2.    ...
    3.    return result;
    4. }
    • Reduce函功能应该是纯粹的,不应由于任何原因访问数据库。也不能对函数之外有任何影响。
    • values参数是一个数组,其元素是"映射"到键的值对象数组。MongoDB不会调用只有一个值的键的reduce函数。
    • MongoDB可以对同一个键多次调用reduce函数。 在这种情况下,该键的reduce函数的先前输出将成为该键的下一个reduce函数调用的输入值之一。

    关于MongoDB不会调用只有一个值的键的reduce函数。实验如下:

    1. //此时的values值不再是1 而是100
    2. var m = function(){ emit(this.age,100) };
    3. //对values进行循环 每个+1 获取count
    4. var r = function(key,values){
    5.    var sum = 0;
    6.    values.forEach(function(val){
    7.       sum += 1;
    8.    });
    9.    return sum;
    10. }
    11. //查看结果 凡是values为1的都输出了100 不是我们想要的结果
    12. > db.person.mapReduce(m,r,{out:'outt'}).find();
    13. { "_id" : 2, "value" : 100 }
    14. { "_id" : 30, "value" : 2 }
    15. { "_id" : "i do not know", "value" : 100 }

    Options参数:

    Field

    Type

    Description

    out

    string or document

    Specifies the location of the result of the map-reduce operation. You can output to a collection, output to a collection with an action, or output inline. You may output to a collection when performing map reduce operations on the primary members of the set; on secondary members you may only use theinline output.

    定义mapreduce操作的输出位置。

    query

    document

    Specifies the selection criteria using query operators for determining the documents input to the map function.

    定义一个查询这个查询将输入给map函数

    sort

    document

    Sorts the input documents. This option is useful for optimization. For example, specify the sort key to be the same as the emit key so that there are fewer reduce operations. The sort key must be in an existing index for this collection.

    指定为输入的document进行sort排序sort的列上必须要有索引。

    Sort主要为了提升性能,可以参考 http://www.csdn.net/article/2013-07-08/2816155-MongoDB-MapReduce-Optimization

    limit

    number

    Specifies a maximum number of documents for the input into the map function.

    定义输入给mapdocument的数量 limit

    finalize

    function

    Optional. Follows the reduce method and modifies the output.

    定义Reduce之后执行的操作

    scope

    document

    Specifies global variables that are accessible in the mapreduce andfinalize functions.

    定义在map reduct finalize中可以用的全局变量

    jsMode

    boolean

    Specifies whether to convert intermediate data into BSON format between the execution of the map and reduce functions. Defaults to false.

    If false:

    • Internally, MongoDB converts the JavaScript objects emitted by the mapfunction to BSON objects. These BSON objects are then converted back to JavaScript objects when calling the reduce function.
    • The map-reduce operation places the intermediate BSON objects in temporary, on-disk storage. This allows the map-reduce operation to execute over arbitrarily large data sets.

    map函数执行过程中,MongoDBmap函数发出的JavaScript对象转换为BSON对象。当调用reduce函数时,这些BSON对象再转换回JavaScript对象。

    •这样map-reduce操作将中间BSON对象放置在临时的磁盘存储中。这允许map-reduce操作在任意大的数据集上执行。

    If true:

    • Internally, the JavaScript objects emitted during map function remain as JavaScript objects. There is no need to convert the objects for thereduce function, which can result in faster execution.
    • You can only use jsMode for result sets with fewer than 500,000 distinct key arguments to the mapper's emit() function.

    map函数执行过程中,map函数期间发出的JavaScript对象将保留为JavaScript对象。没有必要转换对象然后给reduct功能,这可能导致执行速度更快。

    只能对映射器的emit()函数使用少于500,000个不同关键参数的结果集使用jsMode

    The jsMode defaults to false.

    verbose

    Boolean

    Specifies whether to include the timing information in the result information. The verbose defaults to true to include the timing information.

    指定是否在结果信息中包含时间信息。 verbose默认为true以包含时间信息。

    collation

    document

    Optional.

    Specifies the collation to use for the operation.

    Collation allows users to specify language-specific rules for string comparison, such as rules for lettercase and accent marks.

    The collation option has the following syntax:

    collation: {

    locale: <string>,

    caseLevel: <boolean>,

    caseFirst: <string>,

    strength: <int>,

    numericOrdering: <boolean>,

    alternate: <string>,

    maxVariable: <string>,

    backwards: <boolean>

    }

    When specifying collation, the locale field is mandatory; all other collation fields are optional. For descriptions of the fields, see Collation Document.

    If the collation is unspecified but the collection has a default collation (seedb.createCollection()), the operation uses the collation specified for the collection.

    If no collation is specified for the collection or for the operations, MongoDB uses the simple binary comparison used in prior versions for string comparisons.

    You cannot specify multiple collations for an operation. For example, you cannot specify different collations per field, or if performing a find with a sort, you cannot use one collation for the find and another for the sort.

    New in version 3.4.

    可选定义字符串的输出格式如大小写首字母等。

    其中:

    Out参数:

    输出到一个新集合:

    1. out: <collectionName>

    输出到一个已存在的集合:

    1. out: { <action>: <collectionName>
    2.         [, db: <dbName>]
    3.         [, sharded: <boolean> ]
    4.         [, nonAtomic: <boolean> ] }

    <action>可以是:

    • replace 如果<collectionName>的集合存在,则替换<collectionName>的内容。
    • merge 如果输出集合已经存在,则将新结果与现有结果合并。 如果现有文档与新结果具有相同的键,则覆盖现有文档。
    • reduce 如果输出集合已经存在,则将新结果与现有结果合并。 如果现有文档与新结果具有相同的键,则将reduce函数应用于新文档和现有文档,并使用结果覆盖现有文档。

    Db sharded nonAtomic都是可选的。

    Sharded:可选的。 如果为true并且已经在输出数据库上启用分片,则map-reduce操作将使用_id字段作为分片键来分割输出集合。

    nonAtomic:

    可选的。 将输出操作指定为非原子。 这仅适用于merge 和reduce 输出模式,这可能需要几分钟才能执行。

    默认情况下,nonAtomic为false,map-reduce操作在后处理期间锁定数据库。

    如果nonAtomic为true,则后处理步骤可防止MongoDB锁定数据库:在此期间,其他客户端将能够读取输出集合的中间状态。

    输出到Inline:

    在内存中执行map-reduce操作并返回结果

    1. out: { inline: 1 }

    效果:

    1. > db.person.mapReduce(m,r,{out:{inline:1}})
    2. {
    3.    "results" : [
    4.       {
    5.          "_id" : 2,
    6.          "value" : 100
    7.       },
    8.       {
    9.          "_id" : 30,
    10.          "value" : 2
    11.       },
    12.       {
    13.          "_id" : "i do not know",
    14.          "value" : 100
    15.       }
    16.    ],
    17.    "timeMillis" : 0,
    18.    "counts" : {
    19.       "input" : 4,
    20.       "emit" : 4,
    21.       "reduce" : 1,
    22.       "output" : 3
    23.    },
    24.    "ok" : 1
    25. }
    26. > db.person.mapReduce(m,r,{out:{inline:1}}).find()
    27. [
    28.    {
    29.       "_id" : 2,
    30.       "value" : 100
    31.    },
    32.    {
    33.       "_id" : 30,
    34.       "value" : 2
    35.    },
    36.    {
    37.       "_id" : "i do not know",
    38.       "value" : 100
    39.    }
    40. ]
  • 相关阅读:
    jupyter notebook 将当前目录设置为工作目录
    推荐个不错的服务器管理软件
    jupyter notebook 安装记录
    微软发布 Pylance:改善 VS Code 中的 Python 体验
    paddleocr安装笔记
    开源免费!7款服务器管理工具
    极简Linux下安装极简桌面
    解决 win7 win10 等 64位 支持access数据库问题
    泓格WINPAC主机与第三方模块rs 485 modbus rtu通信测试
    ajax
  • 原文地址:https://www.cnblogs.com/xiaolang8762400/p/6937146.html
Copyright © 2011-2022 走看看