事由: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. vue 移动端的一些ui

    https://www.jianshu.com/p/b79b3b721cd5 Vant. YDUI. Vonic. buefy (bluma的ui) Vux

  2. centos安装jdk1.8

    一.安装Java环境 1. 删除系统预装的opensdk或其他sdk 用命令 java -version 验证是否存在sdk 2. 下载Java JDK约定的版本 版本:Java SE Develop ...

  3. 深入学习Motan系列(二)——服务发布

    闯关经验: 袋鼠走过了第一关,顺利搭建出了Demo,信心爆棚.不过之后,心想怎么去研究这个框架呢.查了一下,官方文档,好像没什么东西可以研究啊.后来,又搜了搜博客,因为这是微博的框架嘛,所以搜索时用百 ...

  4. maven settings.xml配置优化

    <?xml version="1.0" encoding="UTF-8"?> <settings> <localRepositor ...

  5. Java中的继承抽象类和接口

    一.总结 1.使用extends关键字继承,eg: class Student extends Persion { ...}; 2.Java编程规范中类的首字母大写,方法的首字母小写单词首字母代谢,e ...

  6. How to get checksum by IAR

  7. 普林斯顿数学指南(第一卷) (Timothy Gowers 著)

    第I部分 引论 I.1 数学是做什么的 I.2 数学的语言和语法 I.3 一些基本的数学定义 I.4 数学研究的一般目的 第II部分 现代数学的起源 II.1 从数到数系 II.2 几何学 II.3 ...

  8. 围棋术语 & 中英文 。

    https://senseis.xmp.net/?ChineseGoTerms 一字 二字 三字 四字 一字 长(nobi,solid extension),是指仅靠着自己的棋盘上已有棋子继续向前延伸 ...

  9. js过滤输入的emoji表情

    因为emoji表情是Unicode编码, 在某些流浪器上会显示乱码, 有的数据库字节不够也无法存储, 网上有很多解决此类问题的办法, 最简单的莫过于将emoji表情替换成文本, 比如 [表情][表情] ...

  10. TypeScript 之 JSX

    https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/JSX.html JSX中,类型断言必须使用as操作符. 类型检查 ...