余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

MongoDB 统计 group 操作用不了,试试 mapReduce 吧

xiyangw 2023-05-13 16:18 8 浏览 0 评论

问题回顾

今天,同事小张 Q 我, 说自己辛苦花了一天的时间,基于 mongodb 数据库开发的待办统计功能一直报错!

MongoDB 统计 group 操作用不了,试试 mapReduce 吧

于是笔者花了近半小时了解小张的开发需求以及代码实现方式,大致明白问题出在对待办 collection 做统计时,调用 collection 的分组 group 函数、聚合 aggregate 函数的使用方式不对。

待办 collection 文档分组(group )函数代码

GroupByResults groupByResults = mongoTemplate.group(new Criteria().andOperator(criteriaArray),mongoTemplate.getCollectionName(PendingEntity.class), groupBy, PendingEntity.class);
long resultCount = ((List)groupByResults.getRawResults().get("retval")).size();

待办 collection 文档聚合(aggregate)函数代码

AggregationResults<PendingEntity> results = mongoTemplate.aggregate(aggregation, "studentScore", PendingEntity.class);
double totleScore = results.getUniqueMappedResult().getCollect();

问题定位

异常信息

Map-reduce supports operations on sharded collections, both as an input and as an output. This section describes the behaviors of mapReduce specific to sharded collections.
However, starting in version 4.2, MongoDB deprecates the map-reduce option to create a new sharded collection as well as the use of the sharded option for map-reduce. To output to a sharded collection, create the sharded collection first. MongoDB 4.2 also deprecates the replacement of an existing sharded collection.

Sharded Collection as Input
When using sharded collection as the input for a map-reduce operation, mongos will automatically dispatch the map-reduce job to each shard in parallel. There is no special option required. mongos will wait for jobs on all shards to finish.

Sharded Collection as Output
If the out field for mapReduce has the sharded value, MongoDB shards the output collection using the _idfield as the shard key.

从异常信息提示来看,我注意到 errmsg 字段值:“can't do command: group on sharded collection”,大意是说分片文档(sharded collection)不能使用分组 group 函数。

笔者猜测是 sharded collection 的问题,于是笔者从一些技术博客和 mongodb 官网查了下使用 group 函数的一些限制,大致如下:

  • 分片表不能 group 分组
can't do command: group on sharded collection
  • group 操作不会处理超过 20000 个唯一键( group by 的关键字具有唯一性约束条件下)
exception: group() can't handle more than 20000 unique keys

显然,分片表不能 group 的限制,也验证了我的当初的猜想。

于是我问了下运维组的同事,也证实了 mongodb 在创建 collection 文档时,会指定文档数据分片到不同服务器上 ,这是出于对 mongodb 稳定性的考虑吧。

解决方案

既然分片表不能 group ,那如何解决分组统计的问题呢?

答案是用 “mapReduce” 。

想到什么呢?

是不是很类似 Hadoop 中的 Map-Reduce 的思想:


MapReduce最重要的一个思想: 分而治之. 就是将负责的大任务分解成若干个小任务, 并行执行. 完成后在合并到一起. 适用于大量复杂的任务处理场景, 大规模数据处理场景.

Map负责“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。可以进行拆分的前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。

Reduce负责“合”,即对map阶段的结果进行全局汇总。

Hadoop 中的 Map-Reduce 执行流程

来源网络

翻阅 mongodb 官网文档,对 mapReduce 函数介绍如下:

Map-reduce supports operations on sharded collections, both as an input and as an output. This section describes the behaviors of mapReduce specific to sharded collections.

However, starting in version 4.2, MongoDB deprecates the map-reduce option to create a new sharded collection as well as the use of the sharded option for map-reduce. To output to a sharded collection, create the sharded collection first. MongoDB 4.2 also deprecates the replacement of an existing sharded collection

.

Sharded Collection as Input

When using sharded collection as the input for a map-reduce operation, mongos will automatically dispatch the map-reduce job to each shard in parallel. There is no special option required. mongos will wait for jobs on all shards to finish.


Sharded Collection as Output

If the out field for mapReduce has the sharded value, MongoDB shards the output collection using the _idfield as the shard key.

大意是 mapReduce 支持对 sharded collections 分片文档 input / output 操作,其处理逻辑如下:

  1. mongos接收到mapreduce的操作请求后,根据query条件,将map-reduce任务发给持有数据的shards(sharding collection将会被分裂成多个chunks并分布在多个shards中,shard即为mongod节点)。
  2. 每个shards都依次执行mapper和reducer,并将结果写入到本地的临时collection中,结果数据是根据_id(即reducer的key)正序排列。
  3. 当所有的shards都reduce完成之后,将各自结果数据中_id的最大值和最小值(即min、max key)返回给mongos。
  4. mongos负责shuffle和partition,将所有shards反馈的min、max key进行汇总,并将整个key区间分成多个partitions,每个partition包含[min,max]区间,此后mongos将partiton信息封装在finalReduce指令中并发给每个shard,最终每个shard都会收到一个特定的partition的任务;partition不会重叠。
  5. 此后每个shard将与其他所有的shards建立链接,根据partition信息,从min到max,遍历每个key。对于任何一个key,当前shard都将从其他shards获取此key的所有数据,然后执行reduce和finalize方法,每个key可能会执行多次reduce,这取决于values的条数,但是finalize只会执行一次,最终将此key的finalize的结果通过本地方式写入sharding collection中。
  6. 当所有的shards都处理完毕后,mongos将处理结果返回给客户端(inline)。

mapReduce 语法格式:

db.collection.mapReduce(<map>,         <reduce>,

                         {

                           out: <collection>,

                           query: <document>,

                           sort: <document>,

                           limit: <number>,

                           finalize: <function>,

                           scope: <document>,

                           jsMode: <boolean>,

                           verbose: <boolean>,

                           bypassDocumentValidation: <boolean>

                         }

                       )

