精华内容
下载资源
问答
  • 原文发布时间:2014/4/15 9:17:50转自武汉大学遥感信息学院官网各省市测绘单位: 地理国情普查和监测涉及多种来源、多种尺度的数据综合处理和统计分析应用,为适应当前地理国情监测技术及应用需要,国家测绘地理...

    原文发布时间:2014/4/15  9:17:50

    转自武汉大学遥感信息学院官网

    各省市测绘单位: 

          地理国情普查和监测涉及多种来源、多种尺度的数据综合处理和统计分析应用,为适应当前地理国情监测技术及应用需要,国家测绘地理信息局继续教育中心与地理国情监测国家测绘地理信息局重点实验室定于2014520日至523日在武汉大学举办地理国情监测多源数据组织、整合与处理技术培训班,现将有关事项通知如下:

     
    一、研讨班课程概况
          本次培训班课程主要以加拿大Safe公司的FME软件和ArcGIS地统计分析为工具基础,以多源数据的整合和综合统计指标、统计方法为主要内容,围绕行业综合统计需求进行培训和研讨。培训班以专家授课、上机操作和专题报告相结合的形式开展。


    二、主办单位
          国家测绘地理信息局继续教育中心

          武汉大学遥感信息工程学院

          地理国情监测国家测绘地理信息局重点实验室

          北京世纪安图数码科技发展有限责任公司


    三、学习交流对象
          各省、市测绘部门,地质勘测、规划、水利、城市勘测等相关单位项目管理人员、项目设计与工程人员。


    四、培训课程安排
         

    培训课程

    时间

    培训内容

    地理国情监测数据处理

    521日上午

    1.地理国情监测数据介绍
    2.FME
    技术介绍
    3.
    传感器监测数据的处理与应用
    4.
    地理国情监测数据的统计分析

    地理国情监测综合统计分析

    521日下午

    1.ArcGIS的地理国情普查数据模型
    2.ArcGIS
    的地统计模块介绍
    3.
    结合地理国情普查试点数据介绍综合统计分析流程

    多源数据转换

    522日上午

    1.常见数据格式特点
    2.
    数据格式快速转换
    3.
    坐标系转换

    数据质量检查

    522日下午

    1.数据空间检查
    2.
    数据属性检查

    基于FME的常见数据操作

    523日上午

    1.非空间数据处理
    2.
    空间数据处理

    空间数据库操作

    523日下午

    1.数据入库处理
    2.
    数据出库处理
    3.
    数据库同步更新

    案例介绍

    基于FME的应用案例介绍



    五、注册报到事宜
          1.报到时间:2014520830-2200
          2. 报到地点:武汉大学信息学部星湖园酒店
          3. 培训时间:2014521-23日(共24学时)
          4. 培训地点:武汉大学遥感信息工程学院多功能报告厅(信息学部附3-202

    六、培训费用
          1.研讨班培训费2800元人民币/人(含资料费、餐费);
          2.统一安排住宿,费用自理。

    七、其他事项
          1.报到时请带1寸登记照片一张,以便办理培训结业证书。
          2.请参加培训班的学员于2014514日前将报名回执(见附件2)以传真或电子邮件方式至武汉大学遥感信息工程学院联系人。
         

    八、联系方式
          1.联系人:陈江平,电话:027-68770791
                             周军其,电话:027-68771421
                            万舒良,电话:027-68778505
          2.  真:027-68778086
          3.电子邮件: ngcm@whu.edu.cn
          4.网址:http://cgcc.whu.edu.cn/dlgq/
          5.扫描二维码:

    关于举办“地理国情监测多源数据组织、整合与处理技术培训班”的通知 - FME - FME—专业化的空间数据服务实践者

    展开全文
  • 通常在直播系统源码中,直播间人数是非常重要的统计数据,由于需要统计实时人数,因此需要如下处理。 1.当用户进入和退出直播间,触发进入和退出直播间广播,通知客户端增减人数。 2.当新用户进入直播间时,要给...

    通常在直播系统源码中,直播间人数是非常重要的统计数据,由于需要统计实时的人数,因此需要如下处理。
    1.当用户进入和退出直播间,触发进入和退出直播间的广播,通知客户端增减人数。
    2.当新用户进入直播间时,要给该用户提供相应的房间人数的数据
    3.在数据库中存储累计人数,用于统计
    4.Redis中存储用户列表,方便用户列表的相关功能使用
    处理代码如下:
    1.进入房间部分

    //进入房间
    	socket.on('conn', function(data) {
    
    		if(!data || !data.token){
    				return !1;
    		}
    		userid=data.uid;
    		old_socket = sockets[userid];
    		if (old_socket && old_socket != socket) {
    			
    			if(data.uid != data.roomnum && data.uid==old_socket.roomnum){
                    /* 进房间 但旧链接是 主播 */
                    var data_str='{"retmsg":"ok","retcode":"000000","msg":[{"msgtype":"1","_method_":"StartEndLive","action":"19","ct":"直播关闭"}]}';
    				old_socket.emit('broadcastingListen',[data_str]);
    			}else if(data.uid== data.roomnum && data.stream==old_socket.stream){
                    /* 主播重连 */
    				old_socket.reusing = 1;
    				//console.log("重用");
    			}else if(data.uid== data.roomnum && data.stream!=old_socket.stream){
                    /* 主播多端开播 */
    				var data_str='{"retmsg":"ok","retcode":"000000","msg":[{"msgtype":"1","_method_":"StartEndLive","action":"19","ct":"直播关闭"}]}';
    				old_socket.emit('broadcastingListen',[data_str]);
    			}
    			old_socket.disconnect()
    		}
    		
    		clientRedis.get(data.token,function(error,res){
    			if(error){
    				return;
    			}else if(res==null){
    				//console.log("[获取token失败]"+data.uid);
    			}else{
    				if(res != null){
    					
    					var userInfo = evalJson(res);
    					if(userInfo['id'] == data.uid ){
    						//console.log("[初始化验证成功]--"+data.uid+"---"+data.roomnum+'---'+data.stream);
    						//获取验证token
    						socket.token   = data.token; 
    						socket.roomnum = data.roomnum;
    						socket.stream = data.stream;
    						socket.nicename = userInfo['user_nicename'];
    						socket.level = userInfo['level'];
    						socket.avatar = userInfo['avatar'];
    						socket.sign = Number(userInfo['sign']);
    						socket.usertype   = parseInt(userInfo['usertype']);
    						socket.uid     = data.uid;
    						socket.reusing = 0;
    						
    						socket.join(data.roomnum);
    						sockets[userid] = socket;
    						socket.emit('conn',['ok']);
                            
    						if( socket.roomnum!=socket.uid && socket.uid >0 ){
                                /* 处理有时 无座驾信息会崩溃的问题 */
                                var car_id='0';
                                var car_swf='';
                                var car_swftime='';
                                var car_words='';
                                if(userInfo.hasOwnProperty("car")){
                                    var carinfo=userInfo['car'];
                                    if(carinfo.hasOwnProperty("id")){
                                        car_id=carinfo['id'];
                                    }
                                    if(carinfo.hasOwnProperty("swf")){
                                        car_swf=carinfo['swf'];
                                    }
                                    if(carinfo.hasOwnProperty("swftime")){
                                        car_swftime=carinfo['swftime'];
                                    }
                                    if(carinfo.hasOwnProperty("words")){
                                        car_words=carinfo['words'];
                                    }
                                }
                                
    							var data_obj={
                                                "msg":[
                                                    {
                                                        "_method_":"SendMsg",
                                                        "action":"0",
                                                        "ct":{
                                                            "id":''+userInfo['id'],
                                                            "user_nicename":''+userInfo['user_nicename'],
                                                            "avatar":userInfo['avatar'],
                                                            "avatar_thumb":userInfo['avatar_thumb'],
                                                            "level":''+userInfo['level'],
                                                            "usertype":''+userInfo['usertype'],
                                                            "vip_type":''+userInfo['vip']['type'],
                                                            "guard_type":''+userInfo['guard_type'],
                                                            "liangname":''+userInfo['liang']['name'],
                                                            "car_id":''+car_id,
                                                            "car_swf":''+car_swf,
                                                            "car_swftime":''+car_swftime,
                                                            "car_words":''+car_words
                                                        },
                                                        "msgtype":"0"
                                                    }
                                                ],
                                                "retcode":"000000",
                                                "retmsg":"OK"
                                            };
    
    	//发送进入房间消息
    							process_msg(io,socket.roomnum,JSON.stringify(data_obj));
    							if(socket.stream){
    								clientRedis.zadd('user_'+socket.stream,socket.sign,userInfo['id']);	
    							}
    						}						
    						 
    						sendSystemMsg(socket,"直播内容包含任何低俗、暴露和涉黄内容,账号会被封禁;安全部门会24小时巡查哦~");
    						return;
    					}else{
    						socket.disconnect();
    					}
    				}
    			}
    			
    			socket.emit('conn',['no']);
    		});
            
    		
    	});
    

    2.离开房间部分

     //资源释放
    	socket.on('disconnect', function() { 
    			/* numscount--; 
                if(numscount<0){
    				numscount=0;
    			}   */
              			
    			if(socket.roomnum ==null || socket.token==null || socket.uid <=0){
    				return !1;
    			}
    				
    			d.run(function() {
    				/* 用户连麦 */
    				clientRedis.hget('ShowVideo',socket.roomnum,function(error,res){
                        if(error){
                            return !1;
                        }
                        if(!res){
                            return !1;
                        }
                        var res_j=JSON.parse(res);
                        
                        if( socket.uid == res_j['uid'] || socket.uid == socket.roomnum ){
                            clientRedis.hdel('ShowVideo',socket.roomnum);
                            var data_obj={
                                            "msg":[
                                                {
                                                    "_method_":"ConnectVideo",
                                                    "action":"5",
                                                    "msgtype":"10",
                                                    "uid":""+socket.uid,
                                                    "uname":""+socket.nicename
                                                }
                                            ],
                                            "retcode":"000000",
                                            "retmsg":"OK"
                                        };
                            process_msg(io,socket.roomnum,JSON.stringify(data_obj));									
                        }	
    					 
    				});
    				
    				
    				if(socket.roomnum==socket.uid){
    					/* 主播 */ 
    					if(socket.reusing==0){
    						request(config['WEBADDRESS']+"?service=Live.stopRoom&uid="+socket.uid + "&token=" + socket.token+ "&type=1&stream=" + socket.stream,function(error, response, body){
                                var data_obj={
                                            "retmsg":"ok",
                                            "retcode":"000000",
                                            "msg":[
                                                {
                                                    "msgtype":"1",
                                                    "_method_":"StartEndLive",
                                                    "action":"18",
                                                    "ct":"直播关闭"
                                                }
                                            ]
                                        };
                                process_msg(io,socket.roomnum,JSON.stringify(data_obj));
                                // console.log('关播');
                                // console.log(FormatNowDate());
                                // console.log('uid---'+socket.uid);
                            });
                            endLiveConnect(io,socket.uid);
    					}
                        
                        
                        
    				}else{
    					/* 观众 */
                        clientRedis.zrem('user_'+socket.stream,socket.uid,function(error,res){
    						if(error) return;
    						if(res){
    							var data_obj={
                                                "msg":[
                                                    {
                                                        "_method_":"disconnect",
                                                        "action":"1",
                                                        "ct":{
                                                            "id":''+socket.uid,
                                                            "user_nicename":''+socket.nicename,
                                                            "avatar":socket.avatar,
                                                            "level":''+socket.level
                                                        },
                                                        "msgtype":"0",
                                                        "uid":''+socket.uid,
                                                        "uname":socket.nicename
                                                    }
                                                ],
                                                "retcode":"000000",
                                                "retmsg":"OK"
                                            };
    							process_msg(io,socket.roomnum,JSON.stringify(data_obj));	
    						}
    						
    					});
    					
    				}
    				console.log(socket.roomnum+"==="+socket.token+"===="+socket.uid+"======"+socket.stream);
    				
    				socket.leave(socket.roomnum);
    				delete io.sockets.sockets[socket.id];
    				sockets[socket.uid] = null;
    				delete sockets[socket.uid];
    
    			});
    	});
    
    });
    

    3.用户进入房间返回数据与缓存操作

    	public function enterRoom() {
    		$rs = array('code' => 0, 'msg' => '', 'info' => array());
    		
    		$uid=$this->uid;
    		$token=checkNull($this->token);
    		$liveuid=$this->liveuid;
    		$city=checkNull($this->city);
    		$stream=checkNull($this->stream);
            
            $checkToken=checkToken($uid,$token);
    		if($checkToken==700){
    			$rs['code'] = $checkToken;
    			$rs['msg'] = '您的登陆状态失效,请重新登陆!';
    			return $rs;
    		}
            
            
    		$isban = isBan($uid);
    		if(!$isban){
    			$rs['code']=1001;
    			$rs['msg']='该账号已被禁用';
    			return $rs;
    		}
    
    		
    		$domain = new Domain_Live();
            
            $domain->checkShut($uid,$liveuid);
    		$userinfo=getUserInfo($uid);
    		
    		$carinfo=getUserCar($uid);
    		$userinfo['car']=$carinfo;
    		$issuper='0';
    		if($userinfo['issuper']==1){
    			$issuper='1';
    			DI()->redis  -> hset('super',$userinfo['id'],'1');
    		}else{
    			DI()->redis  -> hDel('super',$userinfo['id']);
    		}
    		if(!$city){
    			$city='好像在火星';
    		}
    		
    		$data=array('city'=>$city);
    		$domain2 = new Domain_User();
    		$info = $domain2->userUpdate($uid,$data);
    		$userinfo['city']=$city;
    
    		$usertype = isAdmin($uid,$liveuid);
    		$userinfo['usertype'] = $usertype;
            
            $stream2=explode('_',$stream);
    		$showid=$stream2[1];
            
            $contribution='0';
            if($showid){
                $contribution=$domain->getContribut($uid,$liveuid,$showid);
            }
    
    		$userinfo['contribution'] = $contribution;
    
    		
    		unset($userinfo['issuper']);
            
            /* 守护 */
            $domain_guard = new Domain_Guard();
    		$guard_info=$domain_guard->getUserGuard($uid,$liveuid);
            
    		$guard_nums=$domain_guard->getGuardNums($liveuid);
            $userinfo['guard_type']=$guard_info['type'];
            /* 等级+100 保证等级位置位数相同,最后拼接1 防止末尾出现0 */
            $userinfo['sign']=$userinfo['contribution'].'.'.($userinfo['level']+100).'1';
    		
    		DI()->redis  -> set($token,json_encode($userinfo));
    		
            /* 用户列表 */
            $userlists=$this->getUserList($liveuid,$stream);
            
            /* 用户连麦 */
    		$linkmic_uid='0';
    		$linkmic_pull='';
    		$showVideo=DI()->redis  -> hGet('ShowVideo',$liveuid);
    		// file_put_contents('./showVideo.txt',date('Y-m-d H:i:s').' 提交参数信息 liveuid:'.json_encode($liveuid)."\r\n",FILE_APPEND);
    		// file_put_contents('./showVideo.txt',date('Y-m-d H:i:s').' 提交参数信息 showVideo:'.json_encode($showVideo)."\r\n",FILE_APPEND);
    		if($showVideo){
                $showVideo_a=json_decode($showVideo,true);
    			$linkmic_uid=$showVideo_a['uid'];
    			$linkmic_pull=$this->getPullWithSign($showVideo_a['pull_url']);
    		}
            
            /* 主播连麦 */
            $pkinfo=array(
                'pkuid'=>'0',
                'pkpull'=>'0',
                'ifpk'=>'0',
                'pk_time'=>'0',
                'pk_gift_liveuid'=>'0',
                'pk_gift_pkuid'=>'0',
            );
            $pkuid=DI()->redis  -> hGet('LiveConnect',$liveuid);
            //file_put_contents('./LiveConnect.txt',date('Y-m-d H:i:s').' 提交参数信息 进房间:'."\r\n",FILE_APPEND);
            //file_put_contents('./LiveConnect.txt',date('Y-m-d H:i:s').' 提交参数信息 uid:'.json_encode($uid)."\r\n",FILE_APPEND);
            //file_put_contents('./LiveConnect.txt',date('Y-m-d H:i:s').' 提交参数信息 liveuid:'.json_encode($liveuid)."\r\n",FILE_APPEND);
            if($pkuid){
                $pkinfo['pkuid']=$pkuid;
                /* 在连麦 */
                $pkpull=DI()->redis  -> hGet('LiveConnect_pull',$pkuid);
                $pkinfo['pkpull']=$this->getPullWithSign($pkpull);
                $ifpk=DI()->redis  -> hGet('LivePK',$liveuid);
                if($ifpk){
                    $pkinfo['ifpk']='1';
                    $pk_time=DI()->redis  -> hGet('LivePK_timer',$liveuid);
                    if(!$pk_time){
                        $pk_time=DI()->redis  -> hGet('LivePK_timer',$pkuid);
                    }
                    $nowtime=time();
                    if($pk_time && $pk_time >0 && $pk_time< $nowtime){
                        $cha=5*60 - ($nowtime - $pk_time);
                        $pkinfo['pk_time']=(string)$cha;
                        
                        $pk_gift_liveuid=DI()->redis  -> hGet('LivePK_gift',$liveuid);
                        if($pk_gift_liveuid){
                            $pkinfo['pk_gift_liveuid']=(string)$pk_gift_liveuid;
                        }
                        $pk_gift_pkuid=DI()->redis  -> hGet('LivePK_gift',$pkuid);
                        if($pk_gift_pkuid){
                            $pkinfo['pk_gift_pkuid']=(string)$pk_gift_pkuid;
                        }
                        
                    }else{
                        $pkinfo['ifpk']='0';
                    }
                }
    
            }
    		//file_put_contents('./LiveConnect.txt',date('Y-m-d H:i:s').' 提交参数信息 pkinfo:'.json_encode($pkinfo)."\r\n",FILE_APPEND);
    		$configpri=getConfigPri();
    
            
    	    $info=array(
    			'votestotal'=>$userlists['votestotal'],
    			'barrage_fee'=>$configpri['barrage_fee'],
    			'userlist_time'=>$configpri['userlist_time'],
    			'chatserver'=>$configpri['chatserver'],
    			'linkmic_uid'=>$linkmic_uid,
    			'linkmic_pull'=>$linkmic_pull,
    			'nums'=>$userlists['nums'],
    			'speak_limit'=>$configpri['speak_limit'],
    			'barrage_limit'=>$configpri['barrage_limit'],
    			'coin'=>$userinfo['coin'],
    			'vip'=>$userinfo['vip'],
    			'liang'=>$userinfo['liang'],
    			'issuper'=>(string)$issuper,
    			'usertype'=>(string)$usertype,
    		);
    		$info['isattention']=(string)isAttention($uid,$liveuid);
    		$info['userlists']=$userlists['userlist'];
            
            /* 守护 */
            $info['guard']=$guard_info;
            $info['guard_nums']=$guard_nums;
            
            /* 主播连麦/PK */
            $info['pkinfo']=$pkinfo;
            
            /* 红包 */
            $key='red_list_'.$stream;
            $nums=DI()->redis->lSize($key);
            $isred='0';
            if($nums>0){
                $isred='1';
            }
    		$info['isred']=$isred;
            
            /* 奖池 */
            $info['jackpot_level']='-1';
    		$jackpotset = getJackpotSet();
            if($jackpotset['switch']){
                $jackpotinfo = getJackpotInfo();
                $info['jackpot_level']=$jackpotinfo['level'];
            }
            
    		$rs['info'][0]=$info;
    		return $rs;
    	}	
    

    以上就是直播系统源码中关于直播间人数统计功能的大致开发流程,这对于平常的团队来说可能会存在一定的难度,但是如果是交给专业的团队,各方面实现和最终效果也会更好一些。
    声明:本文由美狐原创,未经允许禁止转载,谢谢合作。

    展开全文
  • 由于有面试通知,现在复习一下十道和海量数据处理相关题。两篇博客已经讲非常完备了,但是我怕读懂了并非真懂,所以必须自己复述一遍。 教你如何迅速秒杀掉:99%海量数据处理面试题海量数据处理:十道...

    原文地址:http://blog.csdn.net/zy825316/article/details/35600653

    缘由

    由于有面试通知,现在复习一下十道和海量数据处理相关的题。两篇博客已经讲的非常完备了,但是我怕读懂了并非真的懂,所以必须自己复述一遍。
    1. 教你如何迅速秒杀掉:99%的海量数据处理面试题
    2. 海量数据处理:十道面试题与十个海量数据处理方法总结
    3. MapReduce技术的初步了解与学习

    面试归类

    下面6个方面覆盖了大多数关于海量数据处理的面试题:
    1. 分而治之/hash映射 + hash统计 + 堆/快速/归并排序;
    2. 双层桶划分
    3. Bloom filter/Bitmap;
    4. Trie树/数据库/倒排索引;
    5. 外排序;
    6. 分布式处理之Hadoop/Mapreduce。
    下面我讲针对上两篇博客里的海量数据处理的题的解法再复述一遍。

    第一类:分治后hash统计再排序

    第一题:海量日志数据,提取出某日访问百度次数最多的那个IP

    解答:
    该题解题思路总共分为三步
    1. 分而治之/hash映射:如果该文件过大,不能全部读入内存。我们就必须先利用hash函数将其分割成若干小文件。再分别对各个小文件进行处理。注意这一步我们肯定会将相同的ip放在同一个文件。由于这个题干给的比较少。我只有自己脑补一下,大概给我们的日志中就是百度web服务器自己记录的来自不同的ip的访问。这个日志是按天生成的,所以现在我们要统计一天内,哪一个ip访问本网站百度的次数最多。那么日志中肯定就是记录是访问ip和时间,但是相同的ip肯定是单独的一条。所以现在要将相同的ip放在同一个文件中处理。由于我们确定某个ip放到哪一个子文件的时候是使用的一个hash函数,对一个ip用hash函数求值后取模,就可以确定这个条ip记录放到哪一文件。所有在相同的ip一定存在一个文件,这样方便我们统计。
    2. hash_map统计:针对每一个文件,我们肯定是可以读入内存了。(因为这里每一个文件的大小是我们在第一步控制的)。针对内存中的每一条记录,以ip为键,以其出现的次数为值,遍历该文件中的每一条记录。(顺便深入思考一下:这里所谓的hash_map就是一个底层以hashtable实现的数据结构。我猜想底层也就是有一个巨大的数组,数组下标就是键的hash值,而数组的内容就是值。在这里就是用ip算出了数组下标,然后数组内容就是该ip出现的次数。当然更多内容需要去探索,比如这个数组大小是如何确定?发生冲突是如何解决。不过这点与该题无关了,我们只是利用hashmap这个数据结构。)
    3. 堆/快速排序:针对每一个文件,只需遍历一次就可以取得该文件,ip次数出现最多的那个ip。将所有小文件中访问次数最多的ip一对比,就可以得到整个文件中ip最多的那一个。

    第二题:寻找热门查询,300万个查询字符串中统计最热门的10个查询

    题干:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

    解答:
    有了一题的思路,那么这道第二题就更好理解了,思路肯定还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序。但是我们需要考虑第一步是否有必要,因为共有记录300万条,就算每条记录的长度都是255字节,那么就是
    (3000000*1/4)1024 约等于 (3000000*1/4)1000 ,结果单位为MB(注意1/4的单位是kb),那么就是0。75g。所以这整份文件是可以轻易读入大小为1G的内存的。所以第一步分而治之/hash映射在本题中是不需要的。
    直接第二、三步:
    hash统计:遍历这1000万条记录,每天都以一个query为键,其出现的累计出现的次数为值。那么就可以在一次遍历的过程中将所有的统计query出现的次数统计完。
    堆/快速/归并排序:由于我们只需要求出前10个query。所以也就是求top k的问题,那么使用堆结构。我们可以logK的时间内完成查找和调整堆结构。所以,我们只需要维护一个大小为10的最小堆。我们确实是求查询次数最多的10个次,所以我们该用最小堆。接着,就将先将300万条记录的前10个插入最小堆,调整最小堆,然后将第11个与最小堆的堆顶比较,如何堆顶元素大,那么不做任何改变,如果堆顶元素小,那么就用第11个替换掉堆顶元素,然后调整最小堆,与第12个进行比较。那么我们在一次遍历之后就可以选出最大的10个。

    第三题

    3、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
    解答:
    显然过程还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序。而且题中已经说的很明显了,就是内存肯定是不够用的。所以我们肯定要进行分而治之/hash映射这一步。我就不再复述了,因为和上面两道题和相似。

    第四题

    4、海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。
    解答
    还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序 这个思想。
    但是我觉得如果面试官如果问类似的题的话,一定要注意反问面试官,相同的数据是不是存在在同一台电脑上,还有没有没内存大小的限制(这个问题只要题中没有说明有什么限制,我都觉得需要问一下,体现自己思维比较全面)。针对这道题,如果相同的数据不在同一台电脑上,那么就先要进行分而治之/hash映射,将相同的文件放于同一台电脑上,有点像将相同的数据处于同一个文件中。其他进行的过程与本题其他内容类似,不再赘述。

    第五题

    5、有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
    解答:
    本题不再是选出top N的问题。而是排序的问题,但是核心还是不变。
    分而治之/hash映射:由于没有说相同的query是放在同一个文件,所以必须先对每一个query做一个映射,将相同的query放在同一个文件。所以注意这里会产生10个新的文件(相同query在同一个文件)。
    hash统计:主要选一个2g的电脑来对每一个文件完成这个过程。因为每个文件的容量都为1g。

    堆/快速/归并排序:先利用堆/快速/归并排序对每一份文件的query和query_cout的进行排序,然后将排好序的内容再输出到一份新文件中。最后对着10文件进行归并排序(内排序和外排序一起进行)原博客有一份实现:

    • https://github.com/ooooola/sortquery/blob/master/querysort.py

    • 本题一个要点就是:在最后一步的在做完hash,分成多个文件后,可以采用分布式的架构来处理(比如MapReduce)。我记得hadoop的第一个统计单词的个数的小例子就是读取不同文件的单词的次数,然后输出的结果就是一个文本,里面有每一个在单词在所有文件中出现的总次数。

    第六题

    6、 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
    解答:
    5000 000 000 * 64 约等于 5g*64 = 320G。显然一个内存装不去。所以需要分而治之/hash映射。
    分而治之/hash映射:我们可以考虑将这个50亿个url分到1000个小文件中,这样每个文件也就是300m。主要在映射中,我们对a文件和b文件使用的是同一个hash函数,这样就能保证如何a文件和b文件中有相同的url,那么将会被映射到对应的文件中去。比如a0对应b0文件,a1对应b1文件...
    hash_set统计:第二步非常简单了,我们只需要对每一对小文件进行处理。先将a0文件的内容储存到hash_set中,再依次计算b0的,如果有相同的那就是a与b共有的文件,所以将该条url存储到最终结果的文件中既可。


    第七题

    7、怎么在海量数据中找出重复次数最多的一个?
    解答:
    简单说,就是hash映射成小文件,然后hash求出每个数据出现的次数,将每个文件中次数最多的一比较就可以了。

    第八题

    8、上千万或上亿数据(有重复),统计其中出现次数最多的前N个数据。
    解答:
    与第二题类似。

    第九题

    9、一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
    解答:
    除了使用前面的分而治之/hash映射 + hash统计 + 堆/快速/归并排序的方法以外,也可以使用单词查找树。下面是单词查找树的分析:
    这题是考虑时间效率。用trie树(单词查找树,字典树,就是一种树有插入、查找,删除等操作)统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的字符串长度)。因为在面对每一个单词的时候,我们都可以在字典书中进行查找,查看是否有这个单词,然后将相应的次数加一,之后就是找出出现最频繁的前10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。所以总的时间复杂度,是O(n*le)与O(n*lg10)中较大的哪一个。

    第十题

    10. 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
    想了想和前面的题都类似的,即可用字典树,也可以用hashmap,原博客对该题还做了性能上的比较。有兴趣者自行参看。

    第十一题

    11. 一个文本文件,找出前10个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解。
    首先根据用hash并求模,将文件分解为多个小文件,对于单个文件利用上题的方法求出每个文件件中10个最常出现的词。然后再进行排序处理,找出最终的10个最常出现的词。

    第十二题

    12. 100w个数中找出最大的100个数。
    最小堆直接秒杀,复杂度为O(100w*lg100)。

    第二、三类:双层桶划分、Bloom filter/Bitmap。

    双层桶划分、Bloom filter/Bitmap我发现两者实际上还是解决的同一个问题。双层桶划分有点难理解,我今天就算了。

    Bloom filter我已经写过博客总结了:

    bitmap

    下面就是bitmap,参见百度百科的例子,我觉得这个东西很像计数排序。

    假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来达到排序的目的。要表示8个数,我们就只需要8个Bit(1Bytes)(为什么是8个,因为最大的数是7,试想,如果最大的数是10,我们必须要11个bit,这是因为我们需要将需要排序的数作为下标),首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0
    然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,这里默认为Big-ending),因为是从零开始的,所以要把第五位置为1。
    然后再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1。
    然后我们现在遍历一遍Bit区域,将该位是一的位的编号输出(2,3,4,5,7),这样就达到了排序的目的。其实就是把计数排序用的统计数组的每个单位缩小成bit级别的布尔数组。
    然后我们再看看利用这个三个技术能解决的问题,主要是bloom filter/Bitmap

    第一题

    给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢?
    先考虑只有两个文件的情况下:
    如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。”

    这只是另外的解法,我想了想,如果文件多至三个或者n个,那么还是使用分而治之/hash映射 + hash统计 + 堆/快速/归并排序中第六题的思路吧,三个文件的时候,我们用就让每一个小文件:a0、b0、c0。先让a0和b0生成两个hash_set,然后让对c0的每一条记录都去算hash,先a0比对,如果a0有,再b0比对。这样三个都比对成功的就是三个文件都有的url。


    第二题

    在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。
    方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受(为什么这里取2^32,这是因为我们假设了最大的数就是2^32,实际上,这也是各大语言中默认的int类型最大的数。所以这2.5亿个数的取值范围必须在 0< 2^32之间)。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。我觉得思路倒是很清晰。

    方案2:也可采用与第1题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。”


    第三题

    已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
    8位最多99 999 999,最多需要99m个bit,那么99 999 999/(8*1024*1024) = 11.92,所以大概10几m字节的内存即可。 (可以理解为从0-99 999 999的数字,每个数字对应一个Bit位,所以只需要99M个Bit==12MBytes,这样,就用了小小的12M左右的内存表示了所有的8位数的电话)。注意只是用这个每一个bit位来表示有没有这个电话号码,而相应bit位的下标才表示了这个具体的电话号码。

    第四题

    给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
     方案1:用位图/Bitmap的方法,那么需要多少内存呢?因为已经说了是unsigned int ,所以 最大的整数应该是:2^32 = 4 294 967 296。所以其给的40亿数字的范围就在 0-4 294 967 296之间。故需要 4 294 967 296 个bit位,4 294 967 296个bit就是512MB(4 294 967 296/(8*1024*1024))可得。所以申请512M的内存,一个bit位代表一个unsigned int值。读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在。

    第四五类:Trie树/数据库/倒排索引、外排序

    有兴趣的可以自行看看博客:http://blog.csdn.net/v_july_v/article/details/7382693

    Trie树

    我在这里只说一下:Trie树。
    在面对需要处理字符串的时候,不一定非要用hash来完成插入或者查找。也可以使用Trie字典树。所以在处理字符串的时候,我们都需要想到用字典树。字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。可以进行查找、删除、插入等操作。上面已经讲了的题中,有如下几个题涉及字典树:
    上面的第2题:寻找热门查询:查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个,每个不超过255字节。
    上面的第5题:有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。要你按照query的频度排序。
    在分而治之/Hash映射之后,对每一份文件里面的单词,插入到字典树中。在设计字典树的数据结构的时,对于每一个节点,我们需要一个额外的一个int字段,来存储这个单词出现的次数。第一次插入的时候当然是1,之后每被查找到,就自加一。

    第一题

    1000万字符串,其中有些是相同的(重复),需要把重复的全部去掉,保留没有重复的字符串。请问怎么设计和实现?
    这个可能需要两个字典树,遇见一个插入字典数A,如果遇见在A中出现的,那么就插入字典数B。每次遇见新的字符串时,先查找B,如果在B中出现了,那么就不能插入A。如果B在中没有出现,在A中也没有,就插入A,如果B中没有,而在A中有,那么删除A中有的,并插入B。

    第二题

    也是上面的第8题:一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词。
    其解决方法是:用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平均长度),然后是找出出现最频繁的前10个词(使用最小堆)。


    第六类:分布式处理之Mapreduce

    说起Mapreduce常常和Hadoop联系起啦。july总结的很好:
    1. Mapreduce是一种模式。
    2. Hadoop是一种框架。
    3. Hadoop是一个实现了mapreduce模式的开源的分布式并行编程框架。
    4. 在hadoop的框架上采取mapreduce的模式处理海量数据。

    Mapreduce

    那么下面来具体看看Mapreduce是怎样一种模式:
    所谓mapreduc是两个单词map和reduce的组合。Map函数把大数据集进行分解操作得到两个或者更多的小“桶”。每台处理器对分割出来的每个桶进行操作,获取一组中间值,而Reduce函数是把这些中间结果通过一定的函数进行处理来获取最终的答案。

    例子一

    简单的例子就是:
    假设我们有一组数据:1,2,3,…,100。求这一组数据的平方和。现在我们用MapReduce这个模型解决这一个问题。
    首先我们把这组数据分成100份,交由100台计算机去处理。每一台计算机只做一件事,就是把自己要处理的数据平方一下。这样一来,最初的那组数[1,2,3,…,100]就被映射成了[1,4,9,16,…,10000]了。这就是所谓的Map操作。而Reduce操作呢?Reduce操作就是把映射后得到的这100个新的数据累加。

    虽然这个例子过于简单,但是依然算是说明了问题。

    例子二

    下面一个例子是经常出现的,就是统计词频的例子,假设我们有这样三篇文章,每篇文章的内容如下:
    Paper1: We study algorithm.
    Paper2: We share our thinking.
    Paper3: This team shares thinking of algorithm.
    我们想要统计的是所有文章的词频,那么我们可以将每一篇paper交由一台电脑计算词频(map),再对所有计算结果进行统计(reduce)。
    所以map操作开始如下所示:

    接着每台自己计算对自己的部分进行处理,如下所示:


    最后得到结果:


    对其中,我唯一比较困惑的就是,对中间结果的处理,july在旁边图上说:还是由多台处理器分别处理。我就很奇怪其的通信机制,或者如下


    到底是存在哪里?分别存在不同的机器上?那么机器2 的we 1 就会跑到机器1上的文档里么?对旁边的注释: hash%n我还是能理解的。但是我怎么觉得只有对所有机器的文档都遍历一遍,边遍历边算hash值再求模,映射到不同的文档中。
    其实,我觉得都不用映射都不同的文档,直接在一份文档里不就好了么?然后再进行reduce,因为每一个文档的每一行都是同一个字符出现的次数。所以按我的想法,上图第C步,在一个文档中所示才更为合理。
    1. we 1 we 1  
    2. study 1  
    3. algorithm 1 algorithm 1  
    4. share 1 share 1  
    5. our 1  
    6. Thinking 1 Thinking 1   
    7. Team 1  
    8. of 1  
    现在先做做了解吧,以后要深入学习的话,再说。

    Hadoop

    Hadoop既然是个框架,肯定涉及很多组件,我们来看看下面这幅图。

    下面对这幅图的主要组件稍作解释:
    • 分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。
    • HBase – Hadoop Database,首先是一个HBase是一个分布式的、面向列的开源数据库。作为一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,我们可以利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。HBase利用Hadoop HDFS作为其文件存储系统。同时,HBase利用Hadoop MapReduce来处理HBase中的海量数据;HBase利用Zookeeper作为协同服务。

    注意,下面两句话区分一下HDFS和Hbase(摘自:Hbase与HDFS是个什么关系呀? http://tieba.baidu.com/p/1338652682):

    1. HDFS是一种文件格式,像FAT32,NTFS之类的,属于底层的;HBase是数据库,可以建在HDFS上,也可以不在这上面,不过按照设计,是推荐运行在HDFS上的。
    2. hdfs只是一个存储空间,他的完整名字是分布式文件系统。有名可知他的作用了。hbase是一个内存数据库,简单点说hbase把表啊什么的存在hdfs上。
    • MapReduce是一种编程模型,运行分布式系统之上。我的理解就是按照一定的模式处理着HBase或HDFS内的数据。
    • Pig是一种编程语言,它简化了Hadoop常见的工作任务。Pig可加载数据、表达转换数据以及存储最终结果。Pig内置的操作使得半结构化数据变得有意义(如日志文件)。同时Pig可扩展使用Java中添加的自定义数据类型并支持数据转换。
    • hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
    • Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中。
    总的来说,在我们编程的时候,主要是用java针对mapreduce来编程。上次参加一个讲座的时候老师仿佛也说了可以利用hive,使用sql来完成同样的工作。但是集群的安装配置也是值得掌握的。

    后记

    主要是总结了别人的,还需要更多地努力啊!加油

    (全文完)
    展开全文
  • 由于有面试通知,现在复习一下十道和海量数据处理相关题。两篇博客已经讲非常完备了,但是我怕读懂了并非真懂,所以必须自己复述一遍。 教你如何迅速秒杀掉:99%海量数据处理面试题海量数据处理:十道...

    缘由

    由于有面试通知,现在复习一下十道和海量数据处理相关的题。两篇博客已经讲的非常完备了,但是我怕读懂了并非真的懂,所以必须自己复述一遍。
    1. 教你如何迅速秒杀掉:99%的海量数据处理面试题
    2. 海量数据处理:十道面试题与十个海量数据处理方法总结
    3. MapReduce技术的初步了解与学习

    面试归类

    下面6个方面覆盖了大多数关于海量数据处理的面试题:
    1. 分而治之/hash映射 + hash统计 + 堆/快速/归并排序;
    2. 双层桶划分
    3. Bloom filter/Bitmap;
    4. Trie树/数据库/倒排索引;
    5. 外排序;
    6. 分布式处理之Hadoop/Mapreduce。
    下面我讲针对上两篇博客里的海量数据处理的题的解法再复述一遍。

    第一类:分治后hash统计再排序

    第一题:海量日志数据,提取出某日访问百度次数最多的那个IP

    解答:
    该题解题思路总共分为三步
    1. 分而治之/hash映射:如果该文件过大,不能全部读入内存。我们就必须先利用hash函数将其分割成若干小文件。再分别对各个小文件进行处理。注意这一步我们肯定会将相同的ip放在同一个文件。由于这个题干给的比较少。我只有自己脑补一下,大概给我们的日志中就是百度web服务器自己记录的来自不同的ip的访问。这个日志是按天生成的,所以现在我们要统计一天内,哪一个ip访问本网站百度的次数最多。那么日志中肯定就是记录是访问ip和时间,但是相同的ip肯定是单独的一条。所以现在要将相同的ip放在同一个文件中处理。由于我们确定某个ip放到哪一个子文件的时候是使用的一个hash函数,对一个ip用hash函数求值后取模,就可以确定这个条ip记录放到哪一文件。所有在相同的ip一定存在一个文件,这样方便我们统计。
    2. hash_map统计:针对每一个文件,我们肯定是可以读入内存了。(因为这里每一个文件的大小是我们在第一步控制的)。针对内存中的每一条记录,以ip为键,以其出现的次数为值,遍历该文件中的每一条记录。(顺便深入思考一下:这里所谓的hash_map就是一个底层以hashtable实现的数据结构。我猜想底层也就是有一个巨大的数组,数组下标就是键的hash值,而数组的内容就是值。在这里就是用ip算出了数组下标,然后数组内容就是该ip出现的次数。当然更多内容需要去探索,比如这个数组大小是如何确定?发生冲突是如何解决。不过这点与该题无关了,我们只是利用hashmap这个数据结构。)
    3. 堆/快速排序:针对每一个文件,只需遍历一次就可以取得该文件,ip次数出现最多的那个ip。将所有小文件中访问次数最多的ip一对比,就可以得到整个文件中ip最多的那一个。

    第二题:寻找热门查询,300万个查询字符串中统计最热门的10个查询

    题干:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

    解答:
    有了一题的思路,那么这道第二题就更好理解了,思路肯定还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序。但是我们需要考虑第一步是否有必要,因为共有记录300万条,就算每条记录的长度都是255字节,那么就是
    (3000000*1/4)1024 约等于 (3000000*1/4)1000 ,结果单位为MB(注意1/4的单位是kb),那么就是0。75g。所以这整份文件是可以轻易读入大小为1G的内存的。所以第一步分而治之/hash映射在本题中是不需要的。
    直接第二、三步:
    hash统计:遍历这1000万条记录,每天都以一个query为键,其出现的累计出现的次数为值。那么就可以在一次遍历的过程中将所有的统计query出现的次数统计完。
    堆/快速/归并排序:由于我们只需要求出前10个query。所以也就是求top k的问题,那么使用堆结构。我们可以logK的时间内完成查找和调整堆结构。所以,我们只需要维护一个大小为10的最小堆。我们确实是求查询次数最多的10个次,所以我们该用最小堆。接着,就将先将300万条记录的前10个插入最小堆,调整最小堆,然后将第11个与最小堆的堆顶比较,如何堆顶元素大,那么不做任何改变,如果堆顶元素小,那么就用第11个替换掉堆顶元素,然后调整最小堆,与第12个进行比较。那么我们在一次遍历之后就可以选出最大的10个。

    第三题

    3、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
    解答:
    显然过程还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序。而且题中已经说的很明显了,就是内存肯定是不够用的。所以我们肯定要进行分而治之/hash映射这一步。我就不再复述了,因为和上面两道题和相似。

    第四题

    4、海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。
    解答
    还是分而治之/hash映射 + hash统计 + 堆/快速/归并排序 这个思想。
    但是我觉得如果面试官如果问类似的题的话,一定要注意反问面试官,相同的数据是不是存在在同一台电脑上,还有没有没内存大小的限制(这个问题只要题中没有说明有什么限制,我都觉得需要问一下,体现自己思维比较全面)。针对这道题,如果相同的数据不在同一台电脑上,那么就先要进行分而治之/hash映射,将相同的文件放于同一台电脑上,有点像将相同的数据处于同一个文件中。其他进行的过程与本题其他内容类似,不再赘述。

    第五题

    5、有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
    解答:
    本题不再是选出top N的问题。而是排序的问题,但是核心还是不变。
    分而治之/hash映射:由于没有说相同的query是放在同一个文件,所以必须先对每一个query做一个映射,将相同的query放在同一个文件。所以注意这里会产生10个新的文件(相同query在同一个文件)。
    hash统计:主要选一个2g的电脑来对每一个文件完成这个过程。因为每个文件的容量都为1g。

    堆/快速/归并排序:先利用堆/快速/归并排序对每一份文件的query和query_cout的进行排序,然后将排好序的内容再输出到一份新文件中。最后对着10文件进行归并排序(内排序和外排序一起进行)原博客有一份实现:

    • https://github.com/ooooola/sortquery/blob/master/querysort.py


    • 本题一个要点就是:在最后一步的在做完hash,分成多个文件后,可以采用分布式的架构来处理(比如MapReduce)。我记得hadoop的第一个统计单词的个数的小例子就是读取不同文件的单词的次数,然后输出的结果就是一个文本,里面有每一个在单词在所有文件中出现的总次数。

    第六题

    6、 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
    解答:
    5000 000 000 * 64 约等于 5g*64 = 320G。显然一个内存装不去。所以需要分而治之/hash映射。
    分而治之/hash映射:我们可以考虑将这个50亿个url分到1000个小文件中,这样每个文件也就是300m。主要在映射中,我们对a文件和b文件使用的是同一个hash函数,这样就能保证如何a文件和b文件中有相同的url,那么将会被映射到对应的文件中去。比如a0对应b0文件,a1对应b1文件...
    hash_set统计:第二步非常简单了,我们只需要对每一对小文件进行处理。先将a0文件的内容储存到hash_set中,再依次计算b0的,如果有相同的那就是a与b共有的文件,所以将该条url存储到最终结果的文件中既可。


    第七题

    7、怎么在海量数据中找出重复次数最多的一个?
    解答:
    简单说,就是hash映射成小文件,然后hash求出每个数据出现的次数,将每个文件中次数最多的一比较就可以了。

    第八题

    8、上千万或上亿数据(有重复),统计其中出现次数最多的前N个数据。
    解答:
    与第二题类似。

    第九题

    9、一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
    解答:
    除了使用前面的分而治之/hash映射 + hash统计 + 堆/快速/归并排序的方法以外,也可以使用单词查找树。下面是单词查找树的分析:
    这题是考虑时间效率。用trie树(单词查找树,字典树,就是一种树有插入、查找,删除等操作)统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的字符串长度)。因为在面对每一个单词的时候,我们都可以在字典书中进行查找,查看是否有这个单词,然后将相应的次数加一,之后就是找出出现最频繁的前10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。所以总的时间复杂度,是O(n*le)与O(n*lg10)中较大的哪一个。

    第十题

    10. 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
    想了想和前面的题都类似的,即可用字典树,也可以用hashmap,原博客对该题还做了性能上的比较。有兴趣者自行参看。

    第十一题

    11. 一个文本文件,找出前10个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解。
    首先根据用hash并求模,将文件分解为多个小文件,对于单个文件利用上题的方法求出每个文件件中10个最常出现的词。然后再进行排序处理,找出最终的10个最常出现的词。

    第十二题

    12. 100w个数中找出最大的100个数。
    最小堆直接秒杀,复杂度为O(100w*lg100)。

    第二、三类:双层桶划分、Bloom filter/Bitmap。

    双层桶划分、Bloom filter/Bitmap我发现两者实际上还是解决的同一个问题。双层桶划分有点难理解,我今天就算了。

    Bloom filter我已经写过博客总结了:

    bitmap

    下面就是bitmap,参见百度百科的例子,我觉得这个东西很像计数排序。

    假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来达到排序的目的。要表示8个数,我们就只需要8个Bit(1Bytes)(为什么是8个,因为最大的数是7,试想,如果最大的数是10,我们必须要11个bit,这是因为我们需要将需要排序的数作为下标),首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0
    然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,这里默认为Big-ending),因为是从零开始的,所以要把第五位置为1。
    然后再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1。
    然后我们现在遍历一遍Bit区域,将该位是一的位的编号输出(2,3,4,5,7),这样就达到了排序的目的。其实就是把计数排序用的统计数组的每个单位缩小成bit级别的布尔数组。
    然后我们再看看利用这个三个技术能解决的问题,主要是bloom filter/Bitmap

    第一题

    给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢?
    先考虑只有两个文件的情况下:
    如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。”

    这只是另外的解法,我想了想,如果文件多至三个或者n个,那么还是使用分而治之/hash映射 + hash统计 + 堆/快速/归并排序中第六题的思路吧,三个文件的时候,我们用就让每一个小文件:a0、b0、c0。先让a0和b0生成两个hash_set,然后让对c0的每一条记录都去算hash,先a0比对,如果a0有,再b0比对。这样三个都比对成功的就是三个文件都有的url。


    第二题

    在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。
    方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受(为什么这里取2^32,这是因为我们假设了最大的数就是2^32,实际上,这也是各大语言中默认的int类型最大的数。所以这2.5亿个数的取值范围必须在 0< 2^32之间)。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。我觉得思路倒是很清晰。

    方案2:也可采用与第1题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。”


    第三题

    已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
    8位最多99 999 999,最多需要99m个bit,那么99 999 999/(8*1024*1024) = 11.92,所以大概10几m字节的内存即可。 (可以理解为从0-99 999 999的数字,每个数字对应一个Bit位,所以只需要99M个Bit==12MBytes,这样,就用了小小的12M左右的内存表示了所有的8位数的电话)。注意只是用这个每一个bit位来表示有没有这个电话号码,而相应bit位的下标才表示了这个具体的电话号码。

    第四题

    给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
     方案1:用位图/Bitmap的方法,那么需要多少内存呢?因为已经说了是unsigned int ,所以 最大的整数应该是:2^32 = 4 294 967 296。所以其给的40亿数字的范围就在 0-4 294 967 296之间。故需要 4 294 967 296 个bit位,4 294 967 296个bit就是512MB(4 294 967 296/(8*1024*1024))可得。所以申请512M的内存,一个bit位代表一个unsigned int值。读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在。

    第四五类:Trie树/数据库/倒排索引、外排序

    有兴趣的可以自行看看博客:http://blog.csdn.net/v_july_v/article/details/7382693

    Trie树

    我在这里只说一下:Trie树。
    在面对需要处理字符串的时候,不一定非要用hash来完成插入或者查找。也可以使用Trie字典树。所以在处理字符串的时候,我们都需要想到用字典树。字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。可以进行查找、删除、插入等操作。上面已经讲了的题中,有如下几个题涉及字典树:
    上面的第2题:寻找热门查询:查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个,每个不超过255字节。
    上面的第5题:有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。要你按照query的频度排序。
    在分而治之/Hash映射之后,对每一份文件里面的单词,插入到字典树中。在设计字典树的数据结构的时,对于每一个节点,我们需要一个额外的一个int字段,来存储这个单词出现的次数。第一次插入的时候当然是1,之后每被查找到,就自加一。

    第一题

    1000万字符串,其中有些是相同的(重复),需要把重复的全部去掉,保留没有重复的字符串。请问怎么设计和实现?
    这个可能需要两个字典树,遇见一个插入字典数A,如果遇见在A中出现的,那么就插入字典数B。每次遇见新的字符串时,先查找B,如果在B中出现了,那么就不能插入A。如果B在中没有出现,在A中也没有,就插入A,如果B中没有,而在A中有,那么删除A中有的,并插入B。

    第二题

    也是上面的第8题:一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词。
    其解决方法是:用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平均长度),然后是找出出现最频繁的前10个词(使用最小堆)。


    第六类:分布式处理之Mapreduce

    说起Mapreduce常常和Hadoop联系起啦。july总结的很好:
    1. Mapreduce是一种模式。
    2. Hadoop是一种框架。
    3. Hadoop是一个实现了mapreduce模式的开源的分布式并行编程框架。
    4. 在hadoop的框架上采取mapreduce的模式处理海量数据。

    Mapreduce

    那么下面来具体看看Mapreduce是怎样一种模式:
    所谓mapreduc是两个单词map和reduce的组合。Map函数把大数据集进行分解操作得到两个或者更多的小“桶”。每台处理器对分割出来的每个桶进行操作,获取一组中间值,而Reduce函数是把这些中间结果通过一定的函数进行处理来获取最终的答案。

    例子一

    简单的例子就是:
    假设我们有一组数据:1,2,3,…,100。求这一组数据的平方和。现在我们用MapReduce这个模型解决这一个问题。
    首先我们把这组数据分成100份,交由100台计算机去处理。每一台计算机只做一件事,就是把自己要处理的数据平方一下。这样一来,最初的那组数[1,2,3,…,100]就被映射成了[1,4,9,16,…,10000]了。这就是所谓的Map操作。而Reduce操作呢?Reduce操作就是把映射后得到的这100个新的数据累加。

    虽然这个例子过于简单,但是依然算是说明了问题。

    例子二

    下面一个例子是经常出现的,就是统计词频的例子,假设我们有这样三篇文章,每篇文章的内容如下:
    Paper1: We study algorithm.
    Paper2: We share our thinking.
    Paper3: This team shares thinking of algorithm.
    我们想要统计的是所有文章的词频,那么我们可以将每一篇paper交由一台电脑计算词频(map),再对所有计算结果进行统计(reduce)。
    所以map操作开始如下所示:

    接着每台自己计算对自己的部分进行处理,如下所示:


    最后得到结果:


    对其中,我唯一比较困惑的就是,对中间结果的处理,july在旁边图上说:还是由多台处理器分别处理。我就很奇怪其的通信机制,或者如下


    到底是存在哪里?分别存在不同的机器上?那么机器2 的we 1 就会跑到机器1上的文档里么?对旁边的注释: hash%n我还是能理解的。但是我怎么觉得只有对所有机器的文档都遍历一遍,边遍历边算hash值再求模,映射到不同的文档中。
    其实,我觉得都不用映射都不同的文档,直接在一份文档里不就好了么?然后再进行reduce,因为每一个文档的每一行都是同一个字符出现的次数。所以按我的想法,上图第C步,在一个文档中所示才更为合理。
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. we 1 we 1  
    2. study 1  
    3. algorithm 1 algorithm 1  
    4. share 1 share 1  
    5. our 1  
    6. Thinking 1 Thinking 1   
    7. Team 1  
    8. of 1  
    现在先做做了解吧,以后要深入学习的话,再说。

    Hadoop

    Hadoop既然是个框架,肯定涉及很多组件,我们来看看下面这幅图。

    下面对这幅图的主要组件稍作解释:
    • 分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。
    • HBase – Hadoop Database,首先是一个HBase是一个分布式的、面向列的开源数据库。作为一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,我们可以利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。HBase利用Hadoop HDFS作为其文件存储系统。同时,HBase利用Hadoop MapReduce来处理HBase中的海量数据;HBase利用Zookeeper作为协同服务。

    注意,下面两句话区分一下HDFS和Hbase(摘自:Hbase与HDFS是个什么关系呀? http://tieba.baidu.com/p/1338652682):

    1. HDFS是一种文件格式,像FAT32,NTFS之类的,属于底层的;HBase是数据库,可以建在HDFS上,也可以不在这上面,不过按照设计,是推荐运行在HDFS上的。
    2. hdfs只是一个存储空间,他的完整名字是分布式文件系统。有名可知他的作用了。hbase是一个内存数据库,简单点说hbase把表啊什么的存在hdfs上。
    • MapReduce是一种编程模型,运行分布式系统之上。我的理解就是按照一定的模式处理着HBase或HDFS内的数据。
    • Pig是一种编程语言,它简化了Hadoop常见的工作任务。Pig可加载数据、表达转换数据以及存储最终结果。Pig内置的操作使得半结构化数据变得有意义(如日志文件)。同时Pig可扩展使用Java中添加的自定义数据类型并支持数据转换。
    • hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
    • Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中。
    总的来说,在我们编程的时候,主要是用java针对mapreduce来编程。上次参加一个讲座的时候老师仿佛也说了可以利用hive,使用sql来完成同样的工作。但是集群的安装配置也是值得掌握的。
    展开全文
  • 带有一些统计数据的所有应用程序的仪表板 具有一些统计信息的单个应用程序的仪表板 演示 有一个演示服务器正在运行(很少有崩溃,我们正在寻找崩溃数据来提供这个数据库): ://acra-server-demo.marvinlabs....
  • 按照河北省委、省政府关于对雄安新区周边部分区域实施托管的通知要求,沧州市任丘市的苟各庄镇、鄚州镇、七间房乡划归雄县实施统计上托管,保定市高阳县的龙化乡划归安新县实施统计上托管。为确保统计调查工作的顺利...
  • Statistics窗口,全称叫做 Rendering Statistics Window,即渲染统计窗口(或渲染数据统计窗口),窗口中罗列出关于声音、图像等多种统计信息。 Batches:即Batched Draw Calls,是Unity内置Draw Call Batching技术。...
  • 基于Filemaker软件,按照《浙江省人民政府关于高水平建设“四好农村路”的实施意见》(浙政发〔2018〕24号)、《关于切实做好高水平建设“四好农村路”有关工作的通知(浙交办〔2018〕92号)、《高水平建设“四好...
  • 国家卫生健康委办公厅于2020年7月发布了“关于进一步加强单病种质量管理与控制工作的通知”(国卫办医函〔2020〕624号),通知要求各医疗机构需将单病种质量管理与控制工作制度作为医疗质量管理制度的重要组成部分,...
  • 努力:论文CCCV 2017录取通知

    千次阅读 2017-07-20 17:23:55
    研究过程大概是有这么几个阶段:(1)看书因为考虑用条件随机场(Conditional Random Field, CRF)来对神经网络分割结果进行优化,所以先看李航博士统计学习方法》第10、11章,分别是关于隐马尔科夫模型和条件...
  • 笔者根据国调中心调自[1998 ]126号文 “关于印发《能量管理系统(EM S) 应用软件功能要求及其实施基础条件》(试行) 的通知”及其附件, 国调中心[ 1999 ]207号文“EM S 应用软件基本功能实用要求及验收细则”, 以及...
  • 随着数据科学的热门,数据的优化、整理以及如何处理不良数据成为人们关注的重点。本书通过处理不良数据,进行数据清理的案例,向读者展示了处理数据的方法。 本书共有19章,从6部分向读者展示了使用和清理不良数据...
  • 根据2020年度计算机技术与软件专业技术资格(水平)考试数据统计分析,经商工业和信息化部,现将考试合格标准有关事项通告如下: 一、2020年度计算机技术与软件专业技术资格(水平)考试初级、中级、高级各科目合格...
  • 根据2020年度计算机技术与软件专业技术资格(水平)考试数据统计分析,经商工业和信息化部,现将考试合格标准有关事项通告如下: 一、2020年度计算机技术与软件专业技术资格(水平)考试初级、中级、高级各科目合格...
  • 如果您有一个应用程序,该应用程序可以发送来自您的医生的关于您的心脏速率和其他医疗统计数据的通知,您会怎么做?这个由两部分组成的系列教程会介绍一家虚构的医疗中心,该医疗中心要求共享来自数千个心脏监控传感...
  • 添加 Fortran 语言、Matlab(Octave),修订:比赛结束后编辑时丢失提交统计数据、修复部分RE。 05-18 修订 16.04以上版本FB显示异常。 基于OpenJudgerWindows集成便携版 浙传网盘 05-17 修订 改善ajax,减少...
  • 拍卖即将结束的通知 Char Bazaar数据 由于没有来自Cipsoft的官方API,因此此应用中使用的所有数据均从官方网站上抓取。 您可以在检查抓取脚本。 所有实时数据均从以下端点获取: ...
  • 定时任务是操作系统提供给我们一个非常好功能,我们经常用定时任务来处理一些事情,比如每天定时备份网站数据、每个月执行下数据统计程序、监控服务器运行情况(发生错误时给管理员发消息通知)等等,这些都需要...
  • 或多或少一切可能会更改,恕不另行通知,我们暂时不能保证任何向后兼容性。 一旦eth2生态系统成熟,我们将能够为资源管理器可升级性提供更有力保证。 特征 基于Bootstrap和移动优先Web界面 快速强大...
  • 网站管理员工具  网站管理员工具需要对网站... 1、Google Webmaster Tools:谷歌网站管理员工具,可以获取到谷歌抓取、编入索引和搜索流量的数据,同时接收关于用户网站上所存在的问题的通知。  2、Bing Webmas...
  • 1997年11月20日,国务院学位委员会办公室发出《关于批准部分高等学校开展工程硕士培养工作的通知》,批准54所高等学校开展工程硕士培养工作,并行使工程硕士专业学位授予权,由此拉开了我国工程硕士培养的序幕。...
  • R语言学习资源

    2017-08-11 17:40:13
    统计之都 : 国内质量最高统计网站,有一些关于统计和R语言优秀博客以及与R有关会议通知。 肖凯博客(需翻墙): 很有质感博客,有大量 R 语言应用案例。 4.2 数据科学相关书籍
  • 13.自定义网站前台底部关于我们”等信息 14.自定义网站公告 15.详尽业务数据(用户、订单、图书)统计 16.提醒需要处理事务 17.自定义包装方式、送货方式、支付方式 18.自定义用户注册协议 19.查看图书各类...
  • 其中,将4D图像时间序列数据的处理一般化为任意数量的维度,以在统一的框架中处理来自多个接收器线圈的数据,多回波或相位fMRI数据,以及经典的统计分析和强大的可视化选项。 安装 下载的当前版本,并将代码目录添加...
  • 记者今天从最高人民检察院获悉,最高检日前下发《关于全面部署应用全国检察机关统一业务应用系统统计子系统的通知》,对统计系统全面运用进行部署。 据悉,2014年在检察机关全面推行的统一业务应用系统,是融办案、...
  • ManagementSystem-源码

    2021-03-22 00:18:49
    教练关于已建团体的通知 使用Spring Security为管理员配置对页面和端点的访问 上载和下载文件(客户照片等) 在数据库中搜索并生成带有统计信息的报告 该数据管理系统是为体育俱乐部开发的。为了更轻松地跟踪财务...
  • 根据利润、领域、优先级、时间、状态等标准,用户可定制关于将要进行活动、业务、客户、联系人、约会等方面报告;提供类似BBS功能,用户可把销售秘诀贴在系统上,还可以进行某一方面销售技能查询;销售费用...
  • のべらす-crx插件

    2021-04-02 17:17:30
    ,如小说家“kaku yom”,我们将通知您作品的统计数据您已发布,以及新印象和评论。※“让我们成为一名小说家”是Hina Project,Inc。注册商标※“Kaku Yom”是Kadokawa,Inc。注册商标※由于这种扩展功能是非...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 127
精华内容 50
关键字:

关于统计数据的通知