调研系列第二篇:HCatalog简介

1.         一般的hdfs读写

传统的对于hdfs的读写都是直接设置inputPath  outPath ,而且对于数据都是以文件的形式访问的,不涉及到结构化/半结构化的东东,及时如hive存储在hdfs的的结构化数据,外部系统访问也只能自己去了解具体的结构是如何存储的,然后自己读文件再访问,传统访问hdfs的方式如下:

使用InputFormatSplitRecordReader用于读,具体方式如下:

List<InputSplit> InputFormat.getSplits() ; 

RecordReader  InputFormat. createRecordReader(InputSplit split) ;

RecordReader. nextKeyValue();

RecordReader. getCurrentValue();

这样的流程来访问 

使用OutputFormatRecordWriter来写入hdfs数据,具体如下:

OutputFormat. getRecordWriter();

RecordWriter.write(K key, V value)

对于一般的table结构数据,都是将Key值置成NullWritable,作为一个无用的值来存储。

2.         Hcataloghdfs的结合:定义了文件的schema

HCatalog将每份结构化的hdfs数据定义schema和访问信息(dbtablepartition),然后读和写的时候使用dbtablepartition(对于无partition这个可以为空)这三部分信息来访问相应的表数据,屏蔽掉表底层InputFormatOutFormat以及path信息,读&&写时候只许关系以下几个访问类即可:

HCatInputFormat<WritableComparable, HCatRecord>

HCatRecordReader<WritableComparable, HCatRecord>

 

HCatOutputFormat<WritableComparable<?>, HCatRecord>

FileRecordWriterContainer<WritableComparable<?>, HCatRecord>

几个类就行了,读写的接口Value均是HCatRecord对象,Key值是WritableComparable即可,不过一般key值都是NullWritable,并无实际用途 

3.         对象HCatRecord 

内部存储这Object[]数组,分别存储一行数据中每列的值,为hive基本类型的Java对象(intStringlistMap等),对于复杂结构可以嵌套,主要访问接口如下 

List<Object> getAll();

Object get(int fieldIndex);

Object get(String fieldName, HCatSchema recordSchema)

