『 Hadoop』编程之旅二

MapReduce程序——WordsCount 详解

程序功能:读取文件内容,按照空格或制表符对内容进行切分。并对切分后的内容进行计数,统计该内容出现的次数。

package mapreduce;

import java.io.IOException;
import java.net.URI;
import java.util.Iterator;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job; //新版本的mapreduce包
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordsCount_01 {

    /**
     * 读取文件的地址
     * 与输出文件的地址
     */
    static String INPUT_PATH = "hdfs://master:9000/input/find/*";
    static String OUTPUT_PATH = "hdfs://master:9000/output/WordCount01";
    
    /**
     * Map类,输入了LongWritable和Text类型
     * 输出Text类和IntWritable类
     * 
     * Map(k1,v1)   k1读片偏移量(第几个文件),v1为片内容,一行行读取
     * 将v1转为字符串并按照空格分割成一个个元素存在数组里
     * 最后就是循环把数组里到元素和个数传入到上下文中
     * @author sakura
     *
     */
    static class WordMapper extends Mapper<LongWritable,Text,Text,IntWritable>{
        protected void map(LongWritable key, Text value, 
                org.apache.hadoop.mapreduce.Mapper.Context context) throws IOException, InterruptedException{
            String[] words = value.toString().split("\\s"); //  转义后到 \s 匹配任意数量到空格和换行和制表符
            for(String word : words){
                context.write(new Text(word), new IntWritable(1));
            }
        };
    }
    
    /**
     * Reducer类,输入Text和IntWritable类型
     * 输出Text,IntWritable类型
     * 
     * Reducer(k2,v2)   k2=key  即k1不重复值的列表  每个reduce方法一次只处理一个key(已经被排序去重)
     * v2即key出现的次数列表{1,2,1,4}
     * 把v2的值放入迭代器中,计算值的总和
     * 最后把key的值和总和sum传入到上下文中,就存入到我们到结果文件里
     */
    static class WordReducer extends Reducer<Text,IntWritable,Text,IntWritable>{
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException{
            Iterator<IntWritable> it = values.iterator();
            int sum = 0;
            while(it.hasNext()){
                sum += it.next().get();
            }
            System.out.println("sum = " + sum);
            context.write(key, new IntWritable(sum));
        };
    }
    
    public static void main(String[] args) throws Exception {
        
        /**
         * mr要初始化Configuration,需读取配置文件
         * 因为开发mapreduce时候只是在填空,在map函数和reduce函数里编写实际进行的业务逻辑,
         * 其它的工作都是交给mapreduce框架自己操作的,但是至少我们要告诉它怎么操作,即在conf下到配置文件里
         */
        Configuration conf = new Configuration();
        
        /**
         * 新建HDFS文件系统,读取输出文件夹
         * 如果文件夹已经存在,则删除之
         */
        FileSystem fs = FileSystem.get(new URI(INPUT_PATH),conf);
        Path outPath = new Path(OUTPUT_PATH);
        if(fs.exists(outPath)){
            fs.delete(outPath,true);
            System.out.println(outPath+"地址已经存在,已重建");
        }
        
        /**
         * 第一行就是在构建一个job,在mapreduce框架里一个mapreduce任务也叫mapreduce作业也叫做一个mapreduce的job,
         * 而具体的map和reduce运算就是task了,这里我们构建一个job,
         * 构建时候有两个参数,一个是conf,一个是这个job的名称,随意取。
         */
        Job job = new Job(conf,"wordcount");
        
        /**
         * 装载一个mapreduce能执行到job的类,即WordsCount_01.class
         */
        job.setJarByClass(WordsCount_01.class);
        
        /**
         * 构建输入到数据文件
         * 和输出的数据文件
         */
        FileInputFormat.addInputPath(job, new Path(INPUT_PATH));
        FileOutputFormat.setOutputPath(job, outPath);
        
        /**
         * 装载Map实现类
         * combiner阶段,在Reducer前就对相同到key进行了合并操作,使用原则,不影响到reduce计算的最终输入
         * 和Reducer实现类
         */
        job.setMapperClass(WordMapper.class);
        job.setCombinerClass(WordReducer.class);//map运算到后续操作,在map计算出中间文件前做一个简单的合并重复key值的操作,比如重复的单词直接增加v1
        job.setReducerClass(WordReducer.class);
        
        /**
         * 定义输出的key/value的类型,也就是最终存储在hdfs上结果文件的key/value的类型。
         */
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        
        /**
         * 等待job运行成功
         */
        job.waitForCompletion(true);
        
        System.out.println("ending");
    }

}

