事由: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实现对分片数据的分组的更多相关文章

  1. TableInputFormat分片及分片数据读取源码级分析

    我们在MapReduce中TextInputFormat分片和读取分片数据源码级分析 这篇中以TextInputFormat为例讲解了InputFormat的分片过程以及RecordReader读取分 ...

  2. MapReduce中TextInputFormat分片和读取分片数据源码级分析

    InputFormat主要用于描述输入数据的格式(我们只分析新API,即org.apache.hadoop.mapreduce.lib.input.InputFormat),提供以下两个功能: (1) ...

  3. shuffle机制和TextInputFormat分片和读取分片数据(九)

    shuffle机制 1:每个map有一个环形内存缓冲区,用于存储任务的输出.默认大小100MB(io.sort.mb属性),一旦达到阀值0.8(io.sort.spill.percent),一个后台线 ...

  4. 使用Hadoop的MapReduce与HDFS处理数据

    hadoop是一个分布式的基础架构,利用分布式实现高效的计算与储存,最核心的设计在于HDFS与MapReduce,HDFS提供了大量数据的存储,mapReduce提供了大量数据计算的实现,通过Java ...

  5. IOS第七天(3:UiTableView 模型和数据的分组的显示)

    *************UiTableView模型和数据的分组的显示 #import "HMViewController.h" #import "HMHero.h&qu ...

  6. Java将数据进行分组处理

    将传人的数据进行分组,使用map保存每组的数据. /** * 将取出的数据进行分组 * @param list * @return */ public Map<Integer,Object> ...

  7. 数据可视化之powerBI技巧(十七)在Power BI中对数据进行分组

    根据某一个维度的数据,进行分组统计,是很常见的做法,比如按年龄对客户进行分组,按考试成绩进行分组统计等,这篇文章介绍一下,在PowerBI中如何对数据进行分组. 在PowerQuery编辑器中分组 在 ...

  8. MapReduce分析明星微博数据

    互联网时代的到来,使得名人的形象变得更加鲜活,也拉近了明星和粉丝之间的距离.歌星.影星.体育明星.作家等名人通过互联网能够轻易实现和粉丝的互动,赚钱也变得前所未有的简单.同时,互联网的飞速发展本身也造 ...

  9. mapreduce导出MSSQL的数据到HDFS

    今天想通过一些数据,来测试一下我的<基于信息熵的无字典分词算法>这篇文章的正确性.就写了一下MapReduce程序从MSSQL SERVER2008数据库里取数据分析.程序发布到hadoo ...

随机推荐

  1. java-冒泡排序、选择排序、二分查找

    1.冒泡排序 public void bubbleSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { //外循环只需要比较a ...

  2. Linux系统安全笔记

    Linux系统安全笔记 https://insecure.org/https://sectools.org/SecTools.Org:排名前125的网络安全工具 http://www.ibm.com/ ...

  3. C++学习(三)(C语言部分)之 基本数据类型

    基本数据类型 上期回顾 stdlib.h system,命令release MT导入ico文件 基本数据类型 整数 int浮点型(小数 实型) float double字符型 char 变量 常量速度 ...

  4. java 8大数据类型

    第一类:逻辑型boolean 第二类:文本型char 1.JAVA中,char占2字节,16位.可在存放汉字 2.char赋值 char a='a';  //任意单个字符,加单引号. char a=' ...

  5. linux配置防火墙

    centos6.5 防火墙开放80端口 iptables -I INPUT -p tcp –dport 80 -j ACCEPT //注意,dport前面是两个-,其中-I是指在防火墙INPUT表最前 ...

  6. Tomcat环境变量配置命令行报错:The JRE_HOME environment variable is not defined correctl This environment variable is needed to run this program

    1. tomcat——>bin——>setclasspath.bat,使用记事本打开. 2. 添加如下代码即可: 为自己实际的环境变量配置为准!!! set JAVA_HOME=D:\ID ...

  7. Gravitee.io api gateway 试用

    以前写过几篇关于整体介绍的以及 使用docker 运行的简单说明,有了docker-compose 环境我们可以 方便的进行测试使用了. 环境准备 docker-compose 文件   versio ...

  8. EXtJS Ext.data.Model

    (一).首先我们介绍一下Model类中比较常用的几个属性,如果我们想构建一个Model类,最主要的属性就是(Fields)属性,这个属性接受一个数组.用来设置Model中所包含的字段.定义的格式如下: ...

  9. Explicit

    Prefixing the explicit keyword to the constructor prevents the compiler from using that constructor ...

  10. 线性代数笔记13——Ax=b的通解

    关于最简行阶梯矩阵和矩阵秩,可参考<线性代数笔记7——再看行列式与矩阵> 召唤一个方程Ax = b: 3个方程4个变量,方程组有无数解,现在要关注的是b1b2b3之间满足什么条件时方程组有 ...