hadoop07--词频统计、级联删除、hdfs的文件读写、mapreduce的wordCount

一:统计6个文件的单词和单词总数

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 统计6个文件的总的词频:
 * 1.统计每一个文件的词频(每个单词出现的次数)
 * 2.合并统计总的次数
 * @author dai
 *
 */

public class WordCount01 {
    public static void main(String[] args) throws IOException {
        Map map01 = readOneFile("D:\\data\\word01.txt");
        Map map02 = readOneFile("D:\\data\\word02.txt");
        Map map03 = readOneFile("D:\\data\\word03.txt");
        Map map04 = readOneFile("D:\\data\\word04.txt");
        Map map05 = readOneFile("D:\\data\\word05.txt");
        Map map06 = readOneFile("D:\\data\\word06.txt");
        System.out.println(map02);


        System.out.println(map01);
        System.out.println(map03);
        System.out.println(map04);
        System.out.println(map05);
        //统计所有小文件的总的词频  将每个小文件的统计结果拿出来   放在一个大的map中进行总的统计
        Map mergeAllFile = mergeAllFile(map01,map02,map03,map04,map05,map06);
        System.out.println(mergeAllFile);
    }



    /*
     * 统计每一个文件的词频  单词---次数
     *  创建一个字符流
     *  每行读取,将读取的内容进行分割,获取每一个单词
     *  结果存在map集合中:key--单词     value--出现的次数
     * 返回值:结果   map
     * 参数:String path
     *      
     */
    public static Map readOneFile(String path) throws IOException{
        BufferedReader br=new BufferedReader(new FileReader(path));
        String line=null;
        Map map=new HashMap();
        while((line=br.readLine())!=null){
            String[] words = line.split("\t");
            //循环遍历  放在map集合中
            for(String w:words){
                //map集合中还没有放过
                if(!map.containsKey(w)){
                    map.put(w, 1);
                }else{
                    //将原来的值取出来  +1
                    int newvalue=map.get(w)+1;
                    map.put(w, newvalue);
                }
            }
        }
        return map;
    }
    /**
     * 统计所有的小文件的额总的词频
     * @return
     * 可变参数    
     * 定义的时候:
     *  类型... 可变参数的名字
     * 使用的时候:
     * 实际需要几个参数就传几个参数
     */
    public static Map mergeAllFile(Map...maps){
        Map endMap=new HashMap();
        //循环遍历可变参数所有的map   获取到每一个map
        for(Map map:maps){
            //对每一个map进行循环遍历  获取到每一个单词的出现的次数
            Set> entrySet = map.entrySet();
            for(Entry entry:entrySet){
                String key = entry.getKey();
                Integer value = entry.getValue();
                //如果没放过  直接放进去   key  value直接不变放入
                if(!endMap.containsKey(key)){
                    endMap.put(key, value);
                }else{
                    //放过   将原来的取出来  +  新的value
                    Integer oldvalue = endMap.get(key);
                    Integer finalvalue=oldvalue+value;
                    endMap.put(key, finalvalue);
                }
            }
        }
        return endMap;
    }

}

二:统计6个文件的总的单词数


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 统计6个文件的总的词频
 * 统计每一个文件的词频(每个单词出现的次数)
 * 合并统计总的次数
 * @author dai
 *
 */

public class WordCount2 {
    public static void main(String[] args) throws IOException {
        Map map01 = readOneFile("D:\\data\\word01.txt");
        Map map02 = readOneFile("D:\\data\\word02.txt");
        Map map03 = readOneFile("D:\\data\\word03.txt");
        Map map04 = readOneFile("D:\\data\\word04.txt");
        Map map05 = readOneFile("D:\\data\\word05.txt");
        Map map06 = readOneFile("D:\\data\\word06.txt");
        System.out.println(map02);


        System.out.println(map01);
        System.out.println(map03);
        System.out.println(map04);
        System.out.println(map05);
        //统计所有小文件的总的词频  将每个小文件的统计结果拿出来   放在一个大的map中进行总的统计
        Map mergeAllFile = mergeAllFile(map01,map02,map03,map04,map05,map06);
        System.out.println(mergeAllFile);
    }



    /*
     * 统计每一个文件单词总数
     */
    public static Map readOneFile(String path) throws IOException{
        BufferedReader br=new BufferedReader(new FileReader(path));
        String line=null;
        Map map=new HashMap();
        int count=0;
        while((line=br.readLine())!=null){
            String[] words = line.split("\t");
            //循环遍历  放在map集合中
            for(String w:words){
                count++;
            }
        }
        map.put("总单词", count);
        return map;
    }
    /**
     * 统计所有的小文件的总单词个数
     */
    public static Map mergeAllFile(Map...maps){
        Map endMap=new HashMap();
        //循环遍历可变参数所有的map   获取到每一个map
        int count=0;
        for(Map map:maps){
            //对每一个map进行循环遍历  获取到每一个单词的出现的次数
            Set> entrySet = map.entrySet();
            for(Entry entry:entrySet){
                String key = entry.getKey();
                Integer value = entry.getValue();
                count+=value;
            }
        }
        endMap.put("总单词", count);
        return endMap;
    }

}

