posts - 283,  comments - 6275,  trackbacks - 107

      之前的文章中介绍了如何基于Mongodb进行关系型数据的分布式存储,有了存储就会牵扯到查询。虽然用普通的方式也可以进行查询,但今天要介绍的是如何使用MONGODB中提供的MapReduce功能进行查询。
      有关MongoDb的MapReduce之前我写过一篇文章 Mongodb Mapreduce 初窥

      今天介绍如何基于sharding机制进行mapreduce查询。在MongoDB的官方文档中,这么一句话:      

   Sharded Environments
      In sharded environments, data processing of map/reduce operations runs in parallel on all shards.

      
      即: map/reduce操作会并行运行在所有的shards上。
      下面我们就用之前这篇文章中白搭建的环境来构造mapreduce查询:
      

      首先要说的是,基于sharding的mapreduce与非sharding的数据在返回结构上有一些区别,我目前注意到的主要是不支持定制式的json格式的返回数据,也就是下面方式可能会出现问题:     
     

   return { count : total };

      
      注意:上面的情况目前出现在了我的测试环境下,如下图:
     
         
     
     就需要改成 return count;
    
     下面是测试代码,首先是按帖子id来查询相应数量(基于分组查询实例方式):     
    

public partial class getfile : System.Web.UI.Page
    {

        
public Mongo Mongo { getset; }


        
public IMongoDatabase DB
        {
            
get
            {
                
return this.Mongo["dnt_mongodb"];
            }
        }

        
/// <summary>
        
/// Sets up the test environment.  You can either override this OnInit to add custom initialization.
        
/// </summary>
        public virtual void Init()
        {
            
string ConnectionString = "Server=10.0.4.85:27017;ConnectTimeout=30000;ConnectionLifetime=300000;MinimumPoolSize=512;MaximumPoolSize=51200;Pooled=true";
            
if (String.IsNullOrEmpty(ConnectionString))
                
throw new ArgumentNullException("Connection string not found.");
            
this.Mongo = new Mongo(ConnectionString);
            
this.Mongo.Connect();         
        }
        
string mapfunction = "function(){\n" +
                        
"  if(this._id=='548111') { emit(this._id, 1); } \n" +   
                        
"};";

        
string reducefunction = "function(key, current ){" +
                                
"   var count = 0;" +
                                
"   for(var i in current) {" +
                                
"       count+=current[i];" +
                                
"   }" +
                                
"   return count ;\n" +
                              
"};";

      
        
protected void Page_Load(object sender, EventArgs e)
        {
            Init();

            var mrb 
= DB["posts1"].MapReduce();//attach_gfstream.files
            int groupCount = 0;
            
using (var mr = mrb.Map(mapfunction).Reduce(reducefunction))
            {
                
foreach (Document doc in mr.Documents)
                {
                    groupCount 
= int.Parse(doc["value"].ToString());
                }
            }
            
this.Mongo.Disconnect();
        }     
     }

 

     
     下面是运行时的查询结果,如下:
     
          
     
     
     接着演示一下如何把查询到的帖子信息返回并装入list集合,这里只查询ID为548110和548111两个帖子:     
        

        string mapfunction = "function(){\n" +
                        
"  if(this._id=='548110'|| this._id=='548111') { emit(this, 1); } \n" +    
                        
"};";

        
string reducefunction = "function(doc, current ){" +
                                
"   return doc;\n" +
                               
"};";
      
        
protected void Page_Load(object sender, EventArgs e)
        {
            Init();

            var mrb 
= DB["posts1"].MapReduce();//attach_gfstream.files
            List<Document> postDoc = new List<Document>();
            
using (var mr = mrb.Map(mapfunction).Reduce(reducefunction))
            {
                
foreach (Document doc in mr.Documents)
                {
                    postDoc.Add((Document)doc[
"value"]);
                }
            }
            
this.Mongo.Disconnect();
        }

 

     
     下面是运行时的查询结果,如下:
     
         
    

     上面的map/reduce方法还有许多写法,如果大家感兴趣可以看一下如下这些链接:     
     http://cookbook.mongodb.org/patterns/unique_items_map_reduce/
     http://www.mongodb.org/display/DOCS/MapReduce
    
     以及之前我写的这篇文章:http://www.cnblogs.com/daizhj/archive/2010/06/10/1755761.html
    
    
     当然在mongos进行map/reduce运算时,会生成一些临时文件,如下图:
  
     
     我猜这些临时文件可能会对再次查询系统时的性能有一些提升(但目前未观察到)。
    
     当然对于mongodb的gridfs系统(可使用它搭建分布式文件存储系统,我之前在这篇文章中已介绍过,我也做了测试,但遗憾的是并未成功,它经常会报一些错误,比如:     
    

 

 

   Thu Sep 09 12:09:29   Assertion failure _grab client\parallel.cpp 461 

 

         
     看来mapreduce程序链接到mongodb上时,会产生一些问题,但不知道是不是其自身稳定性的原因,还是我的机器环境设置问题(内存或配置的64位系统mongos与32位的client连接问题)。
    
     好了,今天的文章就先到这里了。   


     原文链接:http://www.cnblogs.com/daizhj/archive/2010/09/09/1822264.html

     BLOG: http://daizhj.cnblogs.com/

     作者:daizhj,代震军

标签: mongodb, shard, map, reduce
posted on 2010-09-09 14:14 代震军 阅读(3038) 评论(8) 编辑 收藏

FeedBack:
2010-09-09 21:30 | javincoder      
沙发
 回复 引用 查看   
2010-09-10 00:13 | 《小YY》      
Code 方式的条件查询 性能不太高吧?特别是做高性能查询的时候。。

当然前端应该存在2层或者3层缓存。

 回复 引用 查看   
#3楼[楼主]
2010-09-10 09:15 | 代震军      
@《小YY》
如果是文件分布式存储的话,可以使用前端缓存,我之前写过这方面的文章,链接:http://www.cnblogs.com/daizhj/archive/2010/08/19/1803454.html
但数据分布式存储就要因查询复杂情况而定了。另外效率测试正在进行中...

 回复 引用 查看   
#4楼[楼主]
2010-09-10 09:15 | 代震军      
@javincoder
呵呵

 回复 引用 查看   
2010-09-10 15:03 | 麦子|君子兰      
问下代大侠,索引一般在什么时候创建?
 回复 引用 查看   
#6楼[楼主]
2010-09-10 15:14 | 代震军      
@麦子|君子兰
如果是MONGODB数据库,索引可以必须在有一条记录的情况下(或全部数据添加完毕后)创建,tokyocabinet下也是如此。

 回复 引用 查看   
2011-05-31 19:51 | 酷&酷      
为什么我的报错,是不是源码的问题啊,db assertion failure

 回复 引用 查看   
2011-05-31 20:08 | 酷&酷      
@代震军
为什么我照着你的写分组出现错误:db assertion failure

 回复 引用 查看   
昵称:代震军
园龄:5年11个月
荣誉:推荐博客
粉丝:492
关注:3

<2010年9月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

搜索

 
 

常用链接

随笔分类(366)

随笔档案(283)

文章分类(8)

文章档案(31)

相册

JavaScript

LINQ

silverlight

UML,OO

WebBlogger

负载开源项目

  • Discuz!NT
  • LLServer
  • TokyoTyrantClient
  • WebCam

个人简历

漫画

其它

企业级架构

网站案例研究

积分与排名

  • 积分 - 1217876
  • 排名 - 26

最新评论

阅读排行榜

评论排行榜

推荐排行榜