C#使用MapReduce实现对分片数据的分组
事由:mongodb已经进行数据分片,这样就不能使用一些方法就不能使用,例如eval,$group如果尝试使用mongodb会提示
Error: {
"ok" : ,
"errmsg" : "Error: Error: can't use sharded collection from db.eval @:2:9\n",
"code" : ,
"codeName" : "BadValue"
} :
错误原因:分片服务端不支持单服务器实例方法
经过查找,分片服务器的查询和操作只能使用MapReduce或者Aggregate(聚合管道)操作,这两个mongodb的高级操作可以完成mongo的几乎所有操作。
需求:查询collection当天满足指定条件的数据,并根据数据进行每个小时的pv,uv,ui统计
collection中存放浏览器访问记录
首先我们先使用mongdb的语句把查询语句写出来,这个很关键。如果不是很了解,就去解读一下官方文档吧,一言难尽。
db.runCommand({
mapreduce:'visits',
query:{ 'sh.si':100650, _id: { $gte: ObjectId('59931a800000000000000000') }},
map:function(){
emit(
{hours:this._id.getTimestamp().getHours()},{pv:1,ip:this.ip,ui:this.ui,hours:this._id.getTimestamp().getHours()}
);
},
reduce:function(k,values){
var data = {
hours:0,
pv: 0,
ip:[],
ui:[]
};
values.forEach(function (v) {
data.hours=v.hours;
data.pv+=v.pv;
if(v.ui)
data.ui.push(v.ui);
if(v.ip)
data.ip.push(v.ip);
});
return data;
},
finalize:function(key,v){
v.hours=NumberInt(v.hours);
v.pv=NumberInt(v.pv);
if(v.ui)
v.ui=NumberInt(ArrayGroup(v.ui).uni - 1);
else
v.ui=0;
if(v.ip)
v.ip=NumberInt(ArrayGroup(v.ip).uni - 1);
else
v.ip=0;
return v;
},
out:{inline:1}
});
执行之后会得到这样的结果
/* 1 */
{
"results" : [
{
"_id" : {
"hours" : 1.0
},
"value" : {
"pv" : 1,
"ip" : 0,
"ui" : 0.0,
"hours" : 1
}
},
{
"_id" : {
"hours" : 4.0
},
"value" : {
"pv" : 1,
"ip" : 0,
"ui" : 0.0,
"hours" : 4
}
},
{
"_id" : {
"hours" : 5.0
},
"value" : {
"pv" : 1,
"ip" : 0,
"ui" : 0.0,
"hours" : 5
}
},
{
"_id" : {
"hours" : 6.0
},
"value" : {
"hours" : 6,
"pv" : 4,
"ip" : 0,
"ui" : 0
}
},
{
"_id" : {
"hours" : 7.0
},
"value" : {
"pv" : 1,
"ip" : 0,
"ui" : 0,
"hours" : 7
}
},
{
"_id" : {
"hours" : 8.0
},
"value" : {
"hours" : 8,
"pv" : 8,
"ip" : 5,
"ui" : 4
}
},
{
"_id" : {
"hours" : 9.0
},
"value" : {
"hours" : 9,
"pv" : 10,
"ip" : 3,
"ui" : 0
}
},
{
"_id" : {
"hours" : 10.0
},
"value" : {
"hours" : 10,
"pv" : 9,
"ip" : 5,
"ui" : 2
}
},
{
"_id" : {
"hours" : 11.0
},
"value" : {
"hours" : 11,
"pv" : 17,
"ip" : 9,
"ui" : 1
}
},
{
"_id" : {
"hours" : 12.0
},
"value" : {
"hours" : 12,
"pv" : 20,
"ip" : 8,
"ui" : 2
}
},
{
"_id" : {
"hours" : 13.0
},
"value" : {
"hours" : 13,
"pv" : 23,
"ip" : 5,
"ui" : 2
}
},
{
"_id" : {
"hours" : 14.0
},
"value" : {
"hours" : 14,
"pv" : 33,
"ip" : 9,
"ui" : 2
}
},
{
"_id" : {
"hours" : 15.0
},
"value" : {
"hours" : 15,
"pv" : 52,
"ip" : 14,
"ui" : 4
}
}
],
"counts" : {
"input" : NumberLong(180),
"emit" : NumberLong(180),
"reduce" : NumberLong(26),
"output" : NumberLong(13)
},
"timeMillis" : 250,
"timing" : {
"shardProcessing" : 152,
"postProcessing" : 97
},
"shardCounts" : {
"ins-cluster-01/ins-mongodb-01:27018,ins-mongodb-03:27018" : {
"input" : 90,
"emit" : 90,
"reduce" : 9,
"output" : 12
},
"ins-cluster-02/ins-mongodb-02:27019,ins-mongodb-04:27019" : {
"input" : 90,
"emit" : 90,
"reduce" : 8,
"output" : 10
}
},
"postProcessCounts" : {
"ins-cluster-01/ins-mongodb-01:27018,ins-mongodb-03:27018" : {
"input" : NumberLong(22),
"reduce" : NumberLong(9),
"output" : NumberLong(13)
}
},
"ok" : 1.0
}
results
只看results返回的数据就可以
接着就可以借助这里的js脚本移植到C#程序中
public dynamic Today(int id)
{
//var rel = db.DataBase.Eval("show_visited_by_hours(" + id + ")").ToBsonDocument().ToDynamic();
//return rel; var query = Query.And(
Query.EQ("sh.si", id),
Query.GTE("_id", new ObjectId(new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), , , ))
);//筛选数据
var map = new BsonJavaScript(@"function () {
emit(
{hours:this._id.getTimestamp().getHours()},{pv:1,ip:this.ip,ui:this.ui,hours:this._id.getTimestamp().getHours()}
);
}");//数据按需分组 var reduce = new BsonJavaScript(@"function(k,values){
var data = {
hours:0,
pv: 0,
ip:[],
ui: []
};
values.forEach(function (v) {
data.hours=v.hours;
data.pv+=v.pv;
data.ui.push(v.ui);
data.ip.push(v.ip);
});
return data;
}
");//根据map传递参数做数据操作
var finalize = new BsonJavaScript(@"function(key,v){
v.hours=NumberInt(v.hours);
v.pv=NumberInt(v.pv);
if(v.ui)
v.ui=NumberInt(ArrayGroup(v.ui).uni - 1);
else
v.ui=NumberInt(0);
if(v.ip)
v.ip=NumberInt(ArrayGroup(v.ip).uni - 1);
else
v.ip=NumberInt(0);
return v;
}");//按照指定格式编排输出数据格式
MapReduceOptionsBuilder mrob = new MapReduceOptionsBuilder();//定义附加项MapReduceOptions
mrob.SetFinalize(finalize);
mrob.SetQuery(query);
mrob.SetOutput(MapReduceOutput.Inline);//选择直接输出结果
var rel = db.DataBase.GetCollection("visits").MapReduce(map,reduce, mrob); //提交执行MapReduce
var valuearray=rel.InlineResults;//获取执行结果集
var pvcount = ;
var ipcount = ;
var uicount = ;
var count = new List<BsonDocument>();
foreach (var vitem in valuearray)
{
pvcount+= (int)vitem["value"]["pv"];
ipcount += (int)vitem["value"]["ip"];
uicount += (int)vitem["value"]["ui"];
count.Add(vitem["value"].ToBsonDocument());
}
var result = new { pv= pvcount, ip = ipcount, ui = uicount, count = count };//按指定格式组装数据
return result.ToBsonDocument().ToDynamic();
}
过程还需要多去揣摩至于Aggregate就相对很简单了,把所有的查询对象,查询聚合使用BsonDocument做好参数格式化。
再附上一个Aggregate在C#中的使用方法,相对较容易理解。
public string func_api_site_count(int sid = , int st = , int et = , string flag = "year", string order = "pv desc")
{
var sitesday = _dbs.DataBase.GetCollection("log_sites_day");
var match = new QueryDocument();
match.AddRange(new Dictionary<string, object> {
{ "_id.day", new Dictionary<string, object> { { "$gte", st }, { "$lte", et } }},
{ "_id.sid", new Dictionary<string, object> { { "$eq", sid } }}
});
var group = new Dictionary<string, object>();
var sort = new Dictionary<string, BsonValue>();
var query = new Dictionary<string, object>();
switch (flag)
{
case "month":
query.Add("$substr", new List<object>() { "$_id.day", , });
break;
case "year":
query.Add("$substr", new List<object>() { "$_id.day", , });
break;
case "day":
query.Add("$_id.day", "$_id.day");
break;
case "week":
break;
} group.Add("_id", query);
group.Add("pv", new BsonDocument("$sum", "$pv"));
group.Add("uv", new BsonDocument("$sum", "$uv"));
group.Add("ui", new BsonDocument("$sum", "$ui"));
group.Add("ip", new BsonDocument("$sum", "$ip"));
group.Add("nuv", new BsonDocument("$sum", "$nuv"));
group.Add("area", new BsonDocument("$push", "$area"));
group.Add("rf", new BsonDocument("$push", "$rfsite"));
var groupby = new Dictionary<string, BsonValue>{
{"_id",null},
{"day",new BsonDocument("$push", "$_id")},
{"uv",new BsonDocument("$push", "$uv")},
{"pv",new BsonDocument("$push", "$pv")},
{"ui",new BsonDocument("$push", "$ui")},
{"ip",new BsonDocument("$push", "$ip")},
{"nuv",new BsonDocument("$push", "$nuv")},
{"area",new BsonDocument("$push", "$area")},
{"rfsite",new BsonDocument("$push", "$rf")},
{"total",new BsonDocument("$sum", )},
{"totalpv",new BsonDocument("$sum", "$pv")},
{"totaluv",new BsonDocument("$sum", "$uv")},
{"totalui",new BsonDocument("$sum", "$ui")},
}; var project = new Dictionary<string, BsonValue>
{
{"day",},
{"pv",},
{"_id",},
{"total",new BsonDocument() {
new BsonElement("row","$total"),
new BsonElement("pv","$totalpv"),
new BsonElement("uv","$totaluv"),
new BsonElement("ui","$totalui"),
}},
{"area",},
{"uv",},
{"ui",},
{"nuv",},
{"ip",},
{"rfsite",},
}; var sitedayOptions = new List<BsonDocument>() {
new BsonDocument("$match",BsonDocument.Create(match)),
new BsonDocument("$group",BsonDocument.Create(group)),
new BsonDocument("$sort",new BsonDocument("_id",)),
new BsonDocument("$group",BsonDocument.Create(groupby)),
new BsonDocument("$project",BsonDocument.Create(project)),
}; var rel = sitesday.Aggregate(sitedayOptions);
//return rel.ToBsonDocument().ToString(); var result = rel.ResultDocuments.ElementAtOrDefault();
if (rel != null && rel.ResultDocuments.Count() > )
{
var rfbson= new BsonDocument() { };
result.ToBsonDocument().Add("rf", new BsonDocument() { });
foreach (var rfitem in result["rfsite"][].AsBsonArray)
{
foreach (var ritem in rfitem.ToBsonDocument())
{
if (result["rf"].ToBsonDocument().FirstOrDefault(e => e.Name.Equals(ritem.Name)) == null)
{
rfbson.Add(ritem.Name, ritem.Value.AsInt32);
}
else
{
rfbson[ritem.Name] = (rfbson[ritem.Name].AsInt32 + ritem.Value.AsInt32);
}
}
}
result["rf"] = rfbson;
}
return result.ToBsonDocument().ToString();
}
C#使用MapReduce实现对分片数据的分组的更多相关文章
- TableInputFormat分片及分片数据读取源码级分析
我们在MapReduce中TextInputFormat分片和读取分片数据源码级分析 这篇中以TextInputFormat为例讲解了InputFormat的分片过程以及RecordReader读取分 ...
- MapReduce中TextInputFormat分片和读取分片数据源码级分析
InputFormat主要用于描述输入数据的格式(我们只分析新API,即org.apache.hadoop.mapreduce.lib.input.InputFormat),提供以下两个功能: (1) ...
- shuffle机制和TextInputFormat分片和读取分片数据(九)
shuffle机制 1:每个map有一个环形内存缓冲区,用于存储任务的输出.默认大小100MB(io.sort.mb属性),一旦达到阀值0.8(io.sort.spill.percent),一个后台线 ...
- 使用Hadoop的MapReduce与HDFS处理数据
hadoop是一个分布式的基础架构,利用分布式实现高效的计算与储存,最核心的设计在于HDFS与MapReduce,HDFS提供了大量数据的存储,mapReduce提供了大量数据计算的实现,通过Java ...
- IOS第七天(3:UiTableView 模型和数据的分组的显示)
*************UiTableView模型和数据的分组的显示 #import "HMViewController.h" #import "HMHero.h&qu ...
- Java将数据进行分组处理
将传人的数据进行分组,使用map保存每组的数据. /** * 将取出的数据进行分组 * @param list * @return */ public Map<Integer,Object> ...
- 数据可视化之powerBI技巧(十七)在Power BI中对数据进行分组
根据某一个维度的数据,进行分组统计,是很常见的做法,比如按年龄对客户进行分组,按考试成绩进行分组统计等,这篇文章介绍一下,在PowerBI中如何对数据进行分组. 在PowerQuery编辑器中分组 在 ...
- MapReduce分析明星微博数据
互联网时代的到来,使得名人的形象变得更加鲜活,也拉近了明星和粉丝之间的距离.歌星.影星.体育明星.作家等名人通过互联网能够轻易实现和粉丝的互动,赚钱也变得前所未有的简单.同时,互联网的飞速发展本身也造 ...
- mapreduce导出MSSQL的数据到HDFS
今天想通过一些数据,来测试一下我的<基于信息熵的无字典分词算法>这篇文章的正确性.就写了一下MapReduce程序从MSSQL SERVER2008数据库里取数据分析.程序发布到hadoo ...
随机推荐
- JDK8 特性详解
Base64 对Base64编码的支持已经被加入到Java 8官方库中,这样不需要使用第三方库就可以进行Base64编码,例子代码如下: package com.cn.yunliu.jdk8; imp ...
- 无用之flask
Oldboy s4 Flask Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收 ...
- vue全家桶+Koa2开发笔记(2)--koa2
1. 安装koa脚手架的时候 执行命令 koa2 -e koa-learn 注意要使用-e的方式,才会生成ejs的模板 2. async await的使用方法:存在的意义:提高promise的可读性 ...
- classLoader卸载与jvm热部署
以下的相关介绍都是在未使用dcevm的情况 classLoader的卸载机制 jvm中没有提供class及classloader的unload方法.那热部署及osgi中是通过什么机制来实现的呢?实现思 ...
- Bow & Arrow 学习
using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI; ...
- java数据类型取值范围
1个字节:boolean, byte 2个字节:short, char 4个字节:int, float 8个字节:long, double 按照我们初学者的理解1byte=8bit,也就是说1个字节可 ...
- kubernetes 中,Pod、Deployment、ReplicaSet、Service 之间关系分析
deploy控制RS,RS控制Pod,这一整套,向外提供稳定可靠的Service. 详见:https://blog.csdn.net/ucsheep/article/details/81781509
- ts项目报错:Import sources within a group must be alphabetized
报错:Import sources within a group must be alphabetized. 原因:import名称排序问题,要求按照字母从小到大排序:修改 tslint.json 中 ...
- vue-router 与 react-router 设计理念上的区别
vue-router 与 react-router 设计理念上的区别: 区别 vue-router react-router 改成history mode: 'history' 直接使用 react- ...
- C# 控件
.ascx:Web窗体用户控件.用来存放独立的用户控件,可提供众多页面使用: <%@ Control Language="C#" AutoEventWireup=" ...