通过列名称来访问具体列的值,但是需要tableschema信息HCatSchema(具体每列的colName以及每个colName对应的fieldIndex

这点设计不是很好,感觉可以将HCatSchema内置到HCatRecord  中,这样封装性可能会更好一些 

4.         HCatalog的元数据存储 

HCatalog存储元数据和Hive的元数据是一致的,对于元数据的存储底层也是调用hive底层HiveMetaStoreClient的接口(我们常用的Hive其实是在这个类上封装了一层),其提供对于元数据库的各种操作(creat drop alter load insert等等 

直接调用Hive接口/hive的客户端 写入的元数据在HCatalog中可以直接用,同样HCatalog写入的元数据以及数据在hive中也是可以直接使用的。

5.         HCatInputFormat:读取HCatalog中数据的接口

读取的时候需要dbNametableNamepartition(这个可以没有)tableProperties(可以没有)信息,存储于InputJobInfo中,InputJobInfo是读取时候的信息存储封装,在jobclient端初始化以后,使用Java的序列化Serializable转换成byte[],然后将byte[]编码成一个字符串存储(参见HCatUtilencodeBytesdecodeBytes方法)hadoop的配置Configuration来在整个mr任务中传递。

InputJobInfo初始化创建的时候只需要dbNametableNamepartition(这个可以没有)tableProperties(可以没有)信息,在InitializeInput.getInputJobInfo方法中去连接元数据库,补齐InputJobInfo中的HCatTableInfopartitions信息,对于不是分区的table,构造一个partition信息,将相应数据存储在里面。

getSplits(JobContext jobContext)方法,从conf配置中反序列化出InputJobInfo信息,然后根据partition中的信息,利用inputFormatClasslocationsplit成真正的底层数据的split,在封装成HCatSplit

HCatSplit结构

最终读取的时候还是要利用PartInfo中的SerDe来读取相应的数据,后面介绍

 

createRecordReader(InputSplit split, TaskAttemptContext taskContext)方法

返回的是封装了一层的HCatRecordReader对象,然后通过HCatRecordReader. Initialize(split,taskContext)来初始化具体的读信息baseRecordReader 

一切初始化完毕,就可以开始调用经典的nextKeyValue的方法了

baseRecordReader是底层的RecordReader ,读出来数据后使用相应的SerDedeserialize方法反序列化成ObjectInspector(一般是StructObjectInspector)可以访问的数据格式,然后通过相应的colnum ObjectInspector得到每列的具体Java object值,然后封装到HCatRecord对象中 

 对于hive基本类型转换成Java的基本类型,对于structlist转换成JavaListmap转换成Javamap

6.         HcatalogMR程序中的输出类HCatOutputFormat

input对应的,OutputJobInfo是存储用于输出数据时候的信息的,其结构如下:

主要是table的相关信息

OutputJobInfo outPutInfo=OutputJobInfo.create("analyse_db","contline_revenue_day_cut", partitions);

      也是需要dbNametblNamepartition就可以初始化,通过HCatOutputFormat.setOutput(conf, credentials,outPutInfo)中连接metastore,然后补充其余的schemaSerdeoutputFormat等一系列信息 ,目前Hcata中对于hive的自建Index、内置压缩、分桶和sort的特性还是不支持的,然后同样在利用序列化这个对象成String,存储与MR的配置conf ,提供给以后的程序共享使用。

getRecordWriter(TaskAttemptContext context)方法

先得到一个封装后的OutputFormatContainer,这个其实就是内部包装了一个这个table数据真正的OutputFormat对象,以FileOutputFormatContainer为例,以下是FileOutputFormatContainer. getRecordWriter(TaskAttemptContext context)方法 

主要是做了一些MR程序中输出文件夹初始化的工作,然后就是返回了一个FileRecordWriterContainer对象,该对象和上面的OutputFormat一样,内部封装了一个table实际存储的OutputFormat返回的RecordWriter baseWriter ,最终真正用于向hdfs写数据的对象,FileRecordWriterContainer如下:

其中初始化了几个变量

serDe :用于序列化写到hdfs的数据

objectInspector :用于访问HCatRecord 

这里面还是利用了hive中的这一套SerdeObjectInspector的封装来做的 

7.         单机关于读/写的两个Java demo 

write

 1 package com.baidu.rigel.hactalog;
 2 
 3 import java.io.IOException;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import org.apache.hadoop.conf.Configuration;
 8 import org.apache.hadoop.io.WritableComparable;
 9 import org.apache.hadoop.mapreduce.Job;
10 import org.apache.hadoop.mapreduce.OutputCommitter;
11 import org.apache.hadoop.mapreduce.RecordWriter;
12 import org.apache.hadoop.mapreduce.TaskAttemptContext;
13 import org.apache.hadoop.mapreduce.TaskAttemptID;
14 import org.apache.hive.hcatalog.data.DefaultHCatRecord;
15 import org.apache.hive.hcatalog.data.HCatRecord;
16 import org.apache.hive.hcatalog.data.schema.HCatFieldSchema.Type;
17 import org.apache.hive.hcatalog.data.schema.HCatSchema;
18 import org.apache.hive.hcatalog.mapreduce.FileOutputCommitterContainer;
19 import org.apache.hive.hcatalog.mapreduce.HCatOutputFormat;
20 import org.apache.hive.hcatalog.mapreduce.OutputJobInfo;
21 
22 public class HcataLogWriteTestMain {
23 
24     public static void main(String[] args) throws IOException, InterruptedException {
25         Map<String,String> partitions = new HashMap<String, String>(1);
26         partitions.put("pdate", "2011-09-24");
27         Configuration conf =new Configuration();
28         Job job = new Job(conf, "GroupByAge");
29         OutputJobInfo outPutInfo=OutputJobInfo.create("analyse_db","contline_revenue_day_cut", partitions);
30         HCatOutputFormat.setOutput(job, outPutInfo);
31         HCatSchema s = HCatOutputFormat.getTableSchema(job.getConfiguration());
32         System.out.println("INFO: output schema explicitly set for writing:"
33                 + s);
34         //同样,序列化,然后设置到conf配置中  
35         HCatOutputFormat.setSchema(job, s);
36         HCatOutputFormat outFormat= new HCatOutputFormat();
37         // attempt_20140328173000_500575_m000_000000_0     task_20131314_0758_r_000100 
38         job.getConfiguration().set("mapred.task.partition", "1");
39         TaskAttemptID tmp= new TaskAttemptID("20140328173000",500575,true,0,0);
40         job.getConfiguration().set("mapred.task.id", "attempt_20140328173000_500575_m_000000_0");
41         TaskAttemptContext taskTmp=new TaskAttemptContext(job.getConfiguration(),tmp);
42         RecordWriter<WritableComparable<?>, HCatRecord> hcataWrite=outFormat.getRecordWriter(taskTmp);
43         hcataWrite.close(null);
44         for(int i=0;i<100;i++){
45             HCatRecord record = new DefaultHCatRecord(s.getFields().size());
46             for(int k=0;k<s.getFields().size();k++){
47                 if(s.get(k).getType()==Type.BIGINT)
48                     record.set(k, Long.parseLong(i+""));
49                 else if(s.get(k).getType()==Type.STRING)
50                     record.set(k, i+"_ddctest");
51             }
52             hcataWrite.write(null, record);
53         }
54         hcataWrite.close(taskTmp);
55         
56 //        System.out.println(outPutInfo.getDatabaseName());
57 //        System.out.println("******************************************************");
58 //        System.out.println(outPutInfo.getHarRequested());
59 //        System.out.println("******************************************************");
60 //        System.out.println(outPutInfo.getLocation());
61 //        System.out.println("******************************************************");
62 //        System.out.println(outPutInfo.getMaxDynamicPartitions());
63 //        System.out.println("******************************************************");
64 //        System.out.println(outPutInfo.getTableName());
65 //        System.out.println("******************************************************");
66 //        System.out.println(outPutInfo.getOutputSchema());
67 //        System.out.println("******************************************************");
68 //        System.out.println(outPutInfo.getPartitionValues());
69 //        System.out.println("******************************************************");
70 //        System.out.println(outPutInfo.getProperties());
71 //        System.out.println("******************************************************");
72 //        System.out.println(outPutInfo.getTableInfo());
73     }
74 
75 }

readTest

 1 package com.baidu.rigel.hactalog;
 2 
 3 import java.io.IOException;
 4 import java.util.List;
 5 
 6 import org.apache.hadoop.conf.Configuration;
 7 import org.apache.hadoop.io.WritableComparable;
 8 import org.apache.hadoop.mapred.JobConf;
 9 import org.apache.hadoop.mapreduce.InputSplit;
10 import org.apache.hadoop.mapreduce.Job;
11 import org.apache.hadoop.mapreduce.RecordReader;
12 import org.apache.hadoop.mapreduce.TaskAttemptContext;
13 import org.apache.hadoop.mapreduce.TaskAttemptID;
14 import org.apache.hive.hcatalog.common.HCatConstants;
15 import org.apache.hive.hcatalog.data.HCatRecord;
16 import org.apache.hive.hcatalog.data.schema.HCatSchema;
17 import org.apache.hive.hcatalog.mapreduce.HCatInputFormat;
18 
19 public class HcataLogReadTestMain {
20 
21     public static void main(String[] args) throws IOException, InterruptedException {
22         Configuration conf = new  Configuration();
23         JobConf job=new JobConf(conf);
24 //        InputJobInfo inputInfo=InputJobInfo.create("analyse_db", "contline_revenue_day","pdate=\"2014-03-09\"",new Properties());
25         HCatInputFormat hIntput=HCatInputFormat.setInput(job, "analyse_db", "contline_revenue_day");
26         hIntput.setFilter("pdate=\"2014-03-09\"");
27         Job jobContext=new Job(job);
28         System.out.println(job.get(HCatConstants.HCAT_KEY_JOB_INFO));
29         hIntput=new HCatInputFormat();
30         List<InputSplit> splitList=hIntput.getSplits(jobContext);
31         HCatSchema hCatSchema=HCatInputFormat.getTableSchema(job);
32         System.out.println(splitList.size());
33         TaskAttemptID tmp= new TaskAttemptID("20131314",758,false,100,200);
34         TaskAttemptContext taskTmp=new TaskAttemptContext(job,tmp);
35         RecordReader<WritableComparable, HCatRecord> reader=hIntput.createRecordReader(splitList.get(0), taskTmp);
36         reader.initialize(splitList.get(0), taskTmp);
37         int cout=0 ;
38         while(reader.nextKeyValue()){
39             HCatRecord row=reader.getCurrentValue();
40             System.out.println(row.get("click_amt", hCatSchema)+"    "+row.get("pdate", hCatSchema));
41             cout++  ;
42         }
43         System.out.println(cout);
44     }
45 
46 }

 

posted @ 2014-05-19 20:31  xiao晓  阅读(12105)  评论(0编辑  收藏  举报