事由: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. 给Linux服务器设置共享文件目录

    通过samba软件 :yum install samba 修改配置文件:vi /etc/samba/smb.conf 添加 [WORKSPACE] comment = workspace       ...

  2. Odoo9以后的社区版本和企业版功能上的区别

    Odoo9以后的社区版本和企业版除了授权模式的区别外,整理功能上的区别 透过功能设置菜单整理的区别如下,主要功能模块. 未包括所有模块,毕竟模块太多了. 以下是企业版有,而社区版没有的功能.

  3. 第一个程序HelloWorld及常见问题解决和练习

    public class hello world{ public static void main(String[] args){ System.out.println(); } } 注意事项: 源文 ...

  4. ionic项目中 软键盘弹出之后的问题:

    Android SDK目前提供的软键盘弹出模式接口只有两种: 一是弹出时自动回冲界面,将所有元素上顶: 一种则是不重绘界面,直接将控件元素遮住:     1. ionic 中弹出键盘遮挡住输入框(覆盖 ...

  5. stl本子

    记事本,不要想到奇怪的地方去 迭代器什么的不会玩quq set: #include<set> set<int> quq; quq.insert(qvq); -- 插入 quq. ...

  6. django+uwsgi+nginx数据表过大引起"out of memory for query result"

    昨天负责的一个项目突然爆“out of memory for query result”. 背景 项目的数据表是保存超过10m的文本数据,通过json方式保存进postgres中,上传一个13m的大文 ...

  7. 依赖注入的方式测试ArrayList和LinkedList的效率(对依赖注入的再次理解)

    9/20 号再进行学习 在C++中,main函数尽可能的简单,只要调用子函数的一句话就实现了功能. java开发中,controller就相同于是main函数,其他类的方法不在本类中时候, 1.可以用 ...

  8. nginx日志分割配置实例

    Nginx没有类似Apache的cronolog日志分割处理的功能,但是,可以通过nginxNginx的信号控制功能利用脚本来实现日志的自动切割.请看下面的一个实例.Nginx对日志进行处理的脚本: ...

  9. shell基础入门(一)

    //获取输入内容 #!/bin/bash echo "What is your name?" read PERSON read -p "who are you name: ...

  10. linux 条件

    1.文件状态测试-d 目录 -r 可读-f 常规文件 -w 可写-L 符号连接 -x 可执行-s 文件长度大于0,非空 -u 文件有suid位设置 示例: [ -s haison.c ] 0表示成功, ...