Spring hadoop之一 mongodb与hadoop的整合使用

在上一章节 我们讲到了hbase的使用回顾, 这一章我们将一下同样是nosql的另一分支 mongodb 基于文档型数据库

mongodb的基本使用  下面是一张与oracle mysql这种关系型数据库的对比

基本操作 crud

db.users.insert( {
    user_id: "abc123",
    age: 55,
    status: "A"
 } )
db.users.update(                       
    { },
    { $set/$unset: { join_date: new Date() } },   
    { multi: true }
)
db.users.drop()
查找全部
db.users.find();
查找通过statu=a 查找该列 0 代表 不查找该列 1代表查找该列
db.users.find(
    { status: "A" },
    { user_id: 1, status: 1, _id: 0 }
)
相当于 SELECT user_id, status
FROM users
WHERE status = "A"

还有好多 like 查询 count统计查询 group by等等 mongodb也是支持的

详细使用见官方文档,这里只是先温习加mongodb基本使用,我们本节的重点是怎么整合mongodb与hadoop

mongodb官方 有一个开源项目 mongodb-hadoop该项目是使mongodb能作为hadoop数据库

    

这样 你就可以某种情况下可以替代hbase cassicade了

pom文件加入相关依赖

  
            org.mongodb
            mongo-hadoop
            1.0.0            
        
        
        
            org.mongodb
            mongo-hadoop-core
            1.1.0
        
        
        
            org.apache.hadoop
            hadoop-core
            0.20.2
        
            

同时还要加上mongod连接java的驱动 

 
            org.mongodb
            mongo-java-driver
            2.11.2
        

这里上面的图涉及到了PIG pig本来我想介绍下,发现网络上有几篇非常好的文章 

这里我就不献丑了

地址

转文章来源:http://www.codelast.com/
(1)Apache Pig的一些基础概念及用法总结(1)

(2)Apache Pig的一些基础概念及用法总结(2)

(3)Apache Pig中文教程(进阶)

(4)使用Apache Pig时应该注意/避免的操作或事项

这里不详细介绍了 还有个HIVE IMPALA 以后有时间会讲下

很多时候 我们是用sqoop相关工具 把关系型数据库导入到相关Hbase数据库 而导入mongodb 的话网上应该有好多工具导入,以及自带的命令mongoexport  同oracle一样sqlldr 。。。等

上面说到mongodb 官方提供的mongodb-hadoop用于mongodb与hadoop进行整合

上篇文章http://my.oschina.net/yilian/blog/175525 讲到了DBobject这个对象  他代表的mongodb的一个document 的每一行存的BJSON类型 的java对象 可以看成key-value形式

正常的时候 我们知道mongodb 数据库是提供一个mapreduce方法调用 

使用方法类似

	JSONObject json = null;
         DBObject query = new BasicDBObject();
		String mapper = "function(){ emit( this.name,this.money); }";
		String reduce = "function(key, values){ var count=0; for(var i in values){ count+=values[i]; } return {'name':key,'money':count};}";

		MapReduceOutput out = getCollection().mapReduce( mapper , reduce , "" + System.currentTimeMillis() , query );

		DBCursor cur = out.getOutputCollection().find();
		while ( cur.hasNext() )
		{
			query = cur.next();

			json = JSONObject.fromObject( query );

			
		}
		out.drop();

这里注意 几个参数 对于为什么这么写 怎么写mapreduce?请参考官方的文档 地址,以及后面附件的图片

http://docs.mongodb.org/manual/reference/command/mapReduce/#dbcmd.mapReduce

 /**
     * performs a map reduce operation
     * Runs the command in REPLACE output mode (saves to named collection)
     *
     * @param map
     *            map function in javascript code
     * @param outputTarget
     *            optional - leave null if want to use temp collection
     * @param reduce
     *            reduce function in javascript code
     * @param query
     *            to match
     * @return
     * @throws MongoException
     * @dochub mapreduce
     */
    public MapReduceOutput mapReduce( String map , String reduce , String outputTarget , DBObject query ){
        return mapReduce( new MapReduceCommand( this , map , reduce , outputTarget , MapReduceCommand.OutputType.REPLACE, query ) );
    }

在hadoop中 我们使用monodb作为数据源 读入 进行 mapreduce 处理后 写入,在第一章我们讲到了对于自定义只要实现相应的InputFormat 以及Recorder即可,同样mongodb-hadoop 提供了 相应的实现,他允许使用mongodb(或者是使用BSON作为格式的备份文件)作为hadoop MapReduce的输入源和输出源

这里先说下Mongo-Hadoop的工作流程:

1) Mongo-Hadoop首先检查MongoDB Collection,并计算数据分割
2) 每个分割部分被分配到Hadoop集群中的一个节点
3) 同时,Hadoop节点从MongoDB(或BSON)获取数据,并进行本地处理
4) Hadoop合并结果,并输出到MongoDB或BSON
下面来介绍怎么使用,正常时候实现mapper时候 只要继承mapper类 然后