读取的文件内容


输出的结果


MapReduce程序——WordComparator 详解

程序功能:将wordsCount输出的内容按值进行降序排序。

package mapreduce;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.IntWritable.Comparator;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordComparator {

    static String INPUT_PATH = "hdfs://master:9000/output/WordCount01/p*";
    static String OUTPUT_PATH = "hdfs://master:9000/output/WordCount01/out";

    /**
     * @param args
     * @throws IOException
     * @throws IllegalArgumentException
     * @throws InterruptedException
     * @throws ClassNotFoundException
     */
    public static class myComparator extends Comparator {
        @SuppressWarnings("rawtypes")
        public int compare(WritableComparable a, WritableComparable b) {
            return -super.compare(a, b);
        }

        /**
         * 以字节方式比较两个Writable对象,比较值的大小
         * byte[] b1表示第一个参数的输入字节表示,byte[] b2表示第二个参数的输入字节表示
         * b1表示前8个字节,b2表示后8个字节,字节是按次序依次比较的
         * s1 The position index in b1. The object under comparison's starting index.第一列开始位置
         * l1 The length of the object in b1.第一列长度 ,在这里表示长度8
         */
        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
            return -super.compare(b1, s1, l1, b2, s2, l2);
        }
    }

    /**
     * 
     * @author sakura
     *  读取文件内容,按照制表符切分
     *  将切分得到的第二份内容,即单词出现到次数作为Key传出去
     *  将切分得到到第一份内容,即单词的内容作为Value传出去
     */
    public static class Map extends Mapper<Object, Text, IntWritable, Text> {
        public void map(Object key, Text value, Context context)
                throws NumberFormatException, IOException, InterruptedException {
            String[] split = value.toString().split("\t");
            context.write(new IntWritable(Integer.parseInt(split[1])), new Text(split[0]));
        }
    }

    /**
     * 
     * @author sakura
     *  因为mapreduce会自动对key进行排序,因此只要将读到的内容反向传出即可
     *  即单词出现到次数作为Value传出去
     *  即单词的内容作为Key传出去
     */
    public static class Reduce extends Reducer<IntWritable, Text, Text, IntWritable> {
        public void reduce(IntWritable key, Iterable<Text> values, Context context)
                throws IOException, InterruptedException {
            for (Text text : values) {
                context.write(text, key);
            }
        }
    }

    public static void main(String[] args)
            throws IllegalArgumentException, IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
        // TODO Auto-generated method stub
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI(INPUT_PATH),conf);
        Path outPath = new Path(OUTPUT_PATH);
        if(fs.exists(outPath)){
            fs.delete(outPath,true);
            System.out.println(outPath+"地址已经存在,已重建");
        }
        
        Job job = new Job();
        job.setJarByClass(WordComparator.class);

        job.setNumReduceTasks(1); // 设置reduce进程为1个,即output生成一个文件

        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);

        job.setMapOutputKeyClass(IntWritable.class);
        job.setMapOutputValueClass(Text.class);

        job.setOutputKeyClass(Text.class); // 为job的输出数据设置key类
        job.setOutputValueClass(IntWritable.class); // 为job的输出设置value类

        job.setSortComparatorClass(myComparator.class); // 自定义排序

        FileInputFormat.addInputPath(job, new Path(INPUT_PATH)); // 设置输入文件的目录
        FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH)); // 设置输出文件的目录

        System.exit(job.waitForCompletion(true) ? 0 : 1); // 提交任务
    }

}

结果截图


通过这个我们,就可以试着分析一些我们想要分析的东西啦。

比如我喜欢看江南的《龙族》,所以我试着简单地切分它,看看它哪句话说得最多噢,哈哈哈
结果如下:


但是现在还不能实现很好地切分中文词,我正在学习当中啦!
我还有个大胆地想法,小数据分析自己的聊天记录,切分看看自己哪些词用得最多..... 然后嘿嘿嘿(逃

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容