三:删除HDFS集群中的所有空文件和空目录


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

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

/**
 * 删除HDFS集群中的所有空文件和空目录   /
 *      判断给定的目录是否是空目录;
        获取给定的目录下的所有的文件或目录:
            如果是文件:
                判断文件的长度是否为0
                    0   删除
            如果是目录:
                判断是否是空目录:
                    是:删除
                    不是:递归 操作
                父目录是否是空目录

 * @author dai
 *
 */

public class DeleteEmptyFileAndDic {
    public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException {
        Configuration conf=new Configuration();
        FileSystem fs=FileSystem.get(new URI("hdfs://hadoop01:9000"),conf,"hadoop");
        Path path=new Path("/");
        deleteEmpty(fs, path);
    }

    /**
     * 参数:
     * @throws IOException 
     * @throws FileNotFoundException 
     */
    public static void deleteEmpty(FileSystem fs,Path path) throws FileNotFoundException, IOException{
        //获取给定路径下的文件或目录
        FileStatus[] listStatus = fs.listStatus(path);
        //判断是否是一个空目录
        if(listStatus.length==0){
            fs.delete(path,false);
        }else{
            //不是空目录  进行循环遍历
            for(FileStatus fs1:listStatus){
                Path childpath=fs1.getPath();
                //判断是否是文件
                if(fs1.isFile()){
                    if(fs1.getLen()==0){
                        fs.delete(childpath, false);
                    }
                }else{
                    deleteEmpty(fs,childpath);
                }
            }
            //到这里 需要判断父目录是否是空
            FileStatus[] listStatus02=fs.listStatus(path);
            if(listStatus02.length==0){
                deleteEmpty(fs,path);
            }

        }
    }

}

四、从hdfs文件的任意位置开始读取一定长度到另一个文件

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

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

/*
 * 从随机地方开始读,读任意长度     
 * 将hdfs的文件从随机的地方开始读   读取任意长度   
 * 读取完成的内容方法hdfs的一个指定目录下
 * 流的方式:
 *  hdfs(in)------hdfs(out)
 * 
 */
public class RandomRead {
    public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException {
        Random random =new Random();
        //conf
        Configuration conf=new Configuration();
        //fs
        FileSystem fs=FileSystem.get(new URI("hdfs://hadoop01:9000"),conf,"hadoop");
        //hdfs的输入流
        FSDataInputStream in = fs.open(new Path("/testcrc01"));
        in.seek(10L);
        //hdfs的输出流
        FSDataOutputStream out = fs.create(new Path("/testRandom"));
        //参数3:需要复制的字节长度
        IOUtils.copyBytes(in, out, 15L, true);
    }

}

五、手动拷贝某个特定的数据块(比如某个文件的第二个数据块)


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

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
import org.apache.hadoop.io.IOUtils;

/*
 * 手动拷贝某个特定的数据块(比如某个文件的第二个数据块)
 * 从hdfs-----hdfs
 */
public class ReadSecondaryBlock {
    public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException {
        //conf
        Configuration conf=new Configuration();
        //fs
        FileSystem fs=FileSystem.get(new URI("hdfs://hadoop01:9000"),conf,"hadoop");
        //输入
        FSDataInputStream in = fs.open(new Path("/hadoop-2.7.6.tar.gz"));

        RemoteIterator listFiles = fs.listFiles(new Path("/hadoop-2.7.6.tar.gz"), false);
        //System.out.println(listFiles.next().getLen());
        //System.out.println(listFiles.next().getLen());
        //数据块   给定的路径下有几个块就有几个长度
        BlockLocation[] blockLocations = listFiles.next().getBlockLocations();
        BlockLocation secondary=blockLocations[1];
        //获取第二个块 的偏移量
        long offset = secondary.getOffset();
        in.seek(offset);
        //获取第二个块的长度
        long length = secondary.getLength();
        //输出
        FSDataOutputStream out = fs.create(new Path("/hadoop_secondary_block"));
        IOUtils.copyBytes(in, out, length, true);
    }

}

六、第一个mapreduce程序:wordcount


import java.io.IOException;
import java.io.Serializable;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

/*
 * map函数做分的工作
 */
/**
 *  map这里:
 *      拆分出来的每一个单词   标记1   输出就可以   统计工作reduce上了

 * 输入:  k-v  这里的输入是框架写死的,固定的内容
 * KEYIN, 输入的键的类型   在这里指的是偏移量------指的是每一行起始的偏移量    long
 * VALUEIN:输入的值的类型,在这里指的是一行的内容     string
 * 例如,第一行:
 *  KEYIN:0
 * VALUEIN:hadoop   hadoop  spark   mllib   sqoop

 * 输出:  k-v  取决于用户的业务
 * KEYOUT, 输出的键的类型,这里指的是单词,可以允许重复   string类型
 * VALUEOUT  输出的值的类型  这里指的是1     int类型

 *序列化和反序列化
 *  数据需要持久化或网络传输的时候,需要Serializable
 所以所有map端、reduce传输的数据必须是经过序列化和反序列化的
 *hadoop中自定义了一套序列化和反序列化的接口:
 *
 为什么没有使用java中序列化反序列化方法?
 因为java中的序列化和反序列化接口Serializable(将类结构一并可进行序列化和反序列化)  过于臃肿

 序列化对应的类型
 *Writable
 *long-----longWritable
 *int-----intwritable
 *double---doublewritable
 *float-----floatwritable
 *
 *null-----nullwritable
 *string-----text
 */
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
    //重写map方法
    /**
     * key:输入的键,这里指的每一行的起始偏移量
     * value:指的输入的值,这里指的是每一行的内容,和key是对应的
     * context:上下文对象,用于传输使用的
     * 这个方法的调用频率:
     *  每行调用一次  文本中有几行就调用几次
     */
    @Override
    protected void map(LongWritable key,
            Text value, 
            Context context)
            throws IOException, InterruptedException {
        //拿到每一行的内容并且进行分割  
        //将text转化为String
        String line = value.toString();
        //拆分单词
        String[] words = line.split("\t");
        //循环遍历每一个单词,进行打标标记1,发送给reduce进行统一统计
        for(String w:words){
            Text k=new Text(w);
            IntWritable v=new IntWritable(1);
            context.write(k, v);
        }

    }

}


import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

/**
 * reduce输出结果:   单词,词频
 * 
 * reduce的输入:map输出的
 * KEYIN, map输出的key,指的就是单词      text类型
 * VALUEIN, map输出的value,指的就是1    IntWritable类型
 * 输出:最终写出到文件的

 * KEYOUT, 输出的key的类型,这里指的就是单词 这里的key是不可以重复的  text类型
 * VALUEOUT:输出的value的类型,这里指的就是总的词频   intwritable类型
 *
 */
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
    /**
     * 这个方法的调用频率:每组调用一次,有几组会调用几次
     * 分组规则:
     *  key相同的为一组
     * hello,1   hello,1 hadoop,1  hello,1
     * key:reduce输入的  这里指的是单词   每一组中的一个key
     * values:每一组中的所有value  <1,1,1>
     */
    @Override
    protected void reduce(Text key, 
            Iterable values,
            Context context) throws IOException, InterruptedException {
        //进行词频统计
        int sum=0;
        //循环变遍历values   求和
        for(IntWritable v:values){
            //v.get()  这个是将intwritable转换为int
            sum+=v.get();
        }
        context.write(key, new IntWritable(sum));
    }
}

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


public class Driver {
    /**
     * 
     * @param args   参数封装的是程序运行过程中需要的参数
     * 运行程序的时候  传入的第一个参数  分装在args的第一个元素了  下标0   第二个参数封装在数组的第二个元素了
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //加载配置文件
        Configuration conf=new Configuration();
        //启动一个job  一个map  reduce程序  这里叫做一个job
        Job job=Job.getInstance(conf);

        //指定job运行的主类
        job.setJarByClass(Driver.class);

        //指定这个job的mapper类和reduce类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        //指定map的输出的key  和  value的类型
        //这里为什么还要指定     泛型的只在编译的时候有作用  运行会自动擦除   所以在这里需要指定一下
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //指定reduce输出的key和value类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //多个小文件运行的时候:  修改输入类
        job.setInputFormatClass(CombineTextInputFormat.class);
        //修改切片大小
        CombineTextInputFormat.setMinInputSplitSize(job, 130*1024*1024);

        //FileInputFormat.setMaxInputSplitSize(job, 100);//设置最大值    《128
        //FileInputFormat.setMinInputSplitSize(job, 130*1024*1024);//设置最下值     》128

        //指定输入路径   需要统计词频的路径
        CombineTextInputFormat.addInputPath(job,  new Path(args[0]));
        //FileInputFormat.addInputPath(job, new Path(args[0]));
        //添加输出路径    输出路径一定不能存在     怕如果存在会进行覆盖
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        //提交job
        job.waitForCompletion(true);
    }

}

你可能感兴趣的:(hadoop)