这里BSON就是下面我们mapper reduce的关键了 下面是一个mapper实现

public class MyMapper
	extends Mapper{

   


	@Override
	public void map(Object key, BSONObject value, final Context context)
        throws Exception{

             //这里key就可以看出每一个collection 的一行 
             //我们上面说说了BsonObject可以看出每一行的列的key-value的形式 
             colvalue=value.get("columname");
		}

}

 同理reduce也是类似写法,注意BsonObject就可以了 此外注意的是BSONWritable

public class MyReducer
        extends Reducer {

  

    @Override
    public void reduce( final IntWritable key,
                        final Iterable values,
                        final Context context )
            throws Exception{
         //.....

        BasicBSONObject output = new BasicBSONObject();
        
        output.put("name", name);
        context.write( key, new BSONWritable( output ) );
    }


}

下面就是继承Configred 实现Tool 来编写一个JOB 这里要注意的是mongodb参数输入地址 输出地址是

mongodb://地址:端口/collection 

还要设置一些属性 这是官方实例中的一段

job.setReducerClass(MongoConfigUtil.getReducer(conf));
job.setMapperClass(MongoConfigUtil.getMapper(conf));
		job.setOutputFormatClass(MongoConfigUtil.getOutputFormat(conf));
		job.setOutputKeyClass(MongoConfigUtil.getOutputKey(conf));
		job.setMapOutputKeyClass(MongoConfigUtil.getMapperOutputKey(conf));

		job.setMapOutputValueClass(MongoConfigUtil.getMapperOutputValue(conf));
		job.setInputFormatClass(MongoConfigUtil.getInputFormat(conf));

也就是说 他把config文件中的配置属性转换成相应的

   public static Class getOutputFormat( Configuration conf ){
        return conf.getClass( JOB_OUTPUT_FORMAT, null, OutputFormat.class );
    }

而getClass就是反射。。很简单吧,其实就是设置InputFormatClass类为 com.mongodb.hadoop.MongoInputFormat outFormatClass类为com.mongodb.hadoop.MongooutputFormat 然后设置mapper类 reduce类为相应的mapper reduce 这里他这样做是使者job工作交给xml配置好,减少job配置 ,采用xml配置,读取xml反射 注入

实际上mongodb-hadoop还提供了一个mongoTool 工具定义好了相应的,只需你配置好xml文件 该类注释上有很详细的使用方法

/**
 * Tool for simplifying the setup and usage of Mongo Hadoop jobs using the Tool / Configured interfaces for use w/ a
 * ToolRunner Primarily useful in cases of XML Config files.
 *
 * @author Brendan W. McAdams 
 */
public class MongoTool extends Configured implements Tool {
    private static final Log log = LogFactory.getLog( MongoTool.class );

    public int run( String[] args ) throws Exception{
        /**
         * ToolRunner will configure/process/setup the config
         * so we need to grab the classlevel one
         * This will be inited with any loaded xml files or -D prop=value params
         */
        final Configuration conf = getConf();  final Job job = new Job( conf, _jobName );
        /**
         * Any arguments specified with -D =
         * on the CLI will be picked up and set here
         * They override any XML level values
         * Note that -D is important - no space will
         * not work as it get spicked up by Java itself
         */
        // TODO - Do we need to set job name somehow more specifically?
        // This may or may not be correct/sane
        job.setJarByClass( this.getClass() );
        final Class mapper = MongoConfigUtil.getMapper( conf );

        log.info( "Mapper Class: " + mapper );
        job.setMapperClass( mapper );
        Class combiner = MongoConfigUtil.getCombiner(conf);
        if (combiner != null) {
            job.setCombinerClass( combiner );
        }
        job.setReducerClass( MongoConfigUtil.getReducer( conf ) );

        job.setOutputFormatClass( MongoConfigUtil.getOutputFormat( conf ) );
        job.setOutputKeyClass( MongoConfigUtil.getOutputKey( conf ) );
        job.setOutputValueClass( MongoConfigUtil.getOutputValue( conf ) );
        job.setInputFormatClass( MongoConfigUtil.getInputFormat( conf ) );
        Class mapOutputKeyClass = MongoConfigUtil.getMapperOutputKey(conf);
        Class mapOutputValueClass = MongoConfigUtil.getMapperOutputValue(conf);

        if(mapOutputKeyClass != null){
            job.setMapOutputValueClass(mapOutputKeyClass);
        }
        if(mapOutputValueClass != null){
            job.setMapOutputValueClass(mapOutputValueClass);
        }

        /**
         * Determines if the job will run verbosely e.g. print debug output
         * Only works with foreground jobs
         */
        final boolean verbose = MongoConfigUtil.isJobVerbose( conf );
        /**
         * Run job in foreground aka wait for completion or background?
         */
        final boolean background = MongoConfigUtil.isJobBackground( conf );
        try {
            if ( background ){
                log.info( "Setting up and running MapReduce job in background." );
                job.submit();
                return 0;
            }
            else{
                log.info( "Setting up and running MapReduce job in foreground, will wait for results.  {Verbose? "
                          + verbose + "}" );
                return job.waitForCompletion( true ) ? 0 : 1;
            }
        }
        catch ( final Exception e ) {
            log.error( "Exception while executing job... ", e );
            return 1;
        }
    }