参数说明:

  • map:映射函数(生成键值对序列,作为reduce函数参数)
  • reduce:统计函数
  • query:目标记录过滤
  • sort:目标记录排序
  • limit:限制目标记录数量
  • out:统计结果存放集合(不指定使用临时集合,在客户端断开后自动删除)
  • finalize:最终处理函数(对 reduce 返回结果进行最终整理后存入结果集合)
  • Scope:向map、reduce、finalize导入外部变量
  • jsMode说明:为 false 时 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可处理非常大的mapreduce,为 true 时 BSON-->js-->map-->reduce-->BSON
  • verbose:显示详细的时间统计信息

于是,我让小张同学把 group 换成 mapReduce 函数,问题解决!

String reducef = "function(key,values){var total = {count:0};for(var i=0;i<values.length;i++){total.count += values[i].count;} return total;}";
MapReduceResults<BasicDBObject> mrr = readMongoTemplate.mapReduce(query,readMongoTemplate.getCollectionName(ReadingEntity.class), map, reducef, BasicDBObject.class);

问题总结

有时候,问题就出在最显眼的问题描述上,需要有心人去细细琢磨。

另外,其实大部分问题都可以在官网上找到相关技术解决方案,却又苦于受英语单词的折磨。。。

参考

https://docs.mongodb.com/manual/aggregation/

https://docs.mongodb.com/manual/core/map-reduce-sharded-collections/

https://www.cnblogs.com/chenpingzhao/p/7913247.html

https://blog.csdn.net/weixin_42582592/article/details/83080900

https://blog.csdn.net/iteye_19607/article/details/82644559

相关推荐

辞旧迎新,新手使用Containerd时的几点须知

相信大家在2020年岁末都被Kubernetes即将抛弃Docker的消息刷屏了。事实上作为接替Docker运行时的Containerd在早在Kubernetes1.7时就能直接与Kubelet集成使...

分布式日志系统ELK+skywalking分布式链路完整搭建流程

开头在分布式系统中,日志跟踪是一件很令程序员头疼的问题,在遇到生产问题时,如果是多节点需要打开多节点服务器去跟踪问题,如果下游也是多节点且调用多个服务,那就更麻烦,再者,如果没有分布式链路,在生产日志...

Linux用户和用户组管理

1、用户账户概述-AAA介绍AAA指的是Authentication、Authorization、Accounting,即认证、授权和审计。?认证:验证用户是否可以获得权限,是3A的第一步,即验证身份...

linux查看最后N条日志

其实很简单,只需要用到tail这个命令tail-100catalina.out输入以上命令,就能列出catalina.out的最后100行。...

解决linux系统日志时间错误的问题

今天发现一台虚拟机下的系统日志:/var/log/messages,文件时间戳不对,跟正常时间差了12个小时。按网上说的执行了servicersyslogrestart重启syslog服务,还是不...

全程软件测试(六十二):软件测试工作如何运用Linux—读书笔记

从事过软件测试的小伙们就会明白会使用Linux是多么重要的一件事,工作时需要用到,面试时会被问到,简历中需要写到。对于软件测试人员来说,不需要你多么熟练使用Linux所有命令,也不需要你对Linux...

Linux运维之为Nginx添加错误日志(error_log)配置

Nginx错误日志信息介绍配置记录Nginx的错误信息是调试Nginx服务的重要手段,属于核心功能模块(nginx_core_module)的参数,该参数名字为error_log,可以放在不同的虚机主...

Linux使用swatchdog实时监控日志文件的变化

1.前言本教程主要讲解在Linux系统中如何使用swatchdog实时监控日志文件的变化。swatchdog(SimpleWATCHDOG)是一个简单的Perl脚本,用于监视类Unix系统(比如...

syslog服务详解

背景:需求来自于一个客户想将服务器的日志转发到自己的日志服务器上,所以希望我们能提供这个转发的功能,同时还要满足syslog协议。1什么是syslog服务1.1syslog标准协议如下图这里的fa...

linux日志文件的管理、备份及日志服务器的搭建

日志文件存放目录:/var/log[root@xinglog]#cd/var/log[root@xinglog]#lsmessages:系统日志secure:登录日志———————————...

运维之日志管理简介

日志简介在运维过程中,日志是必不可少的东西,通过日志可以快速发现问题所在。日志分类日志分类,对不同的日志进行不同维度的分析。操作系统日志操作系统是基础,应用都是在其之上;操作系统日志的分析,可以反馈出...

Apache Log4j 爆核弹级漏洞,Spring Boot 默认日志框架就能完美躲过

这两天沸沸扬扬的Log4j2漏洞门事件炒得热火朝天:突发!ApacheLog4j2报核弹级漏洞。。赶紧修复!!|Java技术栈|Java|SpringBoot|Spring...

Linux服务器存在大量log日志,如何快速定位错误?

来源:blog.csdn.net/nan1996jiang/articlep/details/109550303针对大量log日志快速定位错误地方tail/head简单命令使用:附加针对大量log日志...

Linux中查看日志文件的正确姿势,求你别tail走天下了!

作为一个后端开发工程师,在Linux中查看查看文件内容是基本操作了。尤其是通常要分析日志文件排查问题,那么我们应该如何正确打开日志文件呢?对于我这种小菜鸡来说,第一反应就是cat,tail,vi(或...

分享几款常用的付费日志系统,献给迷茫的你!

概述在前一篇文章中,我们分享了几款免费的日志服务器。他们各有各的特点,但是大家有不同的需求,有时免费的服务器不能满足大家的需要,下面推荐几款付费的日志服务器。1.Nagios日志服务器Nagio...

取消回复欢迎 发表评论: