Hadoop
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
Hadoop的核心就是HDFS和MapReduce,而两者只是理论基础,不是具体可使用的高级应用,Hadoop旗下有很多经典子项目,比如HBase、Hive等,这些都是基于HDFS和MapReduce发展出来的。要想了解Hadoop,就必须知道HDFS和MapReduce是什么。
HDFS(Hadoop Distributed File System,Hadoop分布式文件系统)
MapReduce(编程模型)
Hadoop典型应用有:搜索、日志处理、推荐系统、数据分析、视频图像分析、数据保存等。
HDFS(Hadoop Distributed File System,Hadoop分布式文件系统),它是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,适合那些有着超大数据集(large data set)的应用程序
HDFS的设计特点是:
1、大数据文件,非常适合上T级别的大文件或者一堆大数据文件的存储,如果文件只有几个G甚至更小就没啥意思了。
2、文件分块存储,HDFS会将一个完整的大文件平均分块存储到不同计算器上,它的意义在于读取文件时可以同时从多个主机取不同区块的文件,多主机读取比单主机读取效率要高得多得都。
3、流式数据访问,一次写入多次读写,这种模式跟传统文件不同,它不支持动态改变文件内容,而是要求让文件一次写入就不做变化,要变化也只能在文件末添加内容。
4、廉价硬件,HDFS可以应用在普通PC机上,这种机制能够让给一些公司用几十台廉价的计算机就可以撑起一个大数据集群。
5、硬件故障,HDFS认为所有计算机都可能会出问题,为了防止某个主机失效读取不到该主机的块文件,它将同一个文件块副本分配到其它某几个主机上,如果其中一台主机失效,可以迅速找另一块副本取文件。
MapReduce:是一套从海量数据中提取分析元素最后返回结果集的编程模型。将文件分布式存储到硬盘是第一步,而从海量数据中提取分析我们需要的内容就是MapReduce做的事了。
MapReduce的基本原理就是:将大的数据分析分成小块逐个分析,最后再将提取出来的数据汇总分析,最终获得我们想要的内容。当然怎么分块分析,怎么做Reduce操作非常复杂,Hadoop已经提供了数据分析的实现,我们只需要编写简单的需求命令即可达成我们想要的数据。
Hadoop例子运行
WordCount(单词计数)
单词计数是最简单也是最能体现MapReduce思想的程序之一,可以称为 MapReduce版"Hello World"。
单词计数主要完成功能是:统计一系列文本文件中每个单词出现的次数。
1. 将文件拆分成splits,由于测试用的文件较小,所以每个文件为一个split,并将文件按行分割形成<key,value>对,如下图所示。这一步由MapReduce框架自动完成,其中偏移量(即key值)包括了回车所占的字符数。
2. 将分割好的<key,value>对交给用户定义的map方法进行处理,生成新的<key,value>对。
3. 得到map方法输出的<key,value>对后,Mapper会将它们按照key值进行排序,并执行Combine过程,将key至相同value值累加,得到Mapper的最终输出结果。
4. Reducer先对从Mapper接收的数据进行排序,再交由用户自定义的reduce方法进行处理,得到新的<key,value>对,并作为WordCount的输出结果。
使用hadoop实例:
将需要处理分析的文件先上传到HDFS上,在从HDFS下下载所需文件,再通过MapReduce进行单词计数,将计数结果上传到HDFS文件中;最后可以直接从hdfs中下载计数结果,将结果进行分析处理
第一步:将本地的文件上传到hdfs
public static void main(String[] args) throws Exception { try { uploadToHdfs(); //把本地文件上传到hdfs;;;主要使用此函数 //deleteFromHdfs(); //从hdfs上面删除文件 // getDirectoryFromHdfs(); //获取hdfs的目录信息 // appendToHdfs(); //追加文件内容到hdfs上某一个文件 //readFromHdfs(); //读取hdfs某一个文件内容 } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("SUCCESS"); } } /** 上传文件到HDFS上去 */ private static void uploadToHdfs() throws FileNotFoundException, IOException { String localSrc = "E:/file/1/java.txt"; //本地上传文件的内容 String dst = "hdfs://192.168.146.175:9000/in14/java"; //上传到hdfs的地址 //通过java的IO流读取本地的文件。 InputStream in = new BufferedInputStream(new FileInputStream(localSrc)); Configuration conf = new Configuration(); // 用来读取Hadoop配置文件 FileSystem fs = FileSystem.get(URI.create(dst), conf); //标准的hadoop文件操作api OutputStream out = fs.create(new Path(dst), new Progressable() { //回调函数 public void progress() { System.out.print("."); } }); //使用Hadoop工具包去上传 文件in 输入流 ,out 输出流 ,每一次的大小,是否输出完毕后进行自动关闭 IOUtils.copyBytes(in, out, 4096, true); } /** 从HDFS上读取文件 */ private static void readFromHdfs() throws FileNotFoundException, IOException { String dst = "hdfs://192.168.168.10:9000/input2/test.rar"; Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(dst), conf); FSDataInputStream hdfsInStream = fs.open(new Path(dst));//是打开hadoop的这个文件的流 File F1=new File("e:\\qqhdfs.rar"); if(!F1.exists()) F1.createNewFile(); OutputStream out = new FileOutputStream("e:\\qqhdfs.rar"); byte[] ioBuffer = new byte[4096]; int readLen = hdfsInStream.read(ioBuffer); while (-1 != readLen) { out.write(ioBuffer, 0, readLen); readLen = hdfsInStream.read(ioBuffer); } out.close(); hdfsInStream.close(); fs.close(); } /** * 以append方式将内容添加到HDFS上文件的末尾;注意:文件更新,需要在hdfs-site.xml中添 * <property><name>dfs.append.support</name><value>true</value></property> */ private static void appendToHdfs() throws FileNotFoundException, IOException { String dst = "hdfs://192.168.168.10:9000/input2/test.rar"; Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(dst), conf); FSDataOutputStream out = fs.append(new Path(dst)); int readLen = "zhangzk add by hdfs java api".getBytes().length; while (-1 != readLen) { out.write("zhangzk add by hdfs java api".getBytes(), 0, readLen); } out.close(); fs.close(); } /** 从HDFS上删除文件 */ private static void deleteFromHdfs() throws FileNotFoundException, IOException { String dst = "hdfs://192.168.146.175:9000/in20/C"; Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(dst), conf); fs.deleteOnExit(new Path(dst)); fs.close(); } /** 遍历HDFS上的文件和目录 */ private static void getDirectoryFromHdfs() throws FileNotFoundException, IOException { String dst = "hdfs://192.168.121.131:9000/test"; Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(URI.create(dst), conf); FileStatus fileList[] = fs.listStatus(new Path(dst)); int size = fileList.length; for (int i = 0; i < size; i++) { System.out.println("name:" + fileList[i].getPath().getName() + "--/t/tsize:" + fileList[i].getLen()); } fs.close(); } }
|
第2步:从hdfs的out文件夹中将文件进行下载,读取内容,并进行单词计数等操作;
Count.java///单词计数,从hdfs中的in中读取文件进行单词计数,将计数结构写入hdsf的out文件夹中
public class Count { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "字符统计"); job.setJarByClass(com.hwadee.Count.class); //设置执行任务的主类 job.setMapperClass(AddressMap.class); //设置map的类 job.setCombinerClass(AddressReduce.class); // 因为hadoop是一个分布式,所有它会在每个节点进行一个预处理 job.setReducerClass(AddressReduce.class); //设置Reduce 类 ,最终的结果输出
job.setOutputKeyClass(Text.class); //告诉最终输出的key是什么类型 job.setOutputValueClass(LongWritable.class); //输出的value是什么类型
//告诉MapReduce执行什么数据作为输出,这里的路径必须是HDFS的路径 FileInputFormat.setInputPaths(job, new Path("hdfs://IP:9000/in/address")); //路径中的目录必须不能存在,需要它自己创建,否则会提示错误 FileOutputFormat.setOutputPath(job, new Path("hdfs://IP:9000/output/address")); if (!job.waitForCompletion(true)) return; } }
|
AddressMap.java////根据地区计数
public class AddressMap extends Mapper<LongWritable, Text, Text, LongWritable> { private final static LongWritable one = new LongWritable(1); //以方便后面reduce的时候进行计数 private Text word = new Text(); //作为我们单词关键字 public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException { String line=ivalue.toString();///每行一个数据 String sp=finsub(line,4,5).substring(0, 2);///将每个数据中截取到所需内容,例地区名 word.set(sp); context.write(word, one);///写入地区和出现次数到文件中 } public static String finsub(String u,int min,int max) {//根据所需内容的位置并且读取内容 int m3=0,m4=0; String sub=""; Matcher slashMatcher = Pattern.compile("\t").matcher(u);///每个数据都是以\t分隔开 int mIdx = 0; while(slashMatcher.find()) { mIdx++; //当"/"符号第三次出现的位置 if(mIdx == min){ m3=slashMatcher.start(); } if(mIdx == max) m4=slashMatcher.start(); } sub=u.substring(m3+1,m4); return sub; } } |
AddressReduce.java |
public class AddressReduce extends Reducer<Text, LongWritable, Text, LongWritable> { private LongWritable result = new LongWritable(); public void reduce(Text _key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException { long sumtotal = 0; for (LongWritable val : values) { sumtotal = val.get() + sumtotal; } result.set(sumtotal); context.write(_key, result); } } |
第三步:最后直接可以从hdfs中的out文件夹下下载文件或查看文件就可以看到计数结果;再进行分析即可