    /**
     * Main will be a necessary method to run the job - suggested implementation
     * template: 这是使用方法
     * public static void main(String[] args) throws Exception {
     * int exitCode = ToolRunner.run(new (), args);
     * System.exit(exitCode);
     * }
     *
     */

    /**
     * SET ME Defines the name of the job on the cluster. Left non-final to allow tweaking with serial #s, etc
     */
    String _jobName = "";
}

这个类 你可以继承 重载,也可以直接使用,常用的一个xml配置文件 我在官方实例中找的 ,去掉一些不必要的东西

 

    
        
        mongo.job.verbose
        true
    
    
        
        mongo.job.background
        false
    
    
        
        mongo.input.key
        
    
    
        
        mongo.input.uri
        mongodb://localhost:27017/basetest.videoAttachments
    
    
        
        mongo.output.uri
        mongodb://localhost:27017/basetest.videoMapReduceResult
    
    
        
        mongo.input.query
        
        
    
    
        
        mongo.input.fields
        
    
    
        
        mongo.input.sort
        
    
    
        
        mongo.input.limit
        0 
    
    
        
        
        mongo.input.skip
        0 
    
    
        
        mongo.job.mapper
        ru.switchsocial.hadoop.SimpleMapper
    
    
        
        mongo.job.reducer
        ru.switchsocial.hadoop.SimpleReducer
    
    
        mongo.job.input.format
        com.mongodb.hadoop.MongoInputFormat
        
    
    
    
    
    
        
        mongo.job.output.format
        com.mongodb.hadoop.MongoOutputFormat 
    
  
    
        mongo.job.output.key
        org.apache.hadoop.io.IntWritable
    
    
        mongo.job.output.value
        com.mongodb.hadoop.io.BSONWritable
    
    
        mongo.job.mapper.output.key
        
        org.apache.hadoop.io.IntWritable
    
    
        mongo.job.mapper.output.value
        org.apache.hadoop.io.IntWritable
    
    
    
        
        mongo.job.partitioner
        
    
    
        
        mongo.job.sort_comparator
        
    

这里注意的是 上面的配置 我修改成我自己的后运行后发现爆出了calculate input splits: need to login错误

http://stackoverflow.com/questions/16916146/hadoop-error-unable-to-calculate-input-splits-need-to-login/16925434#16925434  这上面提出了解决方案

只要加上conf.setBoolean(“mongo.input.split.create_input_splits”, false); 即可

为什么需要这样呢?我查找了官方文档发现了这么一段话

也就是说 共享 与 非共享collections 的处理的true false问题 

这里还有个问题,有可能会提示找不到xxx错误,其实只要把mongodb-hadoop复制到hadoop 的lib目录下 或者hadoop add jar命令也可以即可

下面大家就可以拿官方examples文件去按照上述去运行了。。

在这里我要提的是mongodb 其实提供了group by  sort  aggregation 等一些函数 aggregation其实也是mapreduce的优化实现 这里希望大家去看看也就是说,上面的其实可以直接通过他实现

详细文档地址http://docs.mongodb.org/manual/applications/aggregation/

另外附录几张 图片帮助理解

这里要说的是mongodb可作为hadoop storm spark s3的数据源还是不错的,stackoverflow上面有些与hbase cassisade对比的帖子,关键是 他可以从hdfs 可以从关系数据库到 可以从hbase 等等导入导出

这篇文章是本人抽出时间 多次修改草稿编写的,也许有些不衔接的 请见谅,在找工作中!没多少时间更新,几天才出这篇,最近也在研究apache mohout 这个数据挖掘 推荐算法 分析 的东西,下一章 有可能会更新impala 这个比hive高效的查询框架,hive会稍微提下,有什么问题可以在下面留言回复,本人项目一直在cloudra的伪分布式运行。。关于cloudra这个网站的的工具 ,很方便安装hadoop的各种环境,大家百度搜索就有好多相关文档教程,,以前有个hadoop4win只能安装基本环境,而cloudra很方便,其实impala也是这个公司开源的一个框架

还有就是 我没有讲到sping-hadoop这项目的任何东西,其实前面的知识只是基础,后面讲完了体系后,会讲hbaseTemplate pigTemplate hiveTemplate…等等很方便处理hadoop的常用操作,统一讲一下源代码怎么实现,以及他的回调机制


声明:OSCHINA 博客文章版权属于作者,受法律保护。未经作者同意不得转载。

本文转载于:文章来自KENGINE | Kankanews.com

你可能感兴趣的:(hadoop)