当前位置: 首页 > news >正文

八、Hbase

Hbase

  • 一、NoSQL非关系型数据库简介
    • 1.NoSQL 的起因
    • 2.NoSQL 的特点
    • 3.NoSQL 面临的挑战
    • 4.NoSQL 的分类
  • 二、HBase数据库概述
    • 1.HBase数据库简介
    • 2.HBase数据模型简介
    • 3.HBase数据模型基本概念
    • 4.Hbase概念视图(逻辑视图)
    • 5.Hbase物理视图
    • 6.Hbase主要组件
    • 7.Hbase安装
    • 8.Hbase的数据读写流程
    • 9.Hbase的数据结构
    • 10.Hbase的rowkey设计
  • 三、Hbase Shell:DDL语句操作
  • 四、Hbase Shell:DML语句操作
  • 五、eclipse操作hbase
    • 1.开发环境配置
      • 1.配置pom.xml文件
      • 2.新建hbase-site.xml文件,放到资源文件目录下
      • 3.新建mapred-site.xml文件,放到资源文件目录下
      • 4.新建log4j.properties文件,放到资源文件目录下
    • 2.JAVA-HBASE:DDL操作
    • 3.JAVA-HBASE:DML操作
    • 4.JAVA-HBASE:DQL操作
    • 5.JAVA-HBASE:filter用法
  • 六、ORC文件转HFILE文件
    • 1.数据准备
    • 2.项目的整体架构
      • 1.配置文件
        • 1.配置pom.xml文件
        • 2.新建assembly.xml文件,放到资源文件目录下
        • 3.拷贝hbase-site.xml、文件,放到资源文件目录下
        • 4.拷贝mapred-site.xml文件,放到资源文件目录下
        • 5.拷贝log4j.properties文件,放到资源文件目录下
      • 2.com.shanhai.util
        • 1.BaseMR
        • 2.JobRunnerResult
        • 3.JobRunnerUtil
        • 4.MyConstant
        • 5.ORCFormat
        • 6.ORCUtil
        • 7.Utils
      • 3.com.shanhai.mr
        • 1.HbaseImportData
      • 4.com.shanhai.bin
        • 1.MyJobRunner
        • 2.MyJobDriver
    • 3.集群配置
    • 4.集群运行
  • 七、Hbase表的预分Region
    • 1.小批量预分Region
    • 2.大批量预分Region
    • 3.如何修改HBase表的压缩格式
  • 八、Hbase数据的批量导入+预分Region
    • 1.需求
    • 2.项目的整体架构
      • 1.配置文件
        • 0.新建split_data文件
        • 1.拷贝pom.xml文件
        • 2.新建assembly.xml文件,放到资源文件目录下
        • 3.拷贝hbase-site.xml、文件,放到资源文件目录下
        • 4.拷贝mapred-site.xml文件,放到资源文件目录下
        • 5.拷贝log4j.properties文件,放到资源文件目录下
      • 2.com.shanhai.util
        • 1.BaseMR
        • 2.JobRunnerResult
        • 3.JobRunnerUtil
        • 4.MyConstant
        • 5.MyRegionSpliter
        • 6.ORCFormat
        • 7.ORCUtil
        • 8.Utils
      • 3.com.shanhai.mr
        • 1.NewHbaseDataImport
      • 4.com.shanhai.bin
        • 1.NHIDJobRunner
        • 2.NHIDJobDriver
    • 3.集群环境配置
    • 4.集群运行
  • 九、HFILE文件转ORC文件
    • 1.HFILE-BY-ORC项目的整体架构
      • 1.配置文件
        • 1.新建assembly.xml文件,放到资源文件目录下
      • 2.com.shanhai.util
        • 6.ORCWriteUtil
      • 3.com.shanhai.mr
        • 1.HfileByOrc
      • 4.com.shanhai.bin
        • 1.HBORunner
        • 2.HBODriver
    • 2.集群运行
    • 3.创建Hive-ORC-外部表
    • 4.验证数据
  • 十、MR读写AVRO文件
    • 1.项目需求:
    • 2.生成测试数据
    • 3.项目的整体架构:
      • 1.com.shanhai.mr
        • 1.AvroToAvro
      • 1.com.shanhai.bin
        • 1.ATARunner
    • 4.线下运行:
    • 5.集群运行
  • 十一、Hbase数据的批量导出
    • 1.项目需求:
    • 2.项目的整体架构:
      • 1.配置文件
        • 1.pom.xml文件
        • 2.新建assembly.xml文件,放到资源文件目录下
      • 2.com.shanhai.util
        • 1.ORCWriteUtil
        • 2.HFileInputFormat:自定义输入格式化类
      • 3.com.shanhai.entity
        • 1.HFileItem
        • 2.HFileRecord
      • 4.com.shanhai.mr
        • 1.NewHbaseDateExport
      • 5.com.shanhai.bin
        • 1.NHDERunner
        • 2.NHDEDriver
    • 3.集群运行

一、NoSQL非关系型数据库简介

1.NoSQL 的起因

随着 Web 2.0 网站的兴起,传统的关系数据库已经无法适应 Web 2.0 网站,特别是超大规模和高并发的社交类型的 Web 2.0 纯动态网站;
NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
1. 无法满足对海量数据的高效率存储和访问的需求
2. 无法满足对数据库的高可扩展性和高可用性的需求
3. 关系数据库无法存储和处理半结构化/非结构化数据
4. 关系数据库的事务特性对 Web 2.0 是不必要的
5. Web 2.0 无须进行复杂的 SQL 查询,特别是多表关联查询

2.NoSQL 的特点

它所采用的数据模型并非关系型数据库的关系模型,而是类似键值、列簇、文档等的数据模型。它打破了长久以来关系型数据库与 ACID(原子性(Atomicity)、一致性(Consistency)隔离性(Isolation)和持久性(Durability))理论大一统的局面。
NoSQL 数据存储不需要固定的表结构,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。
NoSQL 在大数据存取上具备关系型数据库无法比拟的性能优势。
1. 灵活的可扩展性
2. 大数据量和高性能
3. 灵活的数据模型,可以处理半结构化/非结构化的大数据

3.NoSQL 面临的挑战

NoSQL 数据库的前景很被看好,但是要应用到主流的企业还有许多困难需要克服。这里是几个首先需要解决的问题。
1. 成熟度(相比关系数据库系统来说,技术还不够成熟。这种状况会随着时间而改进)
2. 支持(需要资金来维持软件的开发和维护)
3. 分析与商业智能(NoSQL 数据库缺少即时查询和数据分析工具)
4. 管理(NoSQL 的设计目标是提供零管理的解决方案,不过当今还远远没有达到这个目标。)
5. 专业(大多数 NoSQL 开发者还处于学习模式。这种状况会随着时间而改进)

4.NoSQL 的分类

可以将典型的NoSQL 划分为 4 种类型,分别是键值数据库、列式数据库、文档数据库和图形数据库
1. 键值数据库:典型代表-->Redis
它使用一个哈希表,表中的 Key(键)用来定位 Value(值),即存储和检索具体的 Value2. 列式数据库:典型代表-->Hbase
列式数据库起源于 Google 的 BigTable,其数据模型可以看作是一个每行列数可变的数据表
3. 文档数据库:典型代表-->MongoDB
文档数据库是通过键来定位一个文档的,所以是键值数据库的一种衍生品。在文档数据库中,文档是数据库的最小单位。文档数据库可以使用模式来指定某个文档结构。
文档数据库是 NoSQL 数据库类型中出现得最自然的类型,因为它们是按照日常文档的存储来设计的,并且允许对这些数据进行复杂的查询和计算。
4. 图形数据库:典型代表--> Neo4J、OrientDB、InfoGrid、Infinite Graph 和 GraphDB 
图形数据库以图论为基础,用图来表示一个对象集合,包括顶点及连接顶点的边。图形数据库使用图作为数据模型来存储数据,可以高效地存储不同顶点之间的关系。
图形数据库是 NoSQL 数据库类型中最复杂的一个,旨在以高效的方式存储实体之间的关系。

二、HBase数据库概述

1.HBase数据库简介

HBase 是基于 Apache Hadoop 的面向列的 NoSQL 数据库,是 Google 的 BigTable 的开源实现。
HBase 是一个针对半结构化数据的开源的、多版本的、可伸缩的、高可靠的、高性能的、分布式的和面向列的动态模式数据库。
HBase 和传统关系数据库不同,它采用了 BigTable 的数据模型增强的稀疏排序映射表(Key/Value),其中,键由行关键字、列关键字和时间戳构成。
HBase 提供了对大规模数据的随机、实时读写访问。
HBase 的目标是存储并处理大型的数据,也就是仅用普通的硬件配置,就能够处理上千亿的行和几百万的列所组成的超大型数据库。
Hadoop 是一个高容错、高延时的分布式文件系统和高并发的批处理系统,不适用于提供实时计算,
而 HBase 是可以提供实时计算(占用大量的内存)的分布式数据库,数据被保存在 HDFS (分布式文件系统)上,由 HDFS 保证其高容错性。
HBase 上的数据是以二进制流的形式存储在 HDFS 上的数据块中的,但是,HBase 上的存储数据对于 HDFS 是透明的。
HBase 可以直接使用本地文件系统,也可以使用 Hadoop 的 HDFS。
HBase 中保存的数据可以使用 MapReduce 来处理,它将数据存储和并行计算有机地结合在一起。
HBase 是按列族进行数据存储的。每个列族会包括许多列,并且这些列是经常需要同时处理的属性。也就是说,HBase 把经常需要一起处理的列构成列族一起存放,从而避免了需要对这些列进行重构的操作。
HBase 在充分利用列式存储优势的同时,通过列族减少列连接的需求。

2.HBase数据模型简介

HBase 是一个稀疏、多维度、有序的映射表。
这张表中每个单元是通过由行键、列族、列限定符和时间戳组成的索引来标识的。
每个单元的值是一个未经解释的二进制数组(byte[]),没有数据类型。当用户在表中存储数据时,每一行都有一个唯一的行键和任意多的列。
表的每一行由一个或多个列族组成,一个列族中可以包含任意多个列。在同一个表模式下,每行所包含的列族是相同的,也就是说,列族的个数与名称都是相同的,但是每一行中的每个列族中列的个数可以不同
HBase 中的同一个列族里面的数据存储在一起,列族支持动态扩展,可以随时添加新的列,无须提前定义列的数量。
HBase 执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,原有的版本仍然保留。
如果查询的时候不提供时间戳,那么系统就会返回离当前时间最近的那一个版本的数据。
HBase 提供了两种数据版本回收方式:一种是保存数据的最后3个版本;另一种是保存最近一段时间内的版本,如最近一个月。

3.HBase数据模型基本概念

HBase 中的数据被存储在表中,具有行和列,是一个多维的映射结构。
1. 表(Table)
HBase采用表来组织数据,表由许多行和列组成,列划分为多个列族。
2. 行(Row)
在表里面,每一行代表着一个数据对象。每一行都是由一个行键(Row Key)和一个或者多个列组成的。行键是行的唯一标识,行键并没有什么特定的数据类型,以二进制的字节来存储,按字母顺序排序。
3. 列族(Column Family)
在定义 HBase 表的时候需要提前设置好列族,表中所有的列都需要组织在列族里面。
4. 列限定符(Column Qualifier)
列族中的数据通过列限定符来进行映射。列限定符不需要事先定义,也不需要在不同行之间保持一致。列限定符没有特定的数据类型,以二进制字节来存储。
5. 列(Column)
列由列族(Column Family)和列限定符(Column Qualifier)联合标识,由“ : ”进行间隔,如 family:qualifiero
6. 单元(Cell)
行键、列族和列限定符一起标识一个单元,存储在单元里的数据称为单元数据,没有特定的数据类型,以二进制字节来存储。
HBase提供基于单元的版本管理功能,版本号默认通过timestamp来标识,并且呈倒序排列;
7. 时间戳(Timestamp)
默认情况下,每一个单元中的数据插入时都会用时间戳来进行版本标识。
读取单元数据时,如果时间戳没有被指定,则默认返回最新的数据;
写入新的单元数据时,如果没有设置时间戳,则默认使用当前时间。
每一个列族的单元数据的版本数量都被 HBase 单独维护,默认情况下,HBase 保留 3 个版本数据。

4.Hbase概念视图(逻辑视图)

在这里插入图片描述

上图是 HBase 的概念视图,是一个存储网页信息的表的片段。行键是一个反向 URL,如 www.cnn.com 反向成 com.cnn.www。
反向 URL 的好处就是,可以让来自同一个网站的数据内容都保存在相邻的位置,从而可以提高用户读取该网站的数据的速度。
contents 列族存储了网页的内容;anchor 列族存储了引用这个网页的链接;mime 列族存储了该网页的媒体类型。

5.Hbase物理视图

在这里插入图片描述
虽然从概念视图层面来看,HBase 的每个表是由许多行组成的,但是在物理存储层面来看,它是采用了基于列的存储方式,而不是像关系型据库那样用基于行的存储方式。这正是 HBase 与关系型数据库的重要区别之一。
在概念视图中,可以看到许多列是空的,也就是说,这些列上面不存在值。
在物理视图中,这些空的列并不会存储成 null,而是根本不会被存储,从而可以节省大量的存储空间。当请求这些空白的单元的时候,会返回 null 值。

6.Hbase主要组件

HBase采用Master/Slave架构搭建集群,它隶属于Hadoop生态系统,由以下类型节点组成:
HMaster节点、HRegionServer节点、ZooKeeper集群,而在底层,它将数据存储于HDFS中,因而涉及到HDFS的NameNode、DataNode等,总体结构如下:
在这里插入图片描述

各组件说明:
1.Client:1)使用HBase RPC机制与HMaster和HRegionServer进行通信;2)Client与HMaster进行通信进行管理类操作;3)Client与HRegionServer进行数据读写类操作;2.HMaster:类似于NAMENODE RESOURCEMANAGER
HMaster 没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper保证总有一个Master在运行。
HMaster主要负责Table和Region的管理工作:1)管理用户对表的增删改查操作;2)管理HRegionServer的负载均衡,调整Region分布;3)Region Split后,负责新Region的分布;4)在HRegionServer停机后,负责失效HRegionServer上Region 的迁移;3.HRegionServer:类似于DATANODE NODEMANAGER
HRegionServer一般和DataNode在同一台机器上运行,实现数据的本地性。
HBase中最核心的模块;1)维护region,处理对这些region的IO请求;2)Regionserver负责切分在运行过程中变得过大的region;Region的概念:Region是HBase数据管理的基本单位。数据的move,数据的balance,数据的split,都是按照region来进行操作的。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。一个表中可以包含一个或多个Region。每个Region只能被一个RS(RegionServer)提供服务,RS可以同时服务多个Region,来自不同RS上的Region组合成表格的整体逻辑视图。HRegionServer详解:HRegionServer一般和DataNode在同一台机器上运行,实现数据的本地性。1)HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region。2)一个Table可以有多个Region,他们可以在一个相同的HRegionServer上,也可以分布在不同的HRegionServer上,一个HRegionServer可以有多个HRegion,他们分别属于不同的Table3)HRegion由多个Store(HStore)构成,每个HStore对应了一个Table在这个HRegion中的一个Column Family,即每个Column Family就是一个集中的存储单元,因而最好将具有相近IO特性的Column存储在一个Column Family,以实现高效读取。4)每个HRegionServer中都会有一个HLog对象。HLog对象:数据库的日志。每个HRegionServer中都会有一个HLog对象。用户进行数据写入的时候,会先把所有数据到HLog文件,同时在HDFS进行备份,然后再写入MemStore中,写到一定程度由MemStore根据一定的算法将数据Flush到底层HDFS文件中(HFile)。引入HLog原因:灾难恢复。在分布式系统环境中,无法避免系统出错或者宕机,一旦HRegionServer意外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种情况。5)一个HStore由一个MemStore 和0个或多个StoreFile组成。MemStore:是一个写缓存(In Memory Sorted Buffer),的写在完成WAL日志写后,会 写入MemStore中,由MemStore根据一定的算法将数据Flush到底层HDFS文件中(HFile),通常每个HRegion中的每个 Column Family有一个自己的MemStore。StoreFile(Hfile):用于存储HBase的数据(Cell/KeyValue)。在HFile中的数据是按RowKey、Column Family、Column排序,对相同的Cell(即这三个值都一样),则按timestamp倒序排列。4.Zookeeper:
1)ZooKeeper为HBase集群提供协调服务,它管理着HMaster和HRegionServer的状态(available/alive等),并且保证集群中只有一个HMaster,会在它们宕机时通知给HMaster,从而HMaster可以实现HMaster之间的故障转移;
2)实时监控HRegionServer的上线和下线信息,并实时通知给HMaster;
3)存储HBase的Meta Table(hbase:meta)的位置,Meta Table表存储了集群中所有用户HRegion的位置信息,且不能split;
4)Zookeeper的引入使得Master不再是单点故障 HMaster虽然可以开启多个 但是不是越多越好 两个 --> 只开一个 nn2 贡献出来保存region nn2 没有 block --> 尴尬

7.Hbase安装

1.Hbase启动
#第一步:先启动集群zookeeper
[hadoop@nn1 conf]$ sh ~/zk_base_op/zk_ssh_all.sh /usr/local/zookeeper/bin/zkServer.sh status
[hadoop@nn1 conf]$ sh ~/zk_base_op/zk_ssh_all.sh /usr/local/zookeeper/bin/zkServer.sh start
#第二步:启动集群hdfs
start-dfs.sh
#第三步:启动集群hbase
start-hbase.sh
#启动后查看进程
[hadoop@nn1 conf]$ sh ~/hadoop_base_op/ssh_all.sh jps#开启hbase shell
hbase shell
#查看hbase状态
status
#查看hbase版本
version2.Hbase关闭
#关闭集群hbase
stop-hbase.sh3.开启、关闭hbase单独
hbase-daemon.sh start/stop regionserver
hbase-daemon.sh start/stop master4.查看hbase的web界面
http://nn1.hadoop:600105.查看Hbase日志
[hadoop@nn1 conf]$ cd /usr/local/hbase/logs/
[hadoop@nn1 logs]$ ll
[hadoop@nn1 logs]$ tail -300 hbase-hadoop-master-nn1.hadoop.log6.1在zookeeper中查看hbase meta 表所在的服务器
[hadoop@nn1 ~]$ zkCli.sh -server nn1.hadoop
[zk: nn1.hadoop(CONNECTED) 0] ls /
[zk: nn1.hadoop(CONNECTED) 1] ls /hbase
[zk: nn1.hadoop(CONNECTED) 2] get /hbase/meta-region-server
6.2在zookeeper中查看hbase的 hmaster的所在主机
[zk: nn1.hadoop(CONNECTED) 3] get /hbase/master

8.Hbase的数据读写流程

1.首先客户端寻找HRegionServer,及缓存位置信息
在这里插入图片描述

1.第一步:先从缓存中或zookeeper中获取hbase:meta表的位置(元数据信息位置)
2.第二步:再从缓存中或hbase:meta表中查询用户table对应请求的RowKey所在的HRegionServerde的位置

2.写数据流程
在这里插入图片描述

1)通过2.8.1找到该写数据最终需要去的HRegionServer;
2)然后客户端将写请求发送给相应的HRegionServer,在HRegionServer中它首先会将该写操作写入WAL(Hlog)日志文件中(Flush到磁盘中)3)写完WAL日志文件后,HRegionServer根据Put中的TableName和RowKey,startkey、endkey找到对应的HRegion,并根据Column Family找到对应的HStore,并将Put写入到该HStore的MemStore中。
4)此时写成功,并返回通知客户端。
5)写入MemStore后的操作:1.触发MemStore Flush操作:数据写入MemStore后,一直到MemStore满 → Flush成一个StoreFile,直至增长到一定阈值2.触发StoreFiles Compact操作:达到一定阈值后,将多个StoreFile小文件合并成一个大StoreFile大文件,逐步形成越来越大的StoreFile,同时进行版本合并和数据删除3.触发Region split操作:当单个StoreFile大文件超过一定阈值(Region split 阈值)后,触发Split操作,把当前Region Split成2个Region,Region会下线, 新Split出的2个子Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上;说明:Region拆分策略:
1.Region大小考量的因素1)Region大,数目太少就会妨碍可扩展性,降低并行能力,导致压力不够分散;2)region小,数目太多就会造成性能下降;2.HRegionServer拆分region的步骤:是先将该region下线,然后拆分,将其子region加入到hbase:meta表中,再将他们加入到原本的HRegionServer中,最后汇报Master。3.hbase在写入数据 为了防止regionserver热点问题,我们需要进行Region的拆分(分为split前、split中、split后)
可以通过设置RegionSplitPolicy的实现类来指定拆分策略,RegionSplitPolicy类的实现类有:ConstantSizeRegionSplitPolicyIncreasingToUpperBoundRegionSplitPolicyDelimitedKeyPrefixRegionSplitPolicyKeyPrefixRegionSplitPolicy其中:1.ConstantSizeRegionSplitPolicy仅当region大小超过常量值(hbase.hregion.max.filesize大小,默认为10G)时,才进行拆分。2. IncreasingToUpperBoundRegionSplitPolicy默认region split策略。即当同一table在同一regionserver上的region数量在[0,100)之间时按照如下的计算公式算,否则按照上一策略计算:Min (R^3* "hbase.hregion.memstore.flush.size"*2, "hbase.hregion.max.filesize")R为同一个table中在同一个regionserver中region的个数,hbase.hregion.memstore.flush.size默认为128M,hbase.hregion.max.filesize默认为10G。3. DelimitedKeyPrefixRegionSplitPolicy保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中。如果定义rowkey时,采用'_'作为字段分隔符(如:userid_eventid),则采用该策略拆分之后,能够确保具有相同userid的记录隶属于同一Region。4. KeyPrefixRegionSplitPolicy                    保证具有相同前缀的row在一个region中(要求设计中前缀具有同样长度)。指定rowkey前缀位数划分region,通过读取table的prefix_split_key_policy.prefix_length属性,该属性为数字类型,表示前缀长度,在进行split时,按此长度对splitPoint进行截取。

3.读数据流程
在这里插入图片描述

1)通过2.8.1找到要读的数据的HRegionServer。
2)根据读取的TableName和RowKey的startkey 、 endkey 找到对应的HRegion。
3)每个regionserver只有一个blockcache(读缓存),读取数据时,先到memestore上读数据,找不到再到blockcahce上找数据,再查不到则到磁盘(storefile)查找,并把读入的数据同时放入blockcache。

9.Hbase的数据结构

1.传统数据库存数据储结构:采用B+树的方式
B+树最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在物理上往往不连续,甚至分离的很远,但做范围查询时,会产生大量读随机IO;2.Hbase数据存储结构:为了克服B+树的弱点,引入了LSM树的概念,即Log-Structured Merge-Trees;
LSM树本质上就是在读写之间取得平衡,和B+树相比,它牺牲了部分读性能,用来大幅提高写性能。
LSM树原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。3.B+树与LSM-Tree树本质区别
他们本质不同点在于他们使用现代硬盘的方式,尤其是磁盘。从磁盘使用方面讲,RDBMS是寻道型,它需要随机读写数据。LSM-Tree则属于传输型,它会顺序读写数据。

10.Hbase的rowkey设计

Row Key特点:1.Row Key可以是任意字符串,最大长度64KB,实际应用中一般为10~100bytes;1 1000000001 1000000002  19 1a 1z 20 2z2.RowKey是按照字典序存储,因此,设计row key时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块;3.region的拆分策略和Row Key主键设计有很大关系,Hregionserver的热点问题就是MapReduce和hive的数据倾斜问题,所以hbase也要求数据平衡。Row Key支持三种检索方式
1)通过单个row key访问:即按照某个row key键值进行get操作;
2)通过row key的范围进行scan:即通过设置startRowKey和endRowKey,在这个范围内进行扫描
3)全表扫描:即直接扫描整张表中所有行记录,只适合小数据量情况。
Hbase中没有join的概念,大表的结构可以使得不需要join。RowKey设计原则:
1)要保证rowkey的唯一性。
2)wkey 长度建议是越短越好,不要超过16个字节。
3)Rowkey的散列原则
如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率。

在这里插入图片描述

三、Hbase Shell:DDL语句操作

Meta:hbase:meta(全限定名称;存储元数据信息表)
Hbase shell操作是hbase通过jruby把所有的命令转成java方法执行一般操作:
查询服务器状态:status
查询版本:versionHbase的命名空间-->MySQL数据库
Hbase的表-->MySQL的数据库别名
Hbase的列簇-->MySQL的表
Hbase的列限定符-->MySQL的字段
Hbase的但愿-->MySQL的字段值DDL语句操作:
1.命名空间操作
# 创建命名空间
create_namespace 'myns1'
# 显示命名空间
list_namespace
#查看命名空间下有什么表
list_namespace_tables 'myns1'
# 删除命名空间, 在删除一个命名空间时,该命名空间不能包含任何的表,否则会报错
drop_namespace '命名空间名'2.创建表
# 创建默认命名空间的表
create '表名称','列族名称1','列族名称2','列族名称N'
# 创建带有命名空间的表
create '命名空间:表名称','列族名称1','列族名称2','列族名称N'
# 创建带有命名空间的表示例
create 'myns1:table1','cf1','cf2','cf3'3.列出某个命名空间下的所有表
# 列出某个命名空间下的所有表
list 'myns1.*'4.获得表的描述
# 获得表的描述(查看表结构)
desc '命名空间:表名'5.删除一个列族
# 删除一个列族(myns1:table1 表的 cf2 列族)
alter 'myns1:table1',{NAME=>'cf2',METHOD=>'delete'}
# 删除多个列族 列族属性操作的时候 属性名 是区分大小写 也就是说 NAME --> 方法 METHOD --> 方法 delete 参数
alter 'myns1:table2', { NAME => 'cf3', METHOD => 'delete'},{ NAME => 'cf2', METHOD => 'delete'}6.将表下线/下线(注意 : 下线后,该表不能进行查询)
检测表是否下线:is_disabled "myns1:tb1"
将表下线:disable "myns1:tb1"
检测表是否上线:is_enabled "myns1:tb1"
将表上线: enable "myns1:tb1"7.删除一个表
# 删除一个表(在线表,会报错)
drop 'myns1:table1'
# 删除一个表(将表下线,再删除)
将表下线:disable "myns1:tb1"
再删除表:drop "myns1:tb2"8.判断表是否存在
# 判断表是否存在
exists "tb1"  //公司常用
exists "myns1:tb1"

四、Hbase Shell:DML语句操作

DML语句操作:
1. 添加数据# 语法:put <table>,<rowkey>,<family:column>,<value>,<timestamp># 如果不写timestamp,则系统默认
# 插入数据前要保证表是enable状态
# 重新创建表
create 'myns1:table2', 'cf1', 'cf2'
#基本信息的列族
put 'myns1:table2','hb_1', 'cf1:name','zhaowenming'
put 'myns1:table2','hb_1', 'cf1:age','25'
put 'myns1:table2','hb_1', 'cf1:sex','M'
#证件信息的列族
put 'myns1:table2','hb_1', 'cf2:cert_type','身份证'
put 'myns1:table2','hb_1', 'cf2:cert_no','130102199405286392'2. 获取数据
get: 获取表中一行数据,不能扫描全表
# 语法:get <table>,<rowkey>,[<family:column>,....]
#获取一行数据
get 'myns1:table2','hb_1'
#获取一行,一个列族的所有数据
get 'myns1:table2','hb_1','cf1'
#获取一行,一个列族中一个列的数据
get 'myns1:table2','hb_1','cf1:name'#获取一行的列族
get 'myns1:table2', 'hb_1', {COLUMN => 'cf1'}
#获取一行的某列族的列
get 'myns1:table2', 'hb_1', {COLUMN => 'cf1:name'}
#获取一行某列族的列并匹配时间戳
get 'myns1:table2', 'hb_1', {COLUMN => 'cf1:name', TIMESTAMP => 1562742642169} 
#获取一行中,FILTER筛选器,binary二进制数组的值为110125的列
get 'myns1:table2', 'hb_1', {FILTER => "ValueFilter(=, 'binary:130102199405286392')"}3. 更新数据
#语法:重新put,put时会覆盖原来的数据
-- 修改年龄
put 'myns1:table2','hb_1','cf1:age','25'
-- 查看年龄
get 'myns1:table2','hb_1','cf1:age'4. 通过timestamp来获取两个版本的数据
get 'myns1:table2','hb_1',{COLUMN=>'cf1:age',TIMESTAMP=>1562746800144}
get 'myns1:table2','hb_1',{COLUMN=>'cf1:age',TIMESTAMP=>1562746813618}5. scan扫描
# 语法:scan <table> ,{COLUMNS => [ <family:column>,.... ], LIMIT => num}
# 添加数据
put 'myns1:table2','hb_2', 'cf2:cert_type','身份证'
put 'myns1:table2','hb_2', 'cf2:cert_no','130102199805236580'
put 'myns1:table2','hb_3', 'cf2:cert_type','身份证'
put 'myns1:table2','hb_3', 'cf2:cert_no','130102199706237795'
put 'myns1:table2','hb_4', 'cf2:cert_type','身份证'
put 'myns1:table2','hb_4', 'cf2:cert_no','130102199705142396'
#扫描全表,大表操作不可取
scan 'myns1:table2'
#获取表中前两行
scan 'myns1:table2', {LIMIT => 2}
#扫描表中指定列族数据
scan 'myns1:table2', {COLUMNS => 'cf1'}
#扫描表中执行列族中列的数据
scan 'myns1:table2', {COLUMNS => 'cf2:cert_no'}
#扫描表中值=130102199705142396 的数据
scan 'myns1:table2', FILTER=>"ValueFilter(=,'binary:130102199705142396')"
#扫描表的范围 包含 STARTROW 的范围 但是不包含 STOPROW 的范围
scan 'myns1:table2' , {STARTROW => 'hb_2', STOPROW => 'hb_3'}6. 删除行中某列数据
# 语法:delete <table>, <rowkey>, <family:column>
# 修改数据
put 'myns1:table2', 'hb_4','cf2:cert_type', 'shenfenzheng'
get 'myns1:table2', 'hb_4','cf2:cert_type'
put 'myns1:table2', 'hb_4','cf2:cert_type', 'idcard'
get 'myns1:table2', 'hb_4','cf2:cert_type'
# 删除行中某列数据(指定列名,会删除执行列的所有版本数据)
delete 'myns1:table2', 'hb_4', 'cf2:cert_type'
get 'myns1:table2', 'hb_4','cf2:cert_type'(获取数据 所有版本都删除)
get 'myns1:table2','hb_4',{TIMESTAMP=>1733829623580}(验证一下 数据已删除)
get 'myns1:table2','hb_4',{TIMESTAMP=>1733829650481}(验证一下 数据已删除)
scan 'myns1:table2'(删除后发现操作的列已经被删除了)7. 删除整行
# 语法:deleteall <table>, <rowkey>
# 删除hb_5行数据
put 'myns1:table2','hb_5', 'cf2:cert_type','身份证'
put 'myns1:table2','hb_5', 'cf2:cert_no','130103199605261159'
put 'myns1:table2','hb_5', 'cf1:name','sunjianguo'
get 'myns1:table2','hb_5'
# 删除hb_5行数据
deleteall 'myns1:table2','hb_5'
get 'myns1:table2','hb_5'8. 清空表数据
#保留 region信息的语法:truncate <table>
#不保留 region信息的语法:truncate_preserve <table>
create 'myns1:table3','cf1'
put 'myns1:table3','id1','cf1:name','zhaowenming'
# 1.清空表(不保留region信息)
truncate 'myns1:table3'
# 2.清空表(保留region信息)
truncate_preserve 'myns1:table3'9. 查询表中有多少行
# 1.小表count()方法# 语法:count <table>, {INTERVAL => intervalNum, CACHE => cacheNum}# INTERVAL设置多少行显示一次及对应的rowkey,默认1000;# CACHE每次去取的缓存区大小,默认是10,调整该参数可提高查询速度这种方式效率很低,如果表行数很大的话不建议采用这种方式。#查询表中数据行数count 'myns1:table2'#按照2行显示一次,查询count 'myns1:table2', {INTERVAL => 2}
# 2. 大表count方法:调用的hbase jar中自带的统计行数的类。hbase org.apache.hadoop.hbase.mapreduce.RowCounter 'tablename'hbase org.apache.hadoop.hbase.mapreduce.RowCounter 'myns1:table2'10. 计数器操作
Hbase计数器可以用于统计用户数,点击量等信息。
# 语法: incr <tablename>,<rowkey>,<family:column>,long n
# 创建表
create 'myns1:table4','cf1'
# 给表的指定行指定列族的指定列设置计数器(给 ‘app_page1’ 这个行健增加 'c_f1:click_volume' 字段,并使用 counter 实现递增)
#默认递增1
incr 'myns1:table4','app_page1', 'cf1:click_volume'
#指定递增 5
incr 'myns1:table4','app_page1', 'cf1:click_volume',5
#指定递增 1000
incr 'myns1:table4','app_page1', 'cf1:click_volume',1000
#获取'app_page1' 数据
get 'myns1:table4','app_page1'
#获取当前count的值
get_counter 'myns1:table4', 'app_page1', 'cf1:click_volume'11. 获取多个版本的数据
# 修改列族的版本数量
alter 'myns1:table2',{ NAME =>'cf1', VERSIONS => 3 }
put 'myns1:table2','hb_1','cf1:age','30'
put 'myns1:table2','hb_1','cf1:age','40'
put 'myns1:table2','hb_1','cf1:age','50'
# 此时,可以查询出1个版本的数据
get 'myns1:table2', 'hb_1', { COLUMN =>'cf1:age',  VERSIONS => 1}
# 此时,可以查询出2个版本的数据
get 'myns1:table2', 'hb_1', { COLUMN =>'cf1:age',  VERSIONS => 2}
# 此时,可以查询出3个版本的数据
get 'myns1:table2', 'hb_1', { COLUMN =>'cf1:age',  VERSIONS => 3}
说明:
列族的版本 和 列的版本是不一样的
列族就是我们mysql的表 所以它就一个版本就可以了 不需要多个版本(默认一个版本)
列族中的列是根据 时间戳 在内存中分出来的3个版本
内存 向 硬盘溢出数据的时候 列有3个版本的数据 --> 只写时间最新的

五、eclipse操作hbase

eclipse操作hbase:用java连接虚拟机的hbase**
在这里插入图片描述

1.开发环境配置

1.配置pom.xml文件

pom.xml–>dependencies–>add–>引入junit-4.12的jar包

	<properties><!-- maven项目整体编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 项目编译的时候,源码(.java)使用哪个版本JDK --><maven.compiler.source>1.8</maven.compiler.source><!-- 项目编译的时候,可执行文件(.class)使用哪个版本JDK --><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>jdk.tools</groupId><artifactId>jdk.tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${JAVA_HOME}/lib/tools.jar</systemPath></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.3.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies>

2.新建hbase-site.xml文件,放到资源文件目录下

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration><!--	Master	--><property><name>hbase.master</name><value>nn1.hadoop:60000</value></property><!--	Client参数	--><property><name>hbase.client.scanner.caching</name><value>10000</value><description>客户端参数,HBase scanner一次从服务端抓取的数据条数</description></property><property><name>hbase.client.scanner.timeout.period</name><value>900000</value><description>scanner过期时间</description></property><!--	Zookeeper	--><property><name>hbase.zookeeper.quorum</name><value>nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181</value></property><property><name>zookeeper.session.timeout</name><value>1200000</value></property>
</configuration>

3.新建mapred-site.xml文件,放到资源文件目录下

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration><property><name>mapreduce.framework.name</name><value>yarn</value><description>运行模式</description></property>
</configuration>

4.新建log4j.properties文件,放到资源文件目录下

2.JAVA-HBASE:DDL操作

package com.shanhai.hbase;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;public class DDLTest {//定义配置对象private static Configuration conf = HBaseConfiguration.create();//定义表名private static TableName tableName = TableName.valueOf("myns1:table4");/*创建表的方法测试*/@Testpublic void createTable() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取数据库的管理对象HBaseAdmin admin = (HBaseAdmin) conn.getAdmin();//定义表的描述信息HTableDescriptor td = new HTableDescriptor(tableName);//描述表的列族信息HColumnDescriptor cd1 = new HColumnDescriptor(Bytes.toBytes("cf1"));HColumnDescriptor cd2 = new HColumnDescriptor(Bytes.toBytes("cf2"));HColumnDescriptor cd3 = new HColumnDescriptor(Bytes.toBytes("cf3"));td.addFamily(cd1);td.addFamily(cd2);td.addFamily(cd3);//判断一下,如果表存在就删除if (admin.tableExists(tableName)) {//下线表admin.disableTable(tableName);//删除表admin.deleteTable(tableName);}//创建这张表admin.createTable(td);//输出提示System.out.println("msg :Table Create Is OK!");//释放连接if (null != admin) {admin.close();}if (null != conn) {conn.close();}}/*删除列族的方法测试*/@Testpublic void deleteByColumnFamily() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取数据库的管理对象HBaseAdmin admin = (HBaseAdmin) conn.getAdmin();//指定列族并删除admin.deleteColumn(tableName, Bytes.toBytes("cf3"));//输出提示System.out.println("msg : The ColumnFamily Is Deleted!");//释放连接if (null != admin) {admin.close();}if (null != conn) {conn.close();}}/*删除表的方法测试*/@Testpublic void deleteTable() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取数据库的管理对象HBaseAdmin admin = (HBaseAdmin) conn.getAdmin();//判断一下,如果表存在就删除if (admin.tableExists(tableName)) {//下线表admin.disableTable(tableName);//删除表admin.deleteTable(tableName);}//输出提示System.out.println("msg : The Table Is Deleted!");//释放连接if (null != admin) {admin.close();}if (null != conn) {conn.close();}}
}

3.JAVA-HBASE:DML操作

package com.shanhai.hbase;import java.util.ArrayList;
import java.util.List;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;public class DMLTest {//定义配置对象private static Configuration conf = HBaseConfiguration.create();//定义表名private static TableName tableName = TableName.valueOf("myns1:table4");/*添加单条数据的方法测试*/@Testpublic void addOneData() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//设置数据Put put = new Put(Bytes.toBytes("hb_1"));put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("name"), Bytes.toBytes("赵文明"));put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("sex"), Bytes.toBytes("男"));put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), Bytes.toBytes("25"));put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("birthday"), Bytes.toBytes("1994-06-01"));put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("np"), Bytes.toBytes("河北省"));//添加这条数据mytable.put(put);//输出提示System.out.println("msg : One Data is Inserted!");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*添加多条数据的方法测试*/@Testpublic void addSomeDatas() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//设置多条数据数据Put put1 = new Put(Bytes.toBytes("hb_2"));put1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("name"), Bytes.toBytes("孙建国"));put1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("sex"), Bytes.toBytes("男"));put1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), Bytes.toBytes("36"));put1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("birthday"), Bytes.toBytes("1983-06-01"));put1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("np"), Bytes.toBytes("北京市"));Put put2 = new Put(Bytes.toBytes("hb_3"));put2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("name"), Bytes.toBytes("王小花"));put2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("sex"), Bytes.toBytes("女"));put2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), Bytes.toBytes("19"));put2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("birthday"), Bytes.toBytes("2000-06-01"));put2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("np"), Bytes.toBytes("湖南省"));Put put3 = new Put(Bytes.toBytes("hb_4"));put3.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("name"), Bytes.toBytes("赵佳佳"));put3.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("sex"), Bytes.toBytes("女"));put3.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), Bytes.toBytes("18"));put3.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("birthday"), Bytes.toBytes("2001-06-01"));put3.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("np"), Bytes.toBytes("河北省"));List<Put> puts = new ArrayList<Put>();puts.add(put1);puts.add(put2);puts.add(put3);//添加多条数据mytable.put(puts);//输出提示System.out.println("msg : Some Datas is Inserted!");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*删除行的方法测试*/@Testpublic void deleteOneData() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建删除对象,同时指定行Delete delete = new Delete(Bytes.toBytes("hb_4"));//删除数据mytable.delete(delete);//输出提示System.out.println("msg:One Row Is Deleted!");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*删除列的方法测试*/@Testpublic void deleteByColumn() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建删除对象,同时指定行Delete delete = new Delete(Bytes.toBytes("hb_1"));//删除指定列的所有数据delete.addColumns(Bytes.toBytes("cf1"), Bytes.toBytes("age"));//删除指定列的指定时间及指定时间前的数据//delete.addColumns(Bytes.toBytes("cf1"), Bytes.toBytes("age"), 1734004118538L);//删除指定列最新时间的数据//delete.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"));//删除指定列指定时间的数据//delete.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), 1734003627689L);//删除指定列族的所有数据//delete.addFamily(Bytes.toBytes("cf1"));//删除指定列族的指定时间及指定时间前的数据//delete.addFamily(Bytes.toBytes("cf1"), 1734066009457L);//删除数据mytable.delete(delete);//输出提示System.out.println("msg : The Column Is Deleted");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}
}

4.JAVA-HBASE:DQL操作

package com.shanhai.hbase;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;public class DQLTest {//定义配置对象private static Configuration conf = HBaseConfiguration.create();//定义表名private static TableName tableName = TableName.valueOf("myns1:table4");/*获取单行数据的方法测试*/@Testpublic void getOneRowData() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建数据的获取对象Get get = new Get(Bytes.toBytes("hb_1"));//指定列族查询get.addFamily(Bytes.toBytes("cf1"));//指定列族+列名查询get.addColumn(Bytes.toBytes("cf1"),Bytes.toBytes("age"));//指定时间戳查询//get.setTimeStamp(1733994220289L);//指定获取的版本个数get.setMaxVersions(3);//获取数据Result result = mytable.get(get);//获取这行数据Cell[] cells = result.rawCells();System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow())+"\t\tcolumn="+new String(CellUtil.cloneFamily(cell))+":"+new String(CellUtil.cloneQualifier(cell))+", timestamp="+cell.getTimestamp()+", value="+new String(CellUtil.cloneValue(cell)));}//输出提示System.out.println("msg : One Data Is Geted!");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*获取批量数据的方法测试*/@Testpublic void getSomeRowDatas() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();//设置开始行和结束行
//		scan.setStartRow(Bytes.toBytes("hb_1"));
//		scan.setStopRow(Bytes.toBytes("hb_4"));//扫描数据,获得多行数据ResultScanner rs = mytable.getScanner(scan);Cell[] cells = null;//遍历数据for (Result result : rs) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow())+"\t\tcolumn="+new String(CellUtil.cloneFamily(cell))+":"+new String(CellUtil.cloneQualifier(cell))+", timestamp="+cell.getTimestamp()+", value="+new String(CellUtil.cloneValue(cell)));}}System.out.println("msg : Table Data Is Scaned!");//释放连接if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}
}

5.JAVA-HBASE:filter用法

1.SingleColumnValueFilter:单列值筛选器(影响查询性能,在处理大量数据的时候速度可能会慢)
2.RegexStringComparator:正则表达式字符串比较器
3.SubstringComparator: 字符包含比较器
4.FilterList:多条件筛选器
5.PageFilter:分页查询

package com.shanhai.hbase;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.FilterList.Operator;
import org.apache.hadoop.hbase.filter.PageFilter;
import org.apache.hadoop.hbase.filter.RegexStringComparator;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.filter.SubstringComparator;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;public class FilterTest {//定义配置对象private static Configuration conf = HBaseConfiguration.create();//定义表名private static TableName tableName = TableName.valueOf("myns1:table4");/*单列值筛选器的方法测试*///shell的写法:scan 'myns1:table4',{ FILTER =>"SingleColumnValueFilter('cf1','name',>=,'binary:赵文明',true,true)"}@Testpublic void queryTableBySingleFilter() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();//创建过滤器对象,通过条件筛选,返回整行数据SingleColumnValueFilter scvf = new SingleColumnValueFilter(Bytes.toBytes("cf1"), Bytes.toBytes("name"),CompareOp.EQUAL, Bytes.toBytes("赵文明"));//当某行的该列不存在时,设置条件是否过滤。true过滤;false不过滤(默认)scvf.setFilterIfMissing(true);//是否只对最新版本有效。取值范围如下:true(默认):只检测最新版本的值是否满足条件。false:检测所有版本的值是否满足条件。scvf.setLatestVersionOnly(true);//绑定筛选条件scan.setFilter(scvf);//扫描数据ResultScanner rs = mytable.getScanner(scan);Cell[] cells = null;//遍历数据for (Result result : rs) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow()) + "\t\tcolumn=" + new String(CellUtil.cloneFamily(cell))+ ":" + new String(CellUtil.cloneQualifier(cell)) + ", timestamp=" + cell.getTimestamp()+ ", value=" + new String(CellUtil.cloneValue(cell)));}}//释放连接if (null != rs) {rs.close();}if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*正则表达式字符串比较器的方法测试*///shell的写法:scan 'myns1:table4',{ FILTER =>"SingleColumnValueFilter('cf1','name',=,'regexstring:^赵',true,true)"}@Testpublic void queryTableByRegexFilter() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();//设置表达式RegexStringComparator rsc = new RegexStringComparator("^赵");//创建过滤器对象,通过条件筛选,返回整行数据SingleColumnValueFilter scvf = new SingleColumnValueFilter(Bytes.toBytes("cf1"), Bytes.toBytes("name"),CompareOp.EQUAL, rsc);//当某行的该列不存在时,设置条件是否过滤。true过滤;false不过滤(默认)scvf.setFilterIfMissing(true);//是否只对最新版本有效。取值范围如下:true(默认):只检测最新版本的值是否满足条件。false:检测所有版本的值是否满足条件。scvf.setLatestVersionOnly(true);//绑定筛选条件scan.setFilter(scvf);//扫描数据ResultScanner rs = mytable.getScanner(scan);Cell[] cells = null;//遍历数据for (Result result : rs) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow()) + "\t\tcolumn=" + new String(CellUtil.cloneFamily(cell))+ ":" + new String(CellUtil.cloneQualifier(cell)) + ", timestamp=" + cell.getTimestamp()+ ", value=" + new String(CellUtil.cloneValue(cell)));}}//释放连接if (null != rs) {rs.close();}if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*字符包含比较器的方法测试*///shell的写法:scan 'myns1:table4',{ FILTER =>"SingleColumnValueFilter('cf1','name',=,'substring:文',true,true)"}@Testpublic void queryTableBySubstringFilter() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();//设置表达式SubstringComparator sc = new SubstringComparator("文");//创建过滤器对象,通过条件筛选,返回整行数据SingleColumnValueFilter scvf = new SingleColumnValueFilter(Bytes.toBytes("cf1"), Bytes.toBytes("name"),CompareOp.EQUAL, sc);//当某行的该列不存在时,设置条件是否过滤。true过滤;false不过滤(默认)scvf.setFilterIfMissing(true);//是否只对最新版本有效。取值范围如下:true(默认):只检测最新版本的值是否满足条件。false:检测所有版本的值是否满足条件。scvf.setLatestVersionOnly(true);//绑定筛选条件scan.setFilter(scvf);//扫描数据ResultScanner rs = mytable.getScanner(scan);Cell[] cells = null;//遍历数据for (Result result : rs) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow()) + "\t\tcolumn=" + new String(CellUtil.cloneFamily(cell))+ ":" + new String(CellUtil.cloneQualifier(cell)) + ", timestamp=" + cell.getTimestamp()+ ", value=" + new String(CellUtil.cloneValue(cell)));}}//释放连接if (null != rs) {rs.close();}if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*多条件筛选器的方法测试*///shell的写法:scan 'myns1:table4', { FILTER => "(SingleColumnValueFilter('cf1','age',<,'binary:20',true,true)) AND (SingleColumnValueFilter('cf1','job',=,'binary:学生',true,true))"}@Testpublic void queryTableByListFilter() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();//查询20岁以下的学生SingleColumnValueFilter scvf1 = new SingleColumnValueFilter(Bytes.toBytes("cf1"), Bytes.toBytes("age"),CompareOp.LESS, Bytes.toBytes("20"));SingleColumnValueFilter scvf2 = new SingleColumnValueFilter(Bytes.toBytes("cf1"), Bytes.toBytes("job"),CompareOp.EQUAL, Bytes.toBytes("学生"));//设置过滤器关系FilterList list = new FilterList(Operator.MUST_PASS_ALL);//绑定过滤条件list.addFilter(scvf1);list.addFilter(scvf2);//绑定筛选条件scan.setFilter(list);//扫描数据ResultScanner rs = mytable.getScanner(scan);Cell[] cells = null;//遍历数据for (Result result : rs) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow()) + "\t\tcolumn=" + new String(CellUtil.cloneFamily(cell))+ ":" + new String(CellUtil.cloneQualifier(cell)) + ", timestamp=" + cell.getTimestamp()+ ", value=" + new String(CellUtil.cloneValue(cell)));}}//释放连接if (null != rs) {rs.close();}if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}/*分页查询的方法测试*///shell的写法:scan 'myns1:table4',{STARTROW => 'row1',FILTER=>"PageFilter(2)"}@Testpublic void queryTableByPageFilter() throws Exception {//获取数据库的连接Connection conn = ConnectionFactory.createConnection(conf);//获取要操作的表HTable mytable = (HTable) conn.getTable(tableName);//创建扫描器对象Scan scan = new Scan();// 设置分页参数int totalRowCount = 0;	// 总行数int pageSize = 2;	// 一次展示多少行// 创建pageFilterPageFilter pf = new PageFilter(pageSize);// 封装查询条件scan.setFilter(pf);byte[] tmprow = null;byte[] pb = Bytes.toBytes("z");ResultScanner scanner = null;Cell[] cells = null;//判断是否有数据量int scanRowCount = 0;while (true) {// 设置每次的起始startrowif(null != tmprow){// 计算rowkeytmprow = Bytes.add(tmprow, pb);System.out.println("startrow : " + Bytes.toString(tmprow));// 设置每行的起始rowkeyscan.setStartRow(tmprow);}// 定义每次查询的行数(用作是否退出的判断条件)scanRowCount = 0;// 获取数据scanner = mytable.getScanner(scan);//遍历数据for (Result result : scanner) {cells = result.rawCells();//获取这行数据System.out.println("ROW\t\tCOLUMN+CELL");//遍历数据for (Cell cell : cells) {//遍历这行所有列族的数据System.out.println(new String(result.getRow())+"\t\tcolumn="+new String(CellUtil.cloneFamily(cell))+":"+new String(CellUtil.cloneQualifier(cell))+", timestamp="+cell.getTimestamp()+", value="+new String(CellUtil.cloneValue(cell)));}// 计数器叠加scanRowCount++;totalRowCount++;// 获取当先循环的最后一行tmprow = result.getRow();}// 执行判断条件if(scanRowCount == 0){// 退出while循环break;}}// 展示消息System.out.println("msg : The Data is Queryed! TotalRowCount : " + totalRowCount);//释放连接if (null != scanner) {scanner.close();}if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}}
}

六、ORC文件转HFILE文件

1.数据准备

-- 通过查询limit表创建orc表
create table user_orc STORED AS orc as select aid, pkgname, uptime, type, country, gpcategory from user_install_status_limit;-- 查询表的orc结构
hive --orcfiledump /hive/warehouse/db1.db/user_orc/000000_0-- 创建hbase表
create 'myns1:user_install_status',{NAME=>'cf1',VERSION=>1,COMPRESSION=>'snappy'}

2.项目的整体架构

完成–>hive的ORC文件转hbase的HFILE文件
在这里插入图片描述
在这里插入图片描述

1.配置文件

1.配置pom.xml文件
  	<properties><!-- maven项目整体编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 项目编译的时候,源码(.java)使用哪个版本JDK --><maven.compiler.source>1.8</maven.compiler.source><!-- 项目编译的时候,可执行文件(.class)使用哪个版本JDK --><maven.compiler.target>1.8</maven.compiler.target><!-- 设置运行主类 --><mainClass>com.hnxy.bin.MRDriver</mainClass></properties><dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.7.3</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-shell</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hive</groupId><artifactId>hive-cli</artifactId><version>2.1.1</version><exclusions><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-common</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId></exclusion>				</exclusions><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/resources</directory></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><descriptors><descriptor>src/main/resources/assembly.xml</descriptor></descriptors><archive><manifest><mainClass>${mainClass}</mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.12</version><configuration><skip>true</skip><forkMode>once</forkMode><excludes><exclude>**/**</exclude></excludes></configuration></plugin></plugins></build>
2.新建assembly.xml文件,放到资源文件目录下
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">  <!-- TODO: a jarjar format would be better -->  <!-- 添加到生成文件名称的后缀符 --><id>hsanhai</id>  <!-- 打包类型 --><formats>  <format>jar</format></formats><!--  指定是否包含打包层目录 --><includeBaseDirectory>false</includeBaseDirectory><!-- 指定要包含的文件集 --><fileSets><fileSet><!-- 指定目录 --><directory>${project.build.directory}/classes</directory><!-- 指定文件集合的输出目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory><!-- 排除文件 --><excludes><exclude>*.xml</exclude><exclude>*.properties</exclude></excludes></fileSet></fileSets><!-- 用来定制工程依赖 jar 包的打包方式 --><dependencySets><dependencySet><!-- 指定包依赖目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory>  <!-- 当前项目构件是否包含在这个依赖集合里 --><useProjectArtifact>false</useProjectArtifact><!-- 是否将第三方jar包解压到该依赖中 false 直接引入jar包 true解压引入 --><unpack>true</unpack><!-- 将scope为runtime的依赖包打包到lib目录下。 --><scope>runtime</scope>  </dependencySet>    </dependencySets> 
</assembly>
3.拷贝hbase-site.xml、文件,放到资源文件目录下
4.拷贝mapred-site.xml文件,放到资源文件目录下
5.拷贝log4j.properties文件,放到资源文件目录下

2.com.shanhai.util

1.BaseMR
package com.shanhai.util;import java.util.Map.Entry;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;/** 所有MapReduce任务的父类。都应该继承它,然后在进行开发* 抽取公用的东西,完成代码复用。*/
public abstract class BaseMR {//定义所有任务公共的配置文件加载对象(公共配置)public static Configuration conf;//获得配置文件的加载对象public static void setConf(Configuration conf) {BaseMR.conf = conf;}//配置任务工作链public ControlledJob getCtrlJob() throws Exception{//创建任务工作链对象ControlledJob ctrlJob = new ControlledJob(conf);//设置输出目录Path out = this.getPath(getJobNameWithTaskID());FileSystem fs = FileSystem.get(conf);if (fs.exists(out)) {//hadoop fs -rm -r out true-->递归删除fs.delete(out, true);System.out.println(this.getJobName() + "的输出目录已经被删除了!");}//设置每个任务私有的confConfiguration jobConf = new Configuration();//拷贝公共配置给当前任务使用for (Entry<String, String> entry : conf) {jobConf.set(entry.getKey(), entry.getValue());}//创建Job任务Job job = getJob(jobConf);//设置工作链的任务ctrlJob.setJob(job);//返回return ctrlJob;}//每个独立jobpublic abstract Job getJob(Configuration jobConf)throws Exception;//获取输出主目录public String getWorkPath(){return MyConstant.TASK_WORK_BASE_PATH;}//获取输出地址public Path getPath(String jobName) {return new Path(getWorkPath() + jobName);}//获取任务名称public abstract String getJobName();//获取任务名称和任务ID-->wordcount_luopublic String getJobNameWithTaskID() {return getJobName()+"_"+conf.get(MyConstant.TASK_ID);}}
2.JobRunnerResult
package com.shanhai.util;
/** 主要对任务工作链的执行结果进行封装* 1.任务工作链的执行状态* 2.任务工作链的执行时间* 3.任务工作链的所有Counter数据*/import java.util.HashMap;
import java.util.Map;import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.Counters;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;public class JobRunnerResult {private boolean isSuccess;private String runTime;private Map<String, Counters> counterMap = new HashMap<String, Counters>();public Boolean getIsSuccess() {return isSuccess;}public void setIsSuccess(Boolean isSuccess) {this.isSuccess = isSuccess;}public String getRunTime() {return runTime;}public void setRunTime(String runTime) {this.runTime = runTime;}public Map<String, Counters> getCmap() {return counterMap;}public void setCmap(Map<String, Counters> counterMap) {this.counterMap = counterMap;}/*** 根据任务链名称 获取counters*/public Counters getCounters(String jobName){return counterMap.get(jobName);}/*** 根据工作链控制的任务名称 获取counters*/public Counters getCounters(ControlledJob colJob){return counterMap.get(colJob.getJobName());}/*** 获取指定的计数器* @param job 工作链名称* @param gname 组名称* @param cname 计数器名称* @return TODO(这里描述每个参数,如果有返回值描述返回值,如果有异常描述异常)*/public Counter getCounter(ControlledJob job,String gname,String cname){Counter counter = getCounters(job).findCounter(gname, cname);return counter;}/*** 获取指定counter的值* @param job 任务名称* @param gname 组名称* @param cname 计数器名称*/public long getCounterVal(ControlledJob job,String gname,String cname){// 获取这个技术器Counter counter = getCounter(job, gname, cname);return Utils.isEmpty(counter)?0L:counter.getValue();}}
3.JobRunnerUtil
package com.shanhai.util;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;/** 执行任务的工具类:执行任务和封装执行结果*/
public class JobRunnerUtil {//创建一个定长线程池来进行线程的管理public static ExecutorService es = Executors.newFixedThreadPool(1);//创建自己的线程类private static class MyCallable implements Callable<JobRunnerResult>{// 定义工作链对象private JobControl jobc;// 构造函数赋值public MyCallable(JobControl jobc) {super();this.jobc = jobc;}@Overridepublic JobRunnerResult call() throws Exception {//创建方法的返回值JobRunnerResult result = new JobRunnerResult();//监控任务工作链的执行//定义开始时间Long startTime = System.currentTimeMillis();//监控执行情况while (!jobc.allFinished()) {//任务没有全部完成Thread.sleep(1000);}//定义结束时间Long endTime = System.currentTimeMillis();//判断任务是否成功result.setIsSuccess(jobc.getFailedJobList().size() == 0);//任务执行成功获取counters数据for (ControlledJob job : jobc.getSuccessfulJobList()) {//按照任务名称保存所有Counters数据result.getCmap().put(job.getJob().getJobName(), job.getJob().getCounters());}//获取运行时间Long tmp = endTime - startTime;String runTime = getLifeTime(tmp);result.setRunTime(runTime);jobc.stop();//返回return result;}private String getLifeTime(Long mss){// 计算用了多少天Long days = mss / (1000*60*60*24);// 计算用了多少个小时 取余数算出不足一天的毫秒数 然后除以小时的毫秒 转换成小时单位Long hours = (mss%(1000*60*60*24))/(1000*60*60);// 计算用了多少分钟Long minutes = (mss%(1000*60*60))/(1000*60);// 计算用了所少秒钟Long seconds = (mss%(1000*60))/1000;// 开始拼接时间StringBuilder sb = new StringBuilder();// 判断if(days != 0){sb.append(days).append("天");}if(hours != 0){sb.append(hours).append("小时");}if(minutes != 0){sb.append(minutes).append("分钟");}if(seconds != 0){sb.append(seconds).append("秒");}return sb.toString();}}public static JobRunnerResult run(JobControl jobc) throws Exception{Thread thread = new Thread(jobc);thread.start();Future<JobRunnerResult> f = es.submit(new MyCallable(jobc));return f.get();}}
4.MyConstant
package com.shanhai.util;
/** 封装我们自己的常量类*/
public class MyConstant {//hbase:rowkey的分隔符public static final String SQE1 = "_";//任务ID//-Dmymr.task.id=luo	wordcount-->outpath wordcount_luopublic static final String TASK_ID = "mymr.task.id";//任务的输入地址//-Dmymr.task.input=D:\hdfs\input\hn16\mr1	固定我们任务的输入目录public static final String TASK_INPUT = "mymr.task.input";//任务的工作目录(windows下制定的绝对路径 如果扔到集群上需要修改成HDFS路径)//-Dmymr.task.output=D:/user/shanhai/task/wordcount_luo/part-r-000000 固定我们任务的输出目录//本地:D:/hdfs/user/shanhai/task///线上:/user/shanhai/task/public static final String TASK_WORK_BASE_PATH = "/user/shanhai/task/";}
5.ORCFormat
package com.shanhai.util;/** 保存ORC结构的工具类*/
public class ORCFormat {//定义ORC的结构public static final String MY_ORC_TYPE1 = "struct<aid:string,pkgname:string,uptime:bigint,type:int,country:string,gpcategory:string>";}
6.ORCUtil
package com.shanhai.util;import org.apache.hadoop.hive.ql.io.orc.OrcStruct;
import org.apache.hadoop.hive.serde2.objectinspector.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;/** 解析ORC的一行数据工具类*/
public class ORCUtil {//一行ORC数据对象private OrcStruct os = null;//一行ORC数据结构对象private StructObjectInspector soi = null;//赋予ORC数据结构public void setOrcType(String orcType){//获取ORC的结构数据TypeInfo info = TypeInfoUtils.getTypeInfoFromTypeString(orcType);//进行类型的转换soi = (StructObjectInspector) OrcStruct.createObjectInspector(info);}//获取一行ORC数据public void setOs(OrcStruct os) {this.os = os;}//获取一行ORC的列的数据public String getDataByKey(String key){//创建方法的返回值String val = null;//根据结构获取节点StructField fild = soi.getStructFieldRef(key);//获取数据val = String.valueOf(soi.getStructFieldData(os, fild));//返回return Utils.isEmpty(val)||val.toLowerCase().equals("null")?null:val;}}
7.Utils
package com.shanhai.util;import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;/** 判断对象是否为空的工具类*/
public class Utils {/** 判断各类型的对象是否为:空*/public static Boolean isEmpty(Object obj){Boolean boo = false;if (obj == null) {boo = true;}else if (obj instanceof String) {boo = "".equals(obj.toString().trim());}else if (obj instanceof Map<?, ?>) {boo = ((Map<?, ?>)obj).isEmpty();}else if (obj instanceof Collection<?>) {boo = ((Collection<?>)obj).isEmpty();}else if (obj.getClass().isArray()) {boo = Array.getLength(obj)==0;}return boo;}/** 判断各类型的对象是否为:非空*/public static Boolean isNotEmpty(Object obj){return !isEmpty(obj);}}

3.com.shanhai.mr

1.HbaseImportData
package com.shanhai.mr;import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hive.ql.io.orc.OrcNewInputFormat;
import org.apache.hadoop.hive.ql.io.orc.OrcStruct;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import com.shanhai.util.BaseMR;
import com.shanhai.util.MyConstant;
import com.shanhai.util.ORCFormat;
import com.shanhai.util.ORCUtil;
import com.shanhai.util.Utils;public class HbaseImportData extends BaseMR {private static class MyMapper extends Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>{//定义map需要用到的变量private ORCUtil ou = new ORCUtil();//定义列族private byte[] family = Bytes.toBytes("cf1");//定义列private byte[] pkgnameQ = Bytes.toBytes("pkgname");private byte[] typeQ = Bytes.toBytes("type");private byte[] countryQ = Bytes.toBytes("country");private byte[] gpcategoryQ = Bytes.toBytes("gpcategory");//定义时间格式化类private  DateFormat df = new SimpleDateFormat("yyyyMMdd");//定义输出的keyImmutableBytesWritable outkey = new ImmutableBytesWritable();@Overrideprotected void setup(Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>.Context context)throws IOException, InterruptedException {ou.setOrcType(ORCFormat.MY_ORC_TYPE1);}@Overrideprotected void map(NullWritable key, OrcStruct value,Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>.Context context)throws IOException, InterruptedException {//解析ORC对象ou.setOs(value);//获取列的数据String aid,pkgname,uptime,type,country,gpcategory;aid = ou.getDataByKey("aid");pkgname = ou.getDataByKey("pkgname");uptime = ou.getDataByKey("uptime");type = ou.getDataByKey("type");country = ou.getDataByKey("country");gpcategory = ou.getDataByKey("gpcategory");//设置rowkeyString rowkey = aid+MyConstant.SQE1+df.format(new Date(Long.parseLong(uptime.trim())*1000));//进行put对象的封装Put put = new Put(Bytes.toBytes(rowkey));if(Utils.isNotEmpty(pkgname)){put.addColumn(family, pkgnameQ, Bytes.toBytes(pkgname));}if(Utils.isNotEmpty(type)){put.addColumn(family, typeQ, Bytes.toBytes(type));}if(Utils.isNotEmpty(country)){put.addColumn(family, countryQ, Bytes.toBytes(country));}if(Utils.isNotEmpty(gpcategory)){put.addColumn(family, gpcategoryQ, Bytes.toBytes(gpcategory));}//设置输出outkey.set(Bytes.toBytes(rowkey));context.write(outkey, put);}}@Overridepublic Job getJob(Configuration jobConf) throws Exception {//创建方法的返回值Job job = Job.getInstance(conf, getJobName());//设置打包类job.setJarByClass(HbaseImportData.class);job.setMapperClass(MyMapper.class);//设置map的格式化类job.setInputFormatClass(OrcNewInputFormat.class);//设置map的输入与输出类型job.setMapOutputKeyClass(ImmutableBytesWritable.class);job.setMapOutputValueClass(Put.class);//获取数据连接Connection conn = ConnectionFactory.createConnection(jobConf);//获取要操作的表HTable mytable = (HTable)conn.getTable(TableName.valueOf("myns1:user_install_status"));//根据Hbase写好的putSortReducer结合HFileOutputFormat2.configureIncrementalLoad(job, mytable, mytable.getRegionLocator());//设置输入与输出目录FileInputFormat.addInputPath(job, new Path(jobConf.get(MyConstant.TASK_INPUT)));FileOutputFormat.setOutputPath(job, this.getPath(this.getJobNameWithTaskID()));//释放资源if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}//返回return job;}@Overridepublic String getJobName() {return "hbase_import_data";}}

4.com.shanhai.bin

1.MyJobRunner
package com.shanhai.bin;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import com.shanhai.mr.HbaseImportData;
import com.shanhai.util.JobRunnerResult;
import com.shanhai.util.JobRunnerUtil;public class MyJobRunner extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//创建任务工作链JobControl jobc = new JobControl("job1");//获取Hadoop的配置文件对象Configuration conf = this.getConf();//设置公共的配置文件加载对象conf,只需加载一次就可以HbaseImportData.setConf(conf);HbaseImportData hid = new HbaseImportData();//获取工作链的任务ControlledJob job1 = hid.getCtrlJob();//设置工作链的任务jobc.addJob(job1);//运行任务JobRunnerResult result = JobRunnerUtil.run(jobc);if (result.getIsSuccess()) {//这里可以打印Counters的信息System.out.println("JOB_STATUS : OK!");System.out.println("THE PROGRAM IS RUN " + result.getRunTime());} else {System.out.println("JOB_STATUS : FALL!");}return 0;}public static void main(String[] args) {try {System.exit(ToolRunner.run(new MyJobRunner(), args));} catch (Exception e) {e.printStackTrace();}}}
2.MyJobDriver
package com.shanhai.bin;import org.apache.hadoop.util.ProgramDriver;public class MyJobDriver {public static void main(String[] args) {//创建驱动程序对象ProgramDriver driver = new ProgramDriver();try {//加载要执行的类driver.addClass("workjob1", MyJobRunner.class, "hive的ORC文件转hbase的HFILE文件");//反射执行ProgramDriver.class.getMethod("driver", new Class[]{String[].class}).invoke(driver, new Object[]{args});} catch (Throwable e) {e.printStackTrace();}}
}

3.集群配置

修改集群环境让其能找到hive和hbase的jar包:1.操作机:修改 hadoop-env.sh 添加如下配置 :  
[hadoop@nn1 ~]$ vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh
添加配置:export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HADOOP_HOME/lib/*:$HBASE_HOME/lib/*2) 所有机器:把hive的jar拷贝到lib目录下 /usr/local/hadoop/lib
[hadoop@nn1 ~]$ ll /usr/local/hive/lib/ | grep hive-exec-2.1.1.jar
[hadoop@nn1 ~]$ cp /usr/local/hive/lib/hive-exec-2.1.1.jar /tmp/
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/scp_all.sh /tmp/hive-exec-2.1.1.jar /tmp/
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh cp /tmp/hive-exec-2.1.1.jar /usr/local/hadoop/lib
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh ls -l /usr/local/hadoop/lib | grep hive-exec3) 操作机:maprd-site.xml
mr 任务能找到hbase的jar包是因为 maprd-site.xml 里把hbase的lib加到了 mapreduce.application.classpath 中
[hadoop@nn1 ~]$ vim /usr/local/hadoop/etc/hadoop/mapred-site.xml
<property><name>mapreduce.application.classpath</name>末尾添加/usr/local/hbase/lib/*(我们之前已经添加了)<value>,/usr/local/hbase/lib/*</value>
</property>4) 操作机:hbase的lib目录下的slf4j移出来
[hadoop@nn1 ~]$ ll /usr/local/hbase/lib/ | grep log4j
[hadoop@nn1 ~]$ mv /usr/local/hbase/lib/slf4j-log4j12-1.7.5.jar /tmp/5) 操作机:在/usr/local/hadoop/etc/hadoop目录下增加hbase配置的软链接
[hadoop@nn1 ~]$ ln -s /usr/local/hbase/conf/hbase-site.xml /usr/local/hadoop/etc/hadoop/hbase-site.xml
[hadoop@nn1 ~]$ cd /usr/local/hadoop/etc/hadoop
[hadoop@nn1 hadoop]$ ll

4.集群运行

1.打jar包
打包命令:clean assembly:assembly2.集群运行:hive的ORC文件转hbase的HFILE文件
[hadoop@nn1 ~]$ mkdir myhbase
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ rz
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ hadoop jar hn16_hbase_tp2-0.0.1-SNAPSHOT-luoxichuan.jar workjob1 -Dmymr.task.id=luo -Dmymr.task.input=hdfs://ns1/hive/warehouse/db1.db/user_orc -Dhbase.zookeeper.quorum=nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181常报错误:1.job的输入与输出2.pom.xml文件的打包类3.-D参数前缀4.属性大小写5.判断属性是否非空6.返回值空3.集群运行:hive数据导入
执行上面的命令时,hdfs目录不能带上列族,如果带上,执行导入的时候,会报错。
hadoop jar /usr/local/hbase/lib/hbase-shell-1.3.1.jar completebulkload hdfs://ns1//user/luoxichuan/task/hbase_import_data_luo myns1:user_install_status4.检查数据:查看hbase表的导入结果
1)方法一:使用rowcounter执行mr统计工具查看hbase中有多少数据
hadoop jar /usr/local/hbase/lib/hbase-shell-1.3.1.jar rowcounter myns1:user_install_status
2)方法二:使用hbase的scan扫描
hbase shell
scan myns1:hainiu_user_install_status

七、Hbase表的预分Region

1.小批量预分Region

1.在hive中分析这300条数据:
# 查看数据发现每个aid 的前5位
select aid fron user_install_status;
# 执行hql,统计前5位
select t.sub, count(1) from 
(select substring(aid, 1, 5) as sub from user_install_status) t group by t.sub;2.分析完后,生成region的key划分配置文件
# 将分配内容写入 
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ vim split_data
文件内容(为SQL语句分析的结果)
8d000
8d001
8d002
8d003
8d004
8d005
8d006
8d007
8d008
8d009
8d00a
8d00b
8d00c
8d00d3.创建带有预留region的表;
#创建带有预留region的表,split_data 是region的key划分配置文件
create '表名','列簇信息',{SPLITS_FILE => '保存了rowkey的信息文件'}
create 'myns1:tb5','cf1',{SPLITS_FILE => '/home/hadoop/myhbase/split_data'}
# 查看region分配情况
http://nn1.hadoop:60010/table.jsp?name=myns1:tb64.执行mapreduce,将orc文件转成hfile,并导入到hbase表;
# 需要在代码上修改表名称,然后打包上传集群运行。
hadoop jar hn16_hbase_tp2-0.0.1-SNAPSHOT-luoxichuan.jar workjob1 -Dmyhbase.tablename=myns1:tb5 -Dmymr.task.id=luo -Dmymr.task.input=hdfs://ns1/hive/warehouse/db1.db/user_orc -Dhbase.zookeeper.quorum=nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181
# 将生成在MapReduce上的HFile文件导入到Habse的表里去。(相当于mv移动)
执行完成的hdfs目录,cf 列族目录下没有数据,导入时已经被load走了:
hadoop jar /usr/local/hbase/lib/hbase-shell-1.3.1.jar completebulkload /user/luoxichuan/task/hbase_import_data_luo myns1:tb5
# 在页面看region的分配情况
http://nn1.hadoop:60010/table.jsp?name=myns1:tb6

2.大批量预分Region

预分region实际上就是制定每个region的rowkey的区间,让rowkey更加均匀的分布到每个region上,所以最主要的就是对rowkey的数据分布进行分析。
在这里插入图片描述

一、获取预分Region的key划分配置文件。
1.在hive中分析数据
# 首先分析第一位字母的数据量占比
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,1) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_1_1 2> /dev/null &
# 分析前两位字母组合的数据量占比
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,2) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_1_2 2> /dev/null &
# 分析前三位字母组合的数据量占比
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,3) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_1_3 2> /dev/null &
# 分析前四位字母组合的数据量占比
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,4) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_1_4 2> /dev/null &
vim split_1_1
vim split_1_2
vim split_1_3
vim split_1_4
从结果中看第四种组合能使rowkey的分布更加均衡,所以采用第四种结果,设置好每个region的超始key和终止key。
所以采用前4位字母的组合对rowkey的区间进行划分。2.用hive进行分析前4位每位数据量的占比情况
分析第一位数据量的占比情况:数据大多分布在字母013456789abcdef
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,1) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_1_1 2> /dev/null &
分析第二位数据量的占比情况:数据大多分布在字母013456789abcdef
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,2,1) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_2_1 2> /dev/null &
分析第三位数据量的占比情况:数据大多分布在字母013456789abcdef
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,3,1) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_3_1 2> /dev/null &
分析第四位数据量的占比情况:数据大多分布在字母013456789abcdef
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,4,1) as sub from user_install_status_orc) a group by sub order by n desc;" 1> ~/split_4_1 2> /dev/null &3.生成rowkey的start和end组合的配置文件
按第二步情况进行组合就会形成16*16*16*16=65536个region,有多少个region就有多少个reducer,这样会把5个主机内存耗光。
所以可以把最后一位划分成两个区间即【0到7】,【8到f】,这样会有16*16*16*2=8192个region。
根据以上情况生成region的key划分配置文件。public static void main(String[] args) {char[] arr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };for (int i1 = 0; i1 <= 15; i1++) {for (int i2 = 0; i2 <= 15; i2++) {for (int i3 = 0; i3 <= 15; i3++) {for (int i4 = 0; i4 <= 8; i4 += 8) {if (i4 == 0) {System.out.println("" + arr[i1] + arr[i2] + arr[i3]);} else {System.out.println("" + arr[i1] + arr[i2] + arr[i3] + arr[i4]);}}}}}}
4.上面的rowkey范围要仔细的再检查一遍看看是否有局部的rowkey保存了太多的数据,需要对局部偏移数据的再次划分
# 分析前四位字母组合的数据量占比
nohup hive -e "use db1;select sub,count(1) n from (select substring(aid,1,4) as sub from user_install_status where dt='20141228') a group by sub order by n desc;" 1> ~/split_4_1 2> /dev/null &5.由于前四位数据分布不均匀的问题,我们需要再次划分
-- 统计前三位为200 201 的前5位汇总
select sub1,count(1) n from 
(select substring(aid,1,3) as sub,substring(aid,1,5) as sub1 from user_install_status_orc) a 
where a.sub >='200' and a.sub <='201' 
group by a.sub1 order by n asc;
--由于5位数据也比较集中,需要看第6位的情况,统计前5位为20000 20001 的前6位汇总
select sub1,count(1) n from 
(select substring(aid,1,5) as sub,substring(aid,1,6) as sub1 from user_install_status_orc) a 
where a.sub >='20000' and a.sub <='20130' 
group by a.sub1 order by n asc;
--由于6位数据也比较集中,需要看第7位的情况,统计前5位为20014 20015 的前6位汇总
select sub1,count(1) n from 
(select substring(aid,1,6) as sub,substring(aid,1,7) as sub1 from user_install_status where dt='20141228') a 
where a.sub >='20000b' and a.sub <='200010' 
group by a.sub1 order by n asc;
可以看到于前七位数据分布比较均匀,我们用前七位就可以了
20000b7
20000b6
20000b4
20000b3
20000b8
20000b5
然后将检查分析后的结果追加到region的配置文件split_data中二、JAVA实现预分region的代码
0.打包命令:clean assembly:assembly
1.注意只需要包含pom.xml文件、assembly.xml文件split_data文件和类即可package com.shanhai.util;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;public class MySplit implements SplitAlgorithm {public Set<String> readSplitData(){//创建方法的返回值Set<String> result = new HashSet<String>();//将文件加载到内存中InputStream in = this.getClass().getClassLoader().getResourceAsStream("split_data");//进行字符流的读取BufferedReader reader = null;try {reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));String line = null;while ((line = reader.readLine()) != null) {if (Utils.isEmpty(line)) {continue;}line = line.trim();result.add(line);}} catch (Exception e) {e.printStackTrace();}finally {if (null != reader) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}return result;}@Overridepublic byte[][] split(int numRegions) {//创建方法的返回值List<byte[]> result = new ArrayList<byte[]>();//数据转换for (String s : readSplitData()) {result.add(Bytes.toBytes(s));}//返回return result.toArray(new byte[0][]);}@Overridepublic byte[] split(byte[] start, byte[] end) {// TODO Auto-generated method stubreturn null;}@Overridepublic byte[] firstRow() {// TODO Auto-generated method stubreturn null;}@Overridepublic byte[] lastRow() {// TODO Auto-generated method stubreturn null;}@Overridepublic void setFirstRow(String userInput) {// TODO Auto-generated method stub}@Overridepublic void setLastRow(String userInput) {// TODO Auto-generated method stub}@Overridepublic byte[] strToRow(String input) {// TODO Auto-generated method stubreturn null;}@Overridepublic String rowToStr(byte[] row) {// TODO Auto-generated method stubreturn null;}@Overridepublic String separator() {// TODO Auto-generated method stubreturn null;}@Overridepublic void setFirstRow(byte[] userInput) {// TODO Auto-generated method stub}@Overridepublic void setLastRow(byte[] userInput) {// TODO Auto-generated method stub}}三、配置运行环境:
1.上传到服务器的指定目录:/home/hadoop/myhbase
2.并把这个目录配置到操作机hbase-env.sh的HBASE_CLASSPATH里
vim /usr/local/hbase/conf/hbase-env.sh
export HBASE_CLASSPATH=$HBASE_CLASSPATH:$HADOOP_HOME/lib/*:/home/hadoop/myhbase/*四、根据自定义split 类创建带有预分region的表
使用以下命令创建表并根据你的自定义split类进行region的预分
hbase org.apache.hadoop.hbase.util.RegionSplitter myns1:table10 com.shanhai.util.MySplit -c 2 -f cf1其中:-c:是指定分多少个region但是在我的自定义的split中并没有使用,不过这是命令的必填项所以要必须写上。只要大于1就可以。-f:是指定列族的名称。五、执行mapreduce,将orc文件转成hfile文件
由于有8199个region,所以这个MR任务会生成8199个reducer用于生成hfile文件
hadoop jar hn16_hbase_tp2-0.0.1-SNAPSHOT-luoxichuan.jar workjob1 -Dmyhbase.tablename=myns1:table10 -Dmymr.task.id=luo -Dmymr.task.input=hdfs://ns1/hive/warehouse/db1.db/user_orc -Dhbase.zookeeper.quorum=nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181六、将生成的hfile文件导入到表中去
hadoop jar /usr/local/hbase/lib/hbase-shell-1.3.1.jar completebulkload /user/luoxichuan/task/hbase_import_data_luo myns1:table10

3.如何修改HBase表的压缩格式

1.如何修改HBase表的压缩格式
步骤:
1)下线表(该动作耗时较长,会对hbase的服务造成很大的影响,可以选择在一个服务不忙的时间来做。或者是在往表里插入数据之前就指定好每个列族的压缩算法)
disable 'myns1:user_hbase_split'
2)设置压缩算法
alter 'myns1:user_hbase_split', NAME => 'cf1', COMPRESSION => 'snappy'
3)重新上线表
enable 'myns1:user_hbase_split'
4)生效压缩配置
major_compact 'myns1:user_hbase_split'
注意:
在实际使用中应该在创建完预分region的表之后就把列簇修改成snappy压缩,不要等到数据导入之后再修改,因为会让regionserver把大量老的region下线再加载压缩完成的新region,这个过程会造成regionserver很繁忙从而影响其它表的使用。2. 正常工作流程:
1.创建预分region表。
hbase org.apache.hadoop.hbase.util.RegionSplitter myns1:user_hbase_split1 com.hnxy.util.UserInstallStatusAidSplit -c 2 -f cf
2.下线刚才创建的预分region表。
disable 'myns1:user_hbase_split2'
3.优化刚才使用预分region命令创建的表,这里是修改了"f"列簇的文件压缩格式为"snappy"。
alter 'myns1:user_hbase_split2', NAME => 'cf1', COMPRESSION => 'snappy'
4.上线优化之后预分region表。
enable 'myns1:user_hbase_split'
5.生成hfile文件。
hadoop jar ~/hbase_bk_tp2-0.0.1-SNAPSHOT-hainiu.jar hbi -Dhainiu.task.id=su -Dhainiu.task.input=hdfs://ns1/hive/warehouse/db1.db/user_orc -Dhbase.zookeeper.quorum=nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181
6.把生成的hfile文件导出到预分region表,这时数据已经snappy格式的,所以不用再major_compact,这样表就可以直接使用了,并且不会造成regionserver的region的频繁操作。
hadoop jar /usr/local/hbase/lib/hbase-shell-1.3.1.jar completebulkload hdfs://ns1//user/suniu/task/hbi_su/ myns1:user_hbase_split1
7. 刷新
major_compact 'myns1:user_hbase_split'

八、Hbase数据的批量导入+预分Region

1.需求

在hbase不需要提前做任何操作的前提下进行表的批量数据导入,并且要包括以下功能 :
1.创建表
2.进行预分region
3.进行适当的表的压缩设置
4.生成数据
5.自动导入数据
在这里插入图片描述

2.项目的整体架构

1.配置文件

0.新建split_data文件
8d000
8d001
8d002
8d003
8d004
8d005
8d006
8d007
8d008
8d009
8d00a
8d00b
8d00c
8d00d
1.拷贝pom.xml文件
	<properties><!-- maven项目整体编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 项目编译的时候,源码(.java)使用哪个版本JDK --><maven.compiler.source>1.8</maven.compiler.source><!-- 项目编译的时候,可执行文件(.class)使用哪个版本JDK --><maven.compiler.target>1.8</maven.compiler.target><!-- 设置运行主类 --><mainClass>com.shanhai.bin.NHIDJobDriver</mainClass></properties><dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.7.3</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hive</groupId><artifactId>hive-cli</artifactId><version>2.1.1</version><exclusions><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-common</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId></exclusion></exclusions><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/resources</directory></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><descriptors><descriptor>src/main/resources/assembly.xml</descriptor></descriptors><archive><manifest><mainClass>${mainClass}</mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.12</version><configuration><skip>true</skip><forkMode>once</forkMode><excludes><exclude>**/**</exclude></excludes></configuration></plugin></plugins></build>
2.新建assembly.xml文件,放到资源文件目录下
<assemblyxmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"><!-- TODO: a jarjar format would be better --><!-- 添加到生成文件名称的后缀符 --><id>shanhai</id><!-- 打包类型 --><formats><format>jar</format></formats><!-- 指定是否包含打包层目录 --><includeBaseDirectory>false</includeBaseDirectory><!-- 指定要包含的文件集 --><fileSets><fileSet><!-- 指定目录 --><directory>${project.build.directory}/classes</directory><!-- 指定文件集合的输出目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory><!-- 排除文件 --><excludes><exclude>*.xml</exclude><exclude>*.properties</exclude></excludes></fileSet></fileSets><!-- 用来定制工程依赖 jar 包的打包方式 --><dependencySets><dependencySet><!-- 指定包依赖目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory><!-- 当前项目构件是否包含在这个依赖集合里 --><useProjectArtifact>false</useProjectArtifact><!-- 是否将第三方jar包解压到该依赖中 false 直接引入jar包 true解压引入 --><unpack>true</unpack><!-- 将scope为runtime的依赖包打包到lib目录下。 --><scope>runtime</scope></dependencySet></dependencySets>
</assembly>
3.拷贝hbase-site.xml、文件,放到资源文件目录下
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration><!--	Master	--><property><name>hbase.master</name><value>nn1.hadoop:60000</value></property><!--	Client参数	--><property><name>hbase.client.scanner.caching</name><value>10000</value><description>客户端参数,HBase scanner一次从服务端抓取的数据条数</description></property><property><name>hbase.client.scanner.timeout.period</name><value>900000</value><description>scanner过期时间</description></property><!--	Zookeeper	--><property><name>hbase.zookeeper.quorum</name><value>nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181</value></property><property><name>zookeeper.session.timeout</name><value>1200000</value></property>
</configuration>
4.拷贝mapred-site.xml文件,放到资源文件目录下
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration><property><name>mapreduce.framework.name</name><value>yarn</value><description>运行模式</description></property>
</configuration>
5.拷贝log4j.properties文件,放到资源文件目录下

2.com.shanhai.util

1.BaseMR
package com.shanhai.util;import java.util.Map.Entry;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;/** 所有MapReduce任务的父类。都应该继承它,然后在进行开发* 抽取公用的东西,完成代码复用。*/
public abstract class BaseMR {//定义所有任务公共的配置文件加载对象(公共配置)public static Configuration conf;//获得配置文件的加载对象public static void setConf(Configuration conf) {BaseMR.conf = conf;}//配置任务工作链public ControlledJob getCtrlJob() throws Exception{//创建任务工作链对象ControlledJob ctrlJob = new ControlledJob(conf);//设置输出目录Path out = this.getPath(getJobNameWithTaskID());FileSystem fs = FileSystem.get(conf);if (fs.exists(out)) {//hadoop fs -rm -r out true-->递归删除fs.delete(out, true);System.out.println(this.getJobName() + "的输出目录已经被删除了!");}//设置每个任务私有的confConfiguration jobConf = new Configuration();//拷贝公共配置给当前任务使用for (Entry<String, String> entry : conf) {jobConf.set(entry.getKey(), entry.getValue());}//创建Job任务Job job = getJob(jobConf);//设置工作链的任务ctrlJob.setJob(job);//返回return ctrlJob;}//每个独立jobpublic abstract Job getJob(Configuration jobConf)throws Exception;//获取输出主目录public String getWorkPath(){return MyConstant.TASK_WORK_BASE_PATH;}//获取输出地址public Path getPath(String jobName) {return new Path(getWorkPath() + jobName);}//获取任务名称public abstract String getJobName();//获取任务名称和任务ID-->wordcount_luopublic String getJobNameWithTaskID() {return getJobName()+"_"+conf.get(MyConstant.TASK_ID);}}
2.JobRunnerResult
package com.shanhai.util;
/** 主要对任务工作链的执行结果进行封装* 1.任务工作链的执行状态* 2.任务工作链的执行时间* 3.任务工作链的所有Counter数据*/import java.util.HashMap;
import java.util.Map;import org.apache.hadoop.mapreduce.Counter;
import org.apache.hadoop.mapreduce.Counters;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;public class JobRunnerResult {private Boolean isSuccess;private String runTime;private Map<String, Counters> counterMap = new HashMap<String, Counters>();public Boolean getIsSuccess() {return isSuccess;}public void setIsSuccess(Boolean isSuccess) {this.isSuccess = isSuccess;}public String getRunTime() {return runTime;}public void setRunTime(String runTime) {this.runTime = runTime;}public Map<String, Counters> getCmap() {return counterMap;}public void setCmap(Map<String, Counters> counterMap) {this.counterMap = counterMap;}/*** 根据任务链名称 获取counters*/public Counters getCounters(String jobName){return counterMap.get(jobName);}/*** 根据工作链控制的任务名称 获取counters*/public Counters getCounters(ControlledJob colJob){return counterMap.get(colJob.getJobName());}/*** 获取指定的计数器* @param job 工作链名称* @param gname 组名称* @param cname 计数器名称* @return TODO(这里描述每个参数,如果有返回值描述返回值,如果有异常描述异常)*/public Counter getCounter(ControlledJob job,String gname,String cname){Counter counter = getCounters(job).findCounter(gname, cname);return counter;}/*** 获取指定counter的值* @param job 任务名称* @param gname 组名称* @param cname 计数器名称*/public long getCounterVal(ControlledJob job,String gname,String cname){// 获取这个技术器Counter counter = getCounter(job, gname, cname);return Utils.isEmpty(counter)?0L:counter.getValue();}}
3.JobRunnerUtil
package com.shanhai.util;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;/** 执行任务的工具类:执行任务和封装执行结果*/
public class JobRunnerUtil {//创建一个定长线程池来进行线程的管理public static ExecutorService es = Executors.newFixedThreadPool(1);//创建自己的线程类private static class MyCallable implements Callable<JobRunnerResult>{// 定义工作链对象private JobControl jobc;// 构造函数赋值public MyCallable(JobControl jobc) {super();this.jobc = jobc;}@Overridepublic JobRunnerResult call() throws Exception {//创建方法的返回值JobRunnerResult result = new JobRunnerResult();//监控任务工作链的执行//定义开始时间Long startTime = System.currentTimeMillis();//监控执行情况while (!jobc.allFinished()) {//任务没有全部完成Thread.sleep(1000);}//定义结束时间Long endTime = System.currentTimeMillis();//判断任务是否成功result.setIsSuccess(jobc.getFailedJobList().size() == 0);//任务执行成功获取counters数据for (ControlledJob job : jobc.getSuccessfulJobList()) {//按照任务名称保存所有Counters数据result.getCmap().put(job.getJob().getJobName(), job.getJob().getCounters());}//获取运行时间Long tmp = endTime - startTime;String runTime = getLifeTime(tmp);result.setRunTime(runTime);jobc.stop();//返回return result;}private String getLifeTime(Long mss){// 计算用了多少天Long days = mss / (1000*60*60*24);// 计算用了多少个小时 取余数算出不足一天的毫秒数 然后除以小时的毫秒 转换成小时单位Long hours = (mss%(1000*60*60*24))/(1000*60*60);// 计算用了多少分钟Long minutes = (mss%(1000*60*60))/(1000*60);// 计算用了所少秒钟Long seconds = (mss%(1000*60))/1000;// 开始拼接时间StringBuilder sb = new StringBuilder();// 判断if(days != 0){sb.append(days).append("天");}if(hours != 0){sb.append(hours).append("小时");}if(minutes != 0){sb.append(minutes).append("分钟");}if(seconds != 0){sb.append(seconds).append("秒");}return sb.toString();}}public static JobRunnerResult run(JobControl jobc) throws Exception{Thread thread = new Thread(jobc);thread.start();Future<JobRunnerResult> f = es.submit(new MyCallable(jobc));return f.get();}}
4.MyConstant
package com.shanhai.util;
/** 封装我们自己的常量类*/
public class MyConstant {//hbase:rowkey的分隔符public static final String SQE1 = "_";//任务ID//-Dmymr.task.id=luo	wordcount-->outpath wordcount_luopublic static final String TASK_ID = "mymr.task.id";//任务的输入地址//-Dmymr.task.input=D:\hdfs\input\hn16\mr1	固定我们任务的输入目录public static final String TASK_INPUT = "mymr.task.input";//任务的工作目录(windows下制定的绝对路径 如果扔到集群上需要修改成HDFS路径)//-Dmymr.task.output=D:/user/luoxichuan/task/wordcount_luo/part-r-000000 固定我们任务的输出目录//本地:D:/hdfs/user/luoxichuan/task///线上:/user/luoxichuan/task/public static final String TASK_WORK_BASE_PATH = "/user/luoxichuan/task/";}
5.MyRegionSpliter
package com.shanhai.util;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;public class MyRegionSpliter implements SplitAlgorithm {public Set<String> readSplitData(){//创建方法的返回值Set<String> result = new HashSet<String>();//将文件加载到内存中InputStream in = this.getClass().getClassLoader().getResourceAsStream("split_data");//进行字符流的读取BufferedReader reader = null;try {reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));String line = null;while ((line = reader.readLine()) != null) {if (Utils.isEmpty(line)) {continue;}result.add(line.trim());}} catch (Exception e) {e.printStackTrace();}finally {if (null != reader) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}return result;}@Overridepublic byte[][] split(int numRegions) {//创建方法的返回值List<byte[]> result = new ArrayList<byte[]>();//数据转换for (String s : readSplitData()) {result.add(Bytes.toBytes(s));}//返回return result.toArray(new byte[0][]);}@Overridepublic byte[] split(byte[] start, byte[] end) {// TODO Auto-generated method stubreturn null;}@Overridepublic byte[] firstRow() {// TODO Auto-generated method stubreturn null;}@Overridepublic byte[] lastRow() {// TODO Auto-generated method stubreturn null;}@Overridepublic void setFirstRow(String userInput) {// TODO Auto-generated method stub}@Overridepublic void setLastRow(String userInput) {// TODO Auto-generated method stub}@Overridepublic byte[] strToRow(String input) {// TODO Auto-generated method stubreturn null;}@Overridepublic String rowToStr(byte[] row) {// TODO Auto-generated method stubreturn null;}@Overridepublic String separator() {// TODO Auto-generated method stubreturn null;}@Overridepublic void setFirstRow(byte[] userInput) {// TODO Auto-generated method stub}@Overridepublic void setLastRow(byte[] userInput) {// TODO Auto-generated method stub}}
6.ORCFormat
package com.shanhai.util;/** 保存ORC结构的工具类*/
public class ORCFormat {//定义ORC的结构public static final String MY_ORC_TYPE1 = "struct<aid:string,pkgname:string,uptime:bigint,type:int,country:string,gpcategory:string>";}
7.ORCUtil
package com.shanhai.util;import org.apache.hadoop.hive.ql.io.orc.OrcStruct;
import org.apache.hadoop.hive.serde2.objectinspector.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;/** 解析ORC的一行数据工具类*/
public class ORCUtil {//一行ORC数据对象private OrcStruct os = null;//一行ORC数据对象的结构private StructObjectInspector soi = null;//赋予ORC数据结构public void setOrcType(String orcType){//获取ORC的结构数据TypeInfo info = TypeInfoUtils.getTypeInfoFromTypeString(orcType);//进行类型转换soi = (StructObjectInspector) OrcStruct.createObjectInspector(info);}//获取一行ORC数据public void setOs(OrcStruct os) {this.os = os;}//获取一行ORC的列的数据public String getDataByKey(String key){//创建方法的返回值String result = null;//根据结构获取想要的列StructField fild = soi.getStructFieldRef(key);//获取数据result = String.valueOf(soi.getStructFieldData(os, fild));if (Utils.isEmpty(result)||result.toLowerCase().equals("null")) {return null;}//返回return result;}}
8.Utils
package com.shanhai.util;import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;/** 判断对象是否为空的工具类*/
public class Utils {/** 判断各类型的对象是否为:空*/public static Boolean isEmpty(Object obj){Boolean boo = false;if (obj == null) {boo = true;}else if (obj instanceof String) {boo = "".equals(obj.toString().trim());}else if (obj instanceof Map<?, ?>) {boo = ((Map<?, ?>)obj).isEmpty();}else if (obj instanceof Collection<?>) {boo = ((Collection<?>)obj).isEmpty();}else if (obj.getClass().isArray()) {boo = Array.getLength(obj)==0;}return boo;}/** 判断各类型的对象是否为:非空*/public static Boolean isNotEmpty(Object obj){return !isEmpty(obj);}}

3.com.shanhai.mr

1.NewHbaseDataImport
package com.shanhai.mr;import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hive.ql.io.orc.OrcNewInputFormat;
import org.apache.hadoop.hive.ql.io.orc.OrcStruct;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import com.shanhai.util.BaseMR;
import com.shanhai.util.MyConstant;
import com.shanhai.util.ORCFormat;
import com.shanhai.util.ORCUtil;
import com.shanhai.util.Utils;public class NewHbaseDataImport extends BaseMR {private static class MyMapper extends Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>{//定义map需要用到的变量private ORCUtil ou = new ORCUtil();//定义列族private byte[] family = Bytes.toBytes("cf1");//定义列private byte[] pkgnameQ = Bytes.toBytes("pkgname");private byte[] typeQ = Bytes.toBytes("type");private byte[] countryQ = Bytes.toBytes("country");private byte[] gpcategoryQ = Bytes.toBytes("gpcategory");//定义时间格式化类private  DateFormat df = new SimpleDateFormat("yyyyMMdd");//定义输出的keyprivate ImmutableBytesWritable outkey = new ImmutableBytesWritable();private Put outval = null;@Overrideprotected void setup(Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>.Context context)throws IOException, InterruptedException {//获取ORC表结构ou.setOrcType(ORCFormat.MY_ORC_TYPE1);}@Overrideprotected void map(NullWritable key, OrcStruct value,Mapper<NullWritable, OrcStruct, ImmutableBytesWritable, Put>.Context context)throws IOException, InterruptedException {//解析ORC对象ou.setOs(value);//获取列的数据String aid,pkgname,uptime,type,country,gpcategory;aid = ou.getDataByKey("aid");pkgname = ou.getDataByKey("pkgname");uptime = ou.getDataByKey("uptime");type = ou.getDataByKey("type");country = ou.getDataByKey("country");gpcategory = ou.getDataByKey("gpcategory");//设置rowkeyString rowkey = aid+MyConstant.SQE1+df.format(new Date(Long.parseLong(uptime.trim())*1000));//进行put对象的封装outval = new Put(Bytes.toBytes(rowkey));if(Utils.isNotEmpty(pkgname)){outval.addColumn(family, pkgnameQ, Bytes.toBytes(pkgname));}if(Utils.isNotEmpty(type)){outval.addColumn(family, typeQ, Bytes.toBytes(type));}if(Utils.isNotEmpty(country)){outval.addColumn(family, countryQ, Bytes.toBytes(country));}if(Utils.isNotEmpty(gpcategory)){outval.addColumn(family, gpcategoryQ, Bytes.toBytes(gpcategory));}//设置输出outkey.set(outval.getRow());context.write(outkey, outval);}}@Overridepublic Job getJob(Configuration jobConf) throws Exception {//创建方法的返回值Job job = Job.getInstance(conf, this.getJobNameWithTaskID());//设置打包类job.setJarByClass(NewHbaseDataImport.class);job.setMapperClass(MyMapper.class);//设置map的格式化类job.setInputFormatClass(OrcNewInputFormat.class);//设置map的输入与输出类型job.setMapOutputKeyClass(ImmutableBytesWritable.class);job.setMapOutputValueClass(Put.class);//设置输入与输出目录FileInputFormat.addInputPath(job, new Path(jobConf.get(MyConstant.TASK_INPUT)));FileOutputFormat.setOutputPath(job, this.getPath(this.getJobNameWithTaskID()));//获取数据连接Connection conn = ConnectionFactory.createConnection(jobConf);//获取要操作的表HTable mytable = (HTable)conn.getTable(TableName.valueOf(jobConf.get("myhbase.table.name")));//让我们的任务与Hbase写好的putSortReducer整合HFileOutputFormat2.configureIncrementalLoad(job, mytable, mytable.getRegionLocator());//释放资源if (null != mytable) {mytable.close();}if (null != conn) {conn.close();}//返回return job;}@Overridepublic String getJobName() {return "auto_hbase_import_data";}}

4.com.shanhai.bin

1.NHIDJobRunner
package com.shanhai.bin;import java.io.IOException;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.io.compress.Compression;
import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.RegionSplitter;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import com.shanhai.mr.NewHbaseDataImport;
import com.shanhai.util.JobRunnerResult;
import com.shanhai.util.JobRunnerUtil;
import com.shanhai.util.MyRegionSpliter;public class NHIDJobRunner extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//获取Hadoop的配置文件对象Configuration conf = this.getConf();//设置公共的配置文件加载对象conf,只需加载一次就可以NewHbaseDataImport.setConf(conf);NewHbaseDataImport nhdi = new NewHbaseDataImport();//创建hbase表并预分regionRegionSplitter.main(new String[]{conf.get("myhbase.table.name"),MyRegionSpliter.class.getName(),"-c","2","-f","cf1"});//修改表 HBASE表的数据压缩modifyTable(conf,nhdi);//创建任务工作链JobControl jobc = new JobControl("NHID");//获取工作链的任务ControlledJob job1 = nhdi.getCtrlJob();//设置工作链的任务jobc.addJob(job1);//执行任务 ORC文件转HFILE文件JobRunnerResult result = JobRunnerUtil.run(jobc);//HBASE导入数据if (result.getIsSuccess()) {//HBASE数据导入对象LoadIncrementalHFiles load = new LoadIncrementalHFiles(conf);//导入数据load.run(new String[]{nhdi.getPath(nhdi.getJobNameWithTaskID()).toString(),conf.get("myhbase.table.name")});}//输出任务状态信息if (result.getIsSuccess()) {//这里可以打印Counters的信息System.out.println("JOB_STATUS : OK!");System.out.println("THE PROGRAM IS RUN " + result.getRunTime());} else {System.out.println("JOB_STATUS : FALL!");}return 0;}private void modifyTable(Configuration conf, NewHbaseDataImport nhdi) {//创建数据库连接Connection conn = null;//创建DDL表的管理对象HBaseAdmin admin = null;try {//获取数据库连接conn = ConnectionFactory.createConnection(conf);//获取DDL表的管理对象admin = (HBaseAdmin)conn.getAdmin();//定义要操作的表名TableName tableName = TableName.valueOf(conf.get("myhbase.table.name"));//下线这张表admin.disableTable(tableName);//定义列族描述器@SuppressWarnings("deprecation")HColumnDescriptor descriptor = new HColumnDescriptor(Bytes.toBytes("cf1"),HColumnDescriptor.DEFAULT_VERSIONS,	// 保留原来的版本Compression.Algorithm.SNAPPY.getName(), // 设置数据的snappy压缩HColumnDescriptor.DEFAULT_IN_MEMORY, // 是否尝试从内存中提供此列族的默认设置。 默认falseHColumnDescriptor.DEFAULT_BLOCKCACHE, // 是否使用块缓存的默认设置。 默认trueHColumnDescriptor.DEFAULT_TTL, // 单元格内容的默认生存时间。默认 Integer的最大值HColumnDescriptor.DEFAULT_BLOOMFILTER); // 是否使用布隆的默认设置。(行键的哈希在每次插入行时将被添加到布隆)//确定修改 数据的压缩算法admin.modifyColumn(tableName, descriptor);//上线这张表admin.enableTable(tableName);} catch (IOException e) {e.printStackTrace();}finally {if (null != admin) {try {admin.close();} catch (IOException e) {e.printStackTrace();}}if (null != conn) {try {conn.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) {try {System.exit(ToolRunner.run(new NHIDJobRunner(), args));} catch (Exception e) {e.printStackTrace();}}}
2.NHIDJobDriver
package com.shanhai.bin;import org.apache.hadoop.util.ProgramDriver;public class NHIDJobDriver {public static void main(String[] args) {//创建驱动程序对象ProgramDriver driver = new ProgramDriver();try {//加载要执行的类driver.addClass("NHID", NHIDJobRunner.class, "HBASE批量数据导入!");//反射执行ProgramDriver.class.getMethod("driver", new Class[]{String[].class}).invoke(driver, new Object[]{args});} catch (Throwable e) {e.printStackTrace();}}
}

3.集群环境配置

1.操作机配置hadoop-env.sh环境,否则会报找不到类。
vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh
export HADOOP_CLASSPATH=末尾添加:【:/home/hadoop/myhbase/*】

4.集群运行

1.打包项目:
打包命令:clean assembly:assembly2.上传Jar包:
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ rz3.集群运行
[hadoop@nn1 myhbase]$ hadoop jar hn16_hbase_tp4-0.0.1-SNAPSHOT-luoxichuan.jar NHID -Dmyhbase.table.name=myns1:table11 -Dmymr.task.id=su -Dmymr.task.input=hdfs://ns1/hive/warehouse/db1.db/user_orc -Discreate.table=true -Dhbase.zookeeper.quorum=nn1.hadoop:2181,nn2.hadoop:2181,s1.hadoop:2181

九、HFILE文件转ORC文件

1.HFILE-BY-ORC项目的整体架构

在这里插入图片描述

1.配置文件

1.新建assembly.xml文件,放到资源文件目录下

2.com.shanhai.util

6.ORCWriteUtil
package com.shanhai.util;import java.util.ArrayList;
import java.util.List;import org.apache.hadoop.hive.ql.io.orc.OrcSerde;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;
import org.apache.hadoop.io.Writable;/** ORC记录写入工具类:传入相应的参数,写入到orc文件中去*/
public class ORCWriteUtil {//1.定义ORC结构的解析对象private ObjectInspector oi = null;//2.定义一个List集合,用于存储ORC的字段private List<Object> list = null;//3.定义ORC文件的序列化对象private OrcSerde os = null;/** 初始化ORC结构的解析对象*/public void setOrcWriteType(String type) {//获取ORC结构信息TypeInfo typeInfo = TypeInfoUtils.getTypeInfoFromTypeString(type);//获取ORC结构的解析对象oi = TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(typeInfo);}/** 添加要写入的ORC数据*/public ORCWriteUtil addAttr(Object... params) {//判断一下保存数据的集合是否为空,如果为空就重新创建if (Utils.isEmpty(list)) {list = new ArrayList<Object>();}//解析参数,进行数据的添加for (Object o : params) {list.add(o);}//返回return this;}/** 将ORC数据进行hadoop序列化*/public Writable serialize() {//判断是否为空if (Utils.isEmpty(os)) {os = new OrcSerde();}//进行数据的序列化Writable result = os.serialize(list, oi);//清空保存数据的集合list = new ArrayList<Object>();return result;}}

3.com.shanhai.mr

1.HfileByOrc
package com.shanhai.mr;import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.RegexStringComparator;
import org.apache.hadoop.hbase.filter.RowFilter;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hive.ql.io.orc.CompressionKind;
import org.apache.hadoop.hive.ql.io.orc.OrcNewOutputFormat;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import com.shanhai.util.BaseMR;
import com.shanhai.util.MyConstant;
import com.shanhai.util.ORCFormat;
import com.shanhai.util.ORCWriteUtil;
import com.shanhai.util.Utils;public class HfileByOrc extends BaseMR {private static class MyMapper extends TableMapper<NullWritable, Writable>{//定义map需要的变量private ORCWriteUtil owu = new ORCWriteUtil();//定义列族private byte[] family = Bytes.toBytes("cf1");//定义列//aid,pkgname,uptime,type,country,gpcategoryprivate byte[] pkgnameQ = Bytes.toBytes("pkgname");private byte[] typeQ = Bytes.toBytes("type");private byte[] countryQ = Bytes.toBytes("country");private byte[] gpcategoryQ = Bytes.toBytes("gpcategory");//定义时间格式化类private DateFormat df = new SimpleDateFormat("yyyyMMdd");@Overrideprotected void setup(Mapper<ImmutableBytesWritable, Result, NullWritable, Writable>.Context context)throws IOException, InterruptedException {//设定ORC的格式owu.setOrcWriteType(ORCFormat.MY_ORC_TYPE1);}//定义中间变量private String rowkey = "";private String aid;private Long uptime;private String tmptime;private Integer type;private String tmptype;private String pkgname,country,gpcategory;private String[] strs = null;@Overrideprotected void map(ImmutableBytesWritable key, Result value,Mapper<ImmutableBytesWritable, Result, NullWritable, Writable>.Context context)throws IOException, InterruptedException {//获取rowkeyrowkey = Bytes.toString((key.get()));//拆分rowkeystrs = rowkey.split(MyConstant.SQE1);//截取aidaid = strs[0];//截取时间tmptime = strs[1];try {uptime = df.parse(tmptime).getTime()/1000;} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}//获取数据pkgname = Bytes.toString(value.getValue(family, pkgnameQ));tmptype = Bytes.toString(value.getValue(family, typeQ));type = Integer.parseInt(Utils.isEmpty(tmptype)||tmptype.toLowerCase().equals("null")?"-1":tmptype);country = Bytes.toString(value.getValue(family, countryQ));gpcategory = Bytes.toString(value.getValue(family, gpcategoryQ));//添加数据aid,pkgname,uptime,type,country,gpcategoryowu.addAttr(aid,pkgname,uptime,type,country,gpcategory);//输出context.write(NullWritable.get(), owu.serialize());}}@Overridepublic Job getJob(Configuration jobConf) throws Exception {//1.定义hadoop相关属性//关闭推测执行:本次任务是写任务,防止数据重复写入jobConf.set("mapreducer.map.spedulative", "false");//设置压缩算法jobConf.set("orc.compress", CompressionKind.SNAPPY.name());//索引创建jobConf.set("orc.create.index", "true");//2.定义任务//定义jobJob job = Job.getInstance(jobConf, this.getJobNameWithTaskID());//设置不需要reducejob.setNumReduceTasks(0);//设置打包类job.setJarByClass(HfileByOrc.class);//3.创建数据扫描器和数据过滤器//创建扫描器Scan scan = new Scan();//设置扫描器scan.addFamily(Bytes.toBytes("cf1"));scan.setCaching(100);//设置抓取一起跳数据scan.setCacheBlocks(false);//设置查询的数据不放入缓存//创建rowkey过滤器RowFilter rf = new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^8d008"));scan.setFilter(rf);//4.设置读取HBASE表的M-R配置TableMapReduceUtil.initTableMapperJob(jobConf.get("myhbase.table.name"), scan, MyMapper.class, NullWritable.class, Writable.class, job);//设置输出格式化类job.setOutputFormatClass(OrcNewOutputFormat.class);//设置输出目录FileOutputFormat.setOutputPath(job, this.getPath(this.getJobNameWithTaskID()));return job;}@Overridepublic String getJobName() {return "hfile_by_orc";}}

4.com.shanhai.bin

1.HBORunner
package com.shanhai.bin;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import com.shanhai.mr.HfileByOrc;
import com.shanhai.util.JobRunnerResult;
import com.shanhai.util.JobRunnerUtil;public class HBORunner extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//创建任务工作链JobControl jobc = new JobControl("jw1");//获取Hadoop的配置文件对象Configuration conf = this.getConf();//设置公共的配置文件加载对象conf,只需加载一次就可以HfileByOrc.setConf(conf);HfileByOrc hde = new HfileByOrc();//获取工作链的任务ControlledJob job1 = hde.getCtrlJob();//设置工作链的任务jobc.addJob(job1);//运行任务JobRunnerResult result = JobRunnerUtil.run(jobc);if (result.getIsSuccess()) {//这里可以打印Counters的信息System.out.println("JOB_STATUS : OK!");System.out.println("THE PROGRAM IS RUN " + result.getRunTime());} else {System.out.println("JOB_STATUS : FALL!");}return 0;}public static void main(String[] args) {try {System.exit(ToolRunner.run(new HBORunner(), args));} catch (Exception e) {e.printStackTrace();}}}
2.HBODriver
package com.shanhai.bin;import org.apache.hadoop.util.ProgramDriver;public class HBODriver {public static void main(String[] args) {//创建驱动程序对象ProgramDriver driver = new ProgramDriver();try {//加载要执行的类driver.addClass("hbo", HBORunner.class, "hbase数据导出!");//反射执行ProgramDriver.class.getMethod("driver", new Class[]{String[].class}).invoke(driver, new Object[]{args});} catch (Throwable e) {e.printStackTrace();}}}

2.集群运行

1.打包项目:
打包命令:clean assembly:assembly2.上传Jar包:
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ rz3.集群运行
hadoop jar hn15_edfh-0.0.1-SNAPSHOT-su.jar hde -Dhainiu.table.name=myns1:table5 -Dhainiu.task.id=su 

3.创建Hive-ORC-外部表

use db1;CREATE TABLE `user_install_status_hfile_by_orc`(
`aid` string COMMENT 'from deserializer', 
`pkgname` string COMMENT 'from deserializer', 
`uptime` bigint COMMENT 'from deserializer', 
`type` int COMMENT 'from deserializer', 
`country` string COMMENT 'from deserializer', 
`gpcategory` string COMMENT 'from deserializer')
stored as orc
LOCATION '/user/luoxichuan/task/hfile_by_orc_luo'
TBLPROPERTIES ('orc.compress'='SNAPPY','orc.create.index'='true');

4.验证数据

select * from user_install_status_hfile_by_orc;

十、MR读写AVRO文件

1.项目需求:

需求:MR读写AVRO文件。(也就是AVRO文件转新AVRO文件)

2.生成测试数据

用hive SQL语句转Avro/Orc的语法:
ORC转AVRO:create table user_avro stored as avro as select * from user_orc;
AVRO转ORC:create table user_orc stored as avro as select * from user_avro;1.从原来ORC表中导出条数据生成avro表用于测试
create table user_avro stored as avro as select * from user_orc;2.找到Avro文件下载下来
show create table user_avro;3.提取avro数据格式 : 编写mr任务用于读取AVRO格式数据并生成新的AVRO格式数据,并根据新的AVRO格式创建外部表.
{"type":"record","name":"user_avro","namespace":"db1","fields":[{"name":"aid","type":["null","string"],"default":null},{"name":"pkgname","type":["null","string"],"default":null},{"name":"uptime","type":["null","long"],"default":null},{"name":"type","type":["null","int"],"default":null},{"name":"country","type":["null","string"],"default":null},{"name":"gpcategory","type":["null","string"],"default":null}]}{\"type\":\"record\",\"name\":\"user_avro\",\"namespace\":\"db1\",\"fields\":[{\"name\":\"aid\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"pkgname\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"uptime\",\"type\":[\"null\",\"long\"],\"default\":null},{\"name\":\"type\",\"type\":[\"null\",\"int\"],\"default\":null},{\"name\":\"country\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"gpcategory\",\"type\":[\"null\",\"string\"],\"default\":null}]}

3.项目的整体架构:

在这里插入图片描述

1.com.shanhai.mr

1.AvroToAvro
package com.shanhai.mr;import java.io.IOException;import org.apache.avro.Schema;
import org.apache.avro.Schema.Parser;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.mapred.AvroKey;
import org.apache.avro.mapreduce.AvroJob;
import org.apache.avro.mapreduce.AvroKeyInputFormat;
import org.apache.avro.mapreduce.AvroKeyOutputFormat;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import com.shanhai.util.BaseMR;
import com.shanhai.util.MyConstant;
import com.shanhai.util.Utils;/** Avro文件转新的Avro文件*/
public class AvroToAvro extends BaseMR{//定义AVRO结构的解析对象private static Parser parser1 = new Schema.Parser();//读取原始数据的AVRO结构private static Schema schema1 = parser1.parse("{\"type\":\"record\",\"name\":\"user_avro\",\"namespace\":\"db1\",\"fields\":[{\"name\":\"aid\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"pkgname\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"uptime\",\"type\":[\"null\",\"long\"],\"default\":null},{\"name\":\"type\",\"type\":[\"null\",\"int\"],\"default\":null},{\"name\":\"country\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"gpcategory\",\"type\":[\"null\",\"string\"],\"default\":null}]}");//定义AVRO结构的解析对象private static Parser parser2 = new Schema.Parser();//读取导出数据的AVRO结构private static Schema schema2 = parser2.parse("{\"type\":\"record\",\"name\":\"user_avro\",\"namespace\":\"db1\",\"fields\":[{\"name\":\"aid\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"pkgname\",\"type\":[\"null\",\"string\"],\"default\":null}]}");public static class MyMapper extends Mapper<AvroKey<GenericRecord>, NullWritable, AvroKey<GenericRecord>, NullWritable>{//定义map需要的变量private String aid = "";private String pkgname = "";@Overrideprotected void map(AvroKey<GenericRecord> key, NullWritable value,Mapper<AvroKey<GenericRecord>, NullWritable, AvroKey<GenericRecord>, NullWritable>.Context context)throws IOException, InterruptedException {//获取AVRO表的一行数据GenericRecord record1 = key.datum();//解析数据aid = String.valueOf(record1.get("aid"));pkgname = String.valueOf(record1.get("pkgname"));//判断数据是否为空aid = Utils.isEmpty(aid)||aid.toLowerCase().equals("null")?null:aid;pkgname = Utils.isEmpty(pkgname)||pkgname.toLowerCase().equals("null")?null:pkgname;//保存数据GenericRecord record2 = new GenericData.Record(schema2);record2.put("aid", aid);record2.put("pkgname", pkgname);//输出context.write(new AvroKey<GenericRecord>(record2), NullWritable.get());}}@Overridepublic Job getJob(Configuration jobConf) throws Exception {Job job = Job.getInstance(jobConf, this.getJobNameWithTaskID());job.setJarByClass(AvroToAvro.class);job.setMapperClass(MyMapper.class);job.setNumReduceTasks(0);job.setOutputKeyClass(AvroKey.class);job.setOutputValueClass(NullWritable.class);job.setInputFormatClass(AvroKeyInputFormat.class);job.setOutputFormatClass(AvroKeyOutputFormat.class);//指定使用哪个结构进行数据的导出AvroJob.setOutputKeySchema(job, schema2);//设置输入与输出的地址FileInputFormat.addInputPath(job, new Path(jobConf.get(MyConstant.TASK_INPUT)));FileOutputFormat.setOutputPath(job, this.getPath(this.getJobNameWithTaskID()));return job;}@Overridepublic String getJobName() {return "avro_to_avro";}}

1.com.shanhai.bin

1.ATARunner
package com.shanhai.bin;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import com.shanhai.mr.AvroToAvro;
import com.shanhai.util.JobRunnerResult;
import com.shanhai.util.JobRunnerUtil;public class ATARunner extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//创建任务工作链JobControl jobc = new JobControl("jw1");//获取Hadoop的配置文件对象Configuration conf = this.getConf();//设置公共的配置文件加载对象conf,只需加载一次就可以AvroToAvro.setConf(conf);	AvroToAvro hde = new AvroToAvro();//获取工作链的任务ControlledJob job1 = hde.getCtrlJob();//设置工作链的任务jobc.addJob(job1);//运行任务JobRunnerResult result = JobRunnerUtil.run(jobc);if (result.getIsSuccess()) {//这里可以打印Counters的信息System.out.println("JOB_STATUS : OK!");System.out.println("THE PROGRAM IS RUN " + result.getRunTime());} else {System.out.println("JOB_STATUS : FALL!");}return 0;}public static void main(String[] args) {try {System.exit(ToolRunner.run(new ATARunner(), args));} catch (Exception e) {e.printStackTrace();}}}

4.线下运行:

1.运行命令:
-Dmymr.task.id=luo -Dmymr.task.input=D:\hdfs\input\hn16\mr102.找到输出文件,打开文件 整理avro的JSON建表描述,创建avro_to_avro.avro文件
{"type":"record","name":"user_avro","namespace":"db1","fields":[{"name":"aid","type":["null","string"],"default":null},{"name":"pkgname","type":["null","string"],"default":null}]
}{"type":"record","name":"user_avro","namespace":"db1","fields":[{"name":"aid","type":["null","string"],"default":null},{"name":"pkgname","type":["null","string"],"default":null}}3.将avro_to_avro.avro文件,上传到/user/luoxichuan/avroconf/目录
[hadoop@nn1 ~]$ cd ~/myhbase
[hadoop@nn1 myhbase]$ rz
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ hadoop fs -put avro_to_avro.avro /user/luoxichuan/avroconf/4.创建新的avro表并导入数据
use db1;
CREATE TABLE IF NOT EXISTS user_install_status_avro_other
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
WITH SERDEPROPERTIES ('avro.schema.url'='/user/luoxichuan/avroconf/avro_to_avro.avro')
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat';5.查看表的位置
hive (db1)> show create table user_install_status_avro_other;6.上传数据
[hadoop@nn1 myhbase]$ hadoop fs -put part-m-00000.avro hdfs://ns1/hive/warehouse/db1.db/user_install_status_avro_other7.查询验证
hive (db1)> select * from user_install_status_avro_other;

5.集群运行

1.在集群运行之前的说明1.注意,在集群上2.7.3的hadoop版本,avrojar包只有1.7.4版本的;2.在集群运行会报错,报错内容如下:缺少createDatumWriter()方法;3.但是1.7.7 版本的avro有此方法。所以,需要你删除集群上1.7.4 版本avro的jar2.替换集群所有机器的Jar包
# 删除/usr/local/hadoop/share/hadoop/common/lib/下的avro-1.7.4.jar
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh rm -rf /usr/local/hadoop/share/hadoop/common/lib/avro-1.7.4.jar
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh ls -l /usr/local/hadoop/share/hadoop/common/lib/ | grep avro
# 删除/usr/local/hbase/lib/下的avro-1.7.4.jar
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh rm -rf /usr/local/hbase/lib/avro-1.7.4.jar
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh ls -l /usr/local/hbase/lib/ | grep avro# 上传avro-1.7.7.jar
[hadoop@nn1 ~]$ rz
[hadoop@nn1 ~]$ ll
# 分发avro-1.7.7.jar
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/scp_all.sh ~/avro-1.7.7.jar /tmp/
# 复制avro-1.7.7.jar到/usr/local/hadoop/share/hadoop/common/lib/
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh cp /tmp/avro-1.7.7.jar /usr/local/hadoop/share/hadoop/common/lib/
# 复制avro-1.7.7.jar到/usr/local/hbase/lib/
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh cp /tmp/avro-1.7.7.jar /usr/local/hbase/lib/
# 复制avro-1.7.7.jar到/usr/local/hadoop/share/hadoop/yarn
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh cp /tmp/avro-1.7.7.jar /usr/local/hadoop/share/hadoop/yarn
# 复制avro-1.7.7.jar到/usr/local/hadoop/lib
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh cp /tmp/avro-1.7.7.jar /usr/local/hadoop/lib3.检查/usr/local/hadoop/lib 目录下是否有hive-exec-2.1.1.jar(hbase批量导入时,配置的集群环境),如果没有,把该jar包分发到所有机器的/usr/local/hadoop/lib 目录下。
[hadoop@nn1 ~]$ sh ~/hadoop_base_op/ssh_all.sh ls -l /usr/local/hadoop/lib | grep hive-exec1.打包项目:
打包命令:clean assembly:assembly2.上传Jar包:
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ rz3.集群运行
hadoop jar hn16_hbase_tp6-0.0.1-SNAPSHOT-luoxichuan.jar com.shanhai.bin.ATARunner -Dmymr.task.id=luo -Dmymr.task.input=/hive/warehouse/db1.db/user_avro3.找到输出文件,下载文件 整理avro的JSON建表描述,创建avro_to_avro.avro文件
{"type":"record","name":"user_avro","namespace":"db1","fields":[{"name":"aid","type":["null","string"],"default":null},{"name":"pkgname","type":["null","string"],"default":null}]
}{"type":"record","name":"user_avro","namespace":"db1","fields":[{"name":"aid","type":["null","string"],"default":null},{"name":"pkgname","type":["null","string"],"default":null}}4.将avro_to_avro.avro文件,上传到/user/luoxichuan/avroconf/目录
[hadoop@nn1 ~]$ cd ~/myhbase
[hadoop@nn1 myhbase]$ rz
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ hadoop fs -put avro_to_avro.avro /user/luoxichuan/avroconf/5.创建外部-AVRO表
CREATE EXTERNAL TABLE IF NOT EXISTS user_install_status_avro_other2
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
WITH SERDEPROPERTIES ('avro.schema.url'='/user/luoxichuan/avroconf/avro_to_avro.avro')
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
LOCATION 'hdfs://ns1/user/luoxichuan/task/avro_to_avro_luo';6.验证数据
hive (db1)> select * from user_install_status_avro_other1;

十一、Hbase数据的批量导出

1.项目需求:

Hbase数据的批量导出:自定义inputformat实现数据转换准备数据:
scan 'myns1:user_install_status'

2.项目的整体架构:

在这里插入图片描述

1.配置文件

1.pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.shanhai</groupId><artifactId>hn16_hbase_tp7</artifactId><version>0.0.1-SNAPSHOT</version><properties><!-- maven项目整体编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 项目编译的时候,源码(.java)使用哪个版本JDK --><maven.compiler.source>1.8</maven.compiler.source><!-- 项目编译的时候,可执行文件(.class)使用哪个版本JDK --><maven.compiler.target>1.8</maven.compiler.target><!-- 设置运行主类 --><mainClass>com.shanhai.bin.NHDEDriver</mainClass></properties><dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.7.3</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId><version>1.3.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.hive</groupId><artifactId>hive-cli</artifactId><version>2.1.1</version><exclusions><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-common</artifactId></exclusion><exclusion><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId></exclusion></exclusions><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/resources</directory></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><descriptors><descriptor>src/main/resources/assembly.xml</descriptor></descriptors><archive><manifest><mainClass>${mainClass}</mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.12</version><configuration><skip>true</skip><forkMode>once</forkMode><excludes><exclude>**/**</exclude></excludes></configuration></plugin></plugins></build>
</project>
2.新建assembly.xml文件,放到资源文件目录下
<assemblyxmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"><!-- TODO: a jarjar format would be better --><!-- 添加到生成文件名称的后缀符 --><id>shanhai</id><!-- 打包类型 --><formats><format>jar</format></formats><!-- 指定是否包含打包层目录 --><includeBaseDirectory>false</includeBaseDirectory><!-- 指定要包含的文件集 --><fileSets><fileSet><!-- 指定目录 --><directory>${project.build.directory}/classes</directory><!-- 指定文件集合的输出目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory><!-- 排除文件 --><excludes><exclude>*.xml</exclude><exclude>*.properties</exclude></excludes></fileSet></fileSets><!-- 用来定制工程依赖 jar 包的打包方式 --><dependencySets><dependencySet><!-- 指定包依赖目录,该目录是相对于根目录 --><outputDirectory>/</outputDirectory><!-- 当前项目构件是否包含在这个依赖集合里 --><useProjectArtifact>false</useProjectArtifact><!-- 是否将第三方jar包解压到该依赖中 false 直接引入jar包 true解压引入 --><unpack>true</unpack><!-- 将scope为runtime的依赖包打包到lib目录下。 --><scope>runtime</scope></dependencySet></dependencySets>
</assembly>

2.com.shanhai.util

1.ORCWriteUtil
package com.shanhai.util;import java.util.ArrayList;
import java.util.List;import org.apache.hadoop.hive.ql.io.orc.OrcSerde;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;
import org.apache.hadoop.io.Writable;/** ORC记录写入工具类:传入相应的参数,写入到orc文件中去*/
public class ORCWriteUtil {//1.定义ORC结构的解析对象private ObjectInspector oi = null;//2.定义一个List集合,用于存储ORC的字段private List<Object> list = null;//3.定义ORC文件的序列化对象private OrcSerde os = null;/** 初始化ORC结构的解析对象*/public void setOrcWriteType(String type) {//获取ORC结构信息TypeInfo typeInfo = TypeInfoUtils.getTypeInfoFromTypeString(type);//获取ORC结构的解析对象oi = TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(typeInfo);}/** 添加要写入的ORC数据*/public ORCWriteUtil addAttr(Object... params) {//判断一下保存数据的集合是否为空,如果为空就重新创建if (Utils.isEmpty(list)) {list = new ArrayList<Object>();}//解析参数,进行数据的添加for (Object o : params) {list.add(o);}//返回return this;}/** 将ORC数据进行hadoop序列化*/public Writable serialize() {//判断是否为空if (Utils.isEmpty(os)) {os = new OrcSerde();}//进行数据的序列化Writable result = os.serialize(list, oi);//清空保存数据的集合list = new ArrayList<Object>();return result;}}
2.HFileInputFormat:自定义输入格式化类
package com.shanhai.util;import java.io.IOException;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
import org.apache.hadoop.hbase.io.hfile.HFile.Reader;
import org.apache.hadoop.hbase.io.hfile.HFileScanner;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;public class HFileInputFormat extends FileInputFormat<ImmutableBytesWritable, KeyValue> {@Overridepublic RecordReader<ImmutableBytesWritable, KeyValue> createRecordReader(InputSplit split,TaskAttemptContext context) throws IOException, InterruptedException {return new HFileRecordReader();}/**创建自己的数据记录读取器*/private static class HFileRecordReader extends RecordReader<ImmutableBytesWritable, KeyValue>{//创建HFile读取器对象private Reader reader;//创建HFile扫描器对象private HFileScanner scanner;//获取的数据的个数private Long entryNum = 0L;;/** 进行读取器的初始化*/@Overridepublic void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {//获取HFile的数据分片对象FileSplit fs = (FileSplit)split;//获取数据分片的路径Path path = fs.getPath();//获得HFile读取器Configuration conf = context.getConfiguration();reader = HFile.createReader(FileSystem.get(conf), path, new CacheConfig(conf), conf);//获取HFile文件的元数据信息FileInfo info = (FileInfo)reader.loadFileInfo();//输出数据长度System.out.println("文件长度:"+info.size());//获取HFile扫描器scanner = reader.getScanner(false, false);//HFile扫描器归位scanner.seekTo();}/** 判断是否有下一个数据*/@Overridepublic boolean nextKeyValue() throws IOException, InterruptedException {entryNum++;return scanner.next();}/** 获取Hfile中每行记录的Rowkey,这里的一行不是指Hbase完整的一行记录,是Hfile文件中存储的行*/@SuppressWarnings("deprecation")@Overridepublic ImmutableBytesWritable getCurrentKey() throws IOException, InterruptedException {return new ImmutableBytesWritable(scanner.getKeyValue().getRow());}/** 获取Hfile中的每行记录的value,包括列名,版本和值*/@Overridepublic KeyValue getCurrentValue() throws IOException, InterruptedException {return (KeyValue)scanner.getKeyValue();}/** 获取整体的处理进度*/@Overridepublic float getProgress() throws IOException, InterruptedException {if (Utils.isNotEmpty(reader)) {return entryNum/reader.getEntries();}return 1;}/** 关闭HFile读取器*/@Overridepublic void close() throws IOException {if (Utils.isNotEmpty(reader)) {reader.close();}}}}

3.com.shanhai.entity

1.HFileItem
package com.shanhai.entity;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;import org.apache.hadoop.io.Writable;/** Hbase单元格信息的定义*/
public class HFileItem implements Writable{//定义属性private String value = "";		// HFile存储中物理行的值private Long version = -1L;		// 版本private boolean isDelete = false;	// 是否被删除public String getValue() {return value;}public void setValue(String value) {this.value = value;}public Long getVersion() {return version;}public void setVersion(Long version) {this.version = version;}public boolean isDelete() {return isDelete;}public void setDelete(boolean isDelete) {this.isDelete = isDelete;}@Overridepublic void write(DataOutput out) throws IOException {out.writeUTF(value);out.writeLong(version);out.writeBoolean(isDelete);}@Overridepublic void readFields(DataInput in) throws IOException {this.value = in.readUTF();this.version = in.readLong();this.isDelete = in.readBoolean();}}
2.HFileRecord
package com.shanhai.entity;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;import org.apache.hadoop.io.Writable;/** Hbase的实体类*/
public class HFileRecord implements Writable {//定义需要的属性//Hbase表中的国家字段private HFileItem country = new HFileItem();//Hbase表中的包名字段private HFileItem pkgname = new HFileItem();//Hbase表中的类型字段private HFileItem type = new HFileItem();//Hbase表中的包的分类,比如游戏、社交private HFileItem gpcategory = new HFileItem();public HFileItem getCountry() {return country;}public void setCountry(HFileItem country) {this.country = country;}public HFileItem getPkgname() {return pkgname;}public void setPkgname(HFileItem pkgname) {this.pkgname = pkgname;}public HFileItem getType() {return type;}public void setType(HFileItem type) {this.type = type;}public HFileItem getGpcategory() {return gpcategory;}public void setGpcategory(HFileItem gpcategory) {this.gpcategory = gpcategory;}@Overridepublic void write(DataOutput out) throws IOException {country.write(out);pkgname.write(out);type.write(out);gpcategory.write(out);}@Overridepublic void readFields(DataInput in) throws IOException {country.readFields(in);pkgname.readFields(in);type.readFields(in);gpcategory.readFields(in);}}

4.com.shanhai.mr

1.NewHbaseDateExport
package com.shanhai.mr;import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hive.ql.io.orc.OrcNewOutputFormat;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
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;import com.shanhai.entity.HFileItem;
import com.shanhai.entity.HFileRecord;
import com.shanhai.util.BaseMR;
import com.shanhai.util.HFileInputFormat;
import com.shanhai.util.MyConstant;
import com.shanhai.util.ORCFormat;
import com.shanhai.util.ORCWriteUtil;
import com.shanhai.util.Utils;public class NewHbaseDateExport extends BaseMR {public static class MyMapper extends Mapper<ImmutableBytesWritable, KeyValue, Text, HFileRecord>{//定义map需要用到的变量private Text outkey = new Text();private HFileRecord outval = null;private HFileItem item = new HFileItem();private String rowkey = "";private byte[] buffers = null;private String cn = "";private String cv = "";@Overrideprotected void map(ImmutableBytesWritable key, KeyValue value,Mapper<ImmutableBytesWritable, KeyValue, Text, HFileRecord>.Context context)throws IOException, InterruptedException {//获取rowkeyrowkey = Bytes.toString(key.get());//判断这个rowkey是否有效if (Utils.isEmpty(rowkey) && rowkey.split(MyConstant.SQE1).length != 2) {return;}//获取数据buffers = value.getBuffer();//获取列名和值cn = Bytes.toString(byteCopy(buffers, value.getQualifierOffset(), value.getQualifierLength()));cv = Bytes.toString(byteCopy(buffers, value.getValueOffset(), value.getValueLength()));//封装我们这个数据的属性item.setValue(cv);item.setVersion(value.getTimestamp());item.setDelete(value.isDelete());//判断一下我们封装的哪个数据outval = new HFileRecord();if (cn.equals("country")) {outval.setCountry(item);}else if (cn.equals("pkgname")) {outval.setPkgname(item);}else if (cn.equals("type")) {outval.setType(item);}else if (cn.equals("gpcategory")) {outval.setGpcategory(item);}//输出outkey.set(rowkey);context.write(outkey, outval);}public byte[] byteCopy(byte[] buff, int offset, int length) {byte[] copy1 = new byte[length];System.arraycopy(buff, offset, copy1, 0, length);return copy1;}}/** 将相同的key在map中进行局部聚合,获取一整行数据的部分内容*/public static class MyCombiner extends Reducer<Text, HFileRecord, Text, HFileRecord>{//创建需要的变量private HFileRecord record = null;@Overrideprotected void reduce(Text key, Iterable<HFileRecord> values,Reducer<Text, HFileRecord, Text, HFileRecord>.Context context) throws IOException, InterruptedException {//创建中间变量record = new HFileRecord();//判断这个rowkey是否有效if (Utils.isEmpty(key.toString()) && key.toString().split(MyConstant.SQE1).length != 2) {return;}//数据局部聚合for (HFileRecord r : values) {if (r.getCountry().getVersion() >= record.getCountry().getVersion()) {record.getCountry().setValue(r.getCountry().getValue());record.getCountry().setVersion(r.getCountry().getVersion());record.getCountry().setDelete(r.getCountry().isDelete());}if (r.getPkgname().getVersion() >= record.getPkgname().getVersion()) {record.getPkgname().setValue(r.getPkgname().getValue());record.getPkgname().setVersion(r.getPkgname().getVersion());record.getPkgname().setDelete(r.getPkgname().isDelete());}if (r.getType().getVersion() >= record.getType().getVersion()) {record.getType().setValue(r.getType().getValue());record.getType().setVersion(r.getType().getVersion());record.getType().setDelete(r.getType().isDelete());}if (r.getGpcategory().getVersion() >= record.getGpcategory().getVersion()) {record.getGpcategory().setValue(r.getGpcategory().getValue());record.getGpcategory().setVersion(r.getGpcategory().getVersion());record.getGpcategory().setDelete(r.getGpcategory().isDelete());}}//输出context.write(key, record);}}private static class MyReducer extends Reducer<Text, HFileRecord, NullWritable, Writable>{//定义需要用到的变量private ORCWriteUtil owu = new ORCWriteUtil();@Overrideprotected void setup(Reducer<Text, HFileRecord, NullWritable, Writable>.Context context)throws IOException, InterruptedException {owu.setOrcWriteType(ORCFormat.MY_ORC_TYPE1);}//定义需要用到的变量private HFileRecord record = null;private String[] strs = null;private String aid = "";private Long uptime = -1L;private String tmpuptime = "";private DateFormat df = new SimpleDateFormat("yyyyMMdd");private String pkgname,country,gpcategory;private Integer type;@Overrideprotected void reduce(Text key, Iterable<HFileRecord> values,Reducer<Text, HFileRecord, NullWritable, Writable>.Context context)throws IOException, InterruptedException {record = new HFileRecord();//判断这个rowkey是否有效if (Utils.isNotEmpty(key.toString()) && key.toString().split(MyConstant.SQE1).length == 2) {strs = key.toString().split(MyConstant.SQE1);aid = strs[0];tmpuptime = strs[1];try {uptime = df.parse(tmpuptime).getTime()/1000;} catch (ParseException e) {e.printStackTrace();}for (HFileRecord r : values) {if (r.getCountry().getVersion() >= record.getCountry().getVersion()) {record.getCountry().setValue(r.getCountry().getValue());record.getCountry().setVersion(r.getCountry().getVersion());record.getCountry().setDelete(r.getCountry().isDelete());}if (r.getPkgname().getVersion() >= record.getPkgname().getVersion()) {record.getPkgname().setValue(r.getPkgname().getValue());record.getPkgname().setVersion(r.getPkgname().getVersion());record.getPkgname().setDelete(r.getPkgname().isDelete());}if (r.getType().getVersion() >= record.getType().getVersion()) {record.getType().setValue(r.getType().getValue());record.getType().setVersion(r.getType().getVersion());record.getType().setDelete(r.getType().isDelete());}if (r.getGpcategory().getVersion() >= record.getGpcategory().getVersion()) {record.getGpcategory().setValue(r.getGpcategory().getValue());record.getGpcategory().setVersion(r.getGpcategory().getVersion());record.getGpcategory().setDelete(r.getGpcategory().isDelete());}//判断数据是否被删除if (record.getCountry().isDelete()&&record.getPkgname().isDelete()&&record.getType().isDelete()&&record.getGpcategory().isDelete()) {return;}//获取数据pkgname = record.getPkgname().getValue();country = record.getCountry().getValue();gpcategory = record.getGpcategory().getValue();type = Integer.parseInt(record.getType().getValue());//数据写入owu.addAttr(aid,pkgname,uptime,type,country,gpcategory);//输出context.write(NullWritable.get(), owu.serialize());}}}}@Overridepublic Job getJob(Configuration jobConf) throws Exception {Job job = Job.getInstance(jobConf, getJobNameWithTaskID());job.setJarByClass(NewHbaseDateExport.class);job.setMapperClass(MyMapper.class);job.setCombinerClass(MyCombiner.class);job.setReducerClass(MyReducer.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(HFileRecord.class);job.setOutputKeyClass(NullWritable.class);job.setOutputValueClass(Writable.class);job.setInputFormatClass(HFileInputFormat.class);job.setOutputFormatClass(OrcNewOutputFormat.class);FileInputFormat.addInputPath(job, new Path(jobConf.get(MyConstant.TASK_INPUT)));FileOutputFormat.setOutputPath(job, this.getPath(this.getJobNameWithTaskID()));return job;}@Overridepublic String getJobName() {return "new_hbase_data_export";}}

5.com.shanhai.bin

1.NHDERunner
package com.shanhai.bin;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import com.shanhai.mr.NewHbaseDateExport;
import com.shanhai.util.JobRunnerResult;
import com.shanhai.util.JobRunnerUtil;public class NHDERunner extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//创建任务工作链JobControl jobc = new JobControl("jobwork_new_hbase_data_export");//获取Hadoop的配置文件对象Configuration conf = this.getConf();//设置公共的配置文件加载对象conf,只需加载一次就可以NewHbaseDateExport.setConf(conf);	NewHbaseDateExport hde = new NewHbaseDateExport();//获取工作链的任务ControlledJob job1 = hde.getCtrlJob();//设置工作链的任务jobc.addJob(job1);//运行任务JobRunnerResult result = JobRunnerUtil.run(jobc);if (result.getIsSuccess()) {//这里可以打印Counters的信息System.out.println("JOB_STATUS : OK!");System.out.println("THE PROGRAM IS RUN " + result.getRunTime());} else {System.out.println("JOB_STATUS : FALL!");}return 0;}public static void main(String[] args) {try {System.exit(ToolRunner.run(new NHDERunner(), args));} catch (Exception e) {e.printStackTrace();}}}
2.NHDEDriver
package com.shanhai.bin;import org.apache.hadoop.util.ProgramDriver;public class NHDEDriver {public static void main(String[] args) {//创建驱动程序对象ProgramDriver driver = new ProgramDriver();try {//加载要执行的类driver.addClass("nhde", NHDERunner.class, "hbase数据导出新方案!");//反射执行ProgramDriver.class.getMethod("driver", new Class[]{String[].class}).invoke(driver, new Object[]{args});} catch (Throwable e) {e.printStackTrace();}}}

3.集群运行

1.打包项目:
打包命令:clean assembly:assembly2.上传Jar包:
[hadoop@nn1 ~]$ cd myhbase/
[hadoop@nn1 myhbase]$ ll
[hadoop@nn1 myhbase]$ rz.集群运行
hadoop jar hn16_hbase_tp7-0.0.1-SNAPSHOT-luoxichuan.jar nhde -Dmymr.task.id=luo -Dmymr.task.input=/hbase/data/myns1/user_install_status/71dc316c82245fde9f5299875f445ea6/cf1
创建外部表指定本地文件路径:
CREATE EXTERNAL TABLE `table1`(
`aid` string COMMENT 'from deserializer', 
`pkgname` string COMMENT 'from deserializer', 
`uptime` bigint COMMENT 'from deserializer', 
`type` int COMMENT 'from deserializer', 
`country` string COMMENT 'from deserializer', 
`gpcategory` string COMMENT 'from deserializer')
ROW FORMAT SERDE 
'org.apache.hadoop.hive.ql.io.orc.OrcSerde' 
STORED AS INPUTFORMAT 
'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' 
OUTPUTFORMAT 
'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION 'hdfs://ns1/user/luoxichuan/task/new_hbase_data_export_luo'
TBLPROPERTIES ('orc.compress'='SNAPPY','orc.create.index'='true');6.验证结果
select * from `table1`;7.进阶作业:
如何进行mr任务的全表扫描:
自己写个读取HDFS文件地址列表的方法,读指定hbase表下的所有存放HFILE文件的目录,这样就可以使你的mr扫描该表下所有的hfile文件,从而达到通过hfile文件进行全表扫描数据的目的

相关文章:

八、Hbase

Hbase 一、NoSQL非关系型数据库简介1.NoSQL 的起因2.NoSQL 的特点3.NoSQL 面临的挑战4.NoSQL 的分类 二、HBase数据库概述1.HBase数据库简介2.HBase数据模型简介3.HBase数据模型基本概念4.Hbase概念视图(逻辑视图)5.Hbase物理视图6.Hbase主要组件7.Hbase安装8.Hbase的数据读写流…...

ubuntu安装sublime安装与免费使用

1. ubuntu安装sublime 参考官网: Linux Package Manager Repositories 2. 破解过程 打开如下网址,打开/opt/sublime_text/sublime_text https://hexed.it/ 3. 替换在hexed打开的文件中查找并替换: 4180激活方法 使用二进制编辑器 8079 0500 0f94 c2替换为 c641 05…...

Onedrive精神分裂怎么办(有变更却不同步)

Onedrive有时候会分裂&#xff0c;你在本地删除文件&#xff0c;并没有同步到云端&#xff0c;但是本地却显示同步成功。 比如删掉了一个目录&#xff0c;在本地看已经删掉&#xff0c;onedrive显示已同步&#xff0c;但是别的电脑并不会同步到这个删除操作&#xff0c;在网页版…...

图像裁剪与批量推理:解决分割和变化检测中的大图处理问题

引言 在分割、变化检测等任务中&#xff0c;我们经常会遇到一个问题&#xff1a;模型的输入尺寸是固定且较小的&#xff08;如256256或512512&#xff09;。当需要处理分辨率较高的大图时&#xff0c;直接输入到模型中显然是不切实际的。那么&#xff0c;如何高效地解决这个问…...

第4章 函数

2024年12月25日一稿 4.1 函数的定义 4.1.1 函数和像 4.1.2 函数的性质 4.1.3 常用函数 4.2 复合函数和反函数 4.2.1 复合函数 4.2.2 反函数 4.3 特征函数与模糊子集 4.4 基数的概念 4.4.1 后继与归纳集 4.4.2 自然数&#xff0c;有穷集&#xff0c;无穷集 4.4.3 基数 4.5 可数…...

【JavaEE进阶】Spring传递请求参数

目录 &#x1f38d;序言 &#x1f334;传递单个参数 &#x1f340;传递多个参数 &#x1f384;传递对象 &#x1f333;后端参数重命名&#xff08;后端参数映射&#xff09; &#x1f6a9;ReuqestParam注解 &#x1f38d;序言 访问不同的路径,就是发送不同的请求.在发送…...

在跨平台开发环境中构建高效的C++项目:从基础到最佳实践20241225

在跨平台开发环境中构建高效的C项目&#xff1a;从基础到最佳实践 引言 在现代软件开发中&#xff0c;跨平台兼容性和高效开发流程是每个工程师追求的目标。尤其是对于 C 开发者&#xff0c;管理代码的跨平台构建以及调试流程可能成为一项棘手的挑战。在本文中&#xff0c;我…...

无人零售及开源 AI 智能名片 S2B2C 商城小程序的深度剖析

摘要&#xff1a;本文聚焦无人零售这一新兴零售模式及其发展浪潮中崛起的开源 AI 智能名片 S2B2C 商城小程序。深入阐述无人零售的发展态势&#xff0c;细致剖析其驱动因素、现存问题&#xff0c;全面详细介绍小程序的功能特性、应用优势以及对无人零售的潜在价值&#xff0c;旨…...

PCL点云库入门——PCL库点云滤波算法之直通滤波(PassThrough)和条件滤波(ConditionalRemoval)

0、滤波算法概述 PCL点云库中的滤波算法是处理点云数据不可或缺的一部分&#xff0c;它们能够有效地去除噪声、提取特征或进行数据降维。例如&#xff0c;使用体素网格滤波&#xff08;VoxelGrid&#xff09;可以减少点云数据量&#xff0c;同时保留重要的形状特征。此外&#…...

v语言介绍

V 语言是一种多用途的编程语言&#xff0c;可以用于前端开发、后端开发、系统编程、游戏开发等多个领域。它的设计哲学是提供接近 C 语言的性能&#xff0c;同时简化开发过程并提高代码的安全性和可读性。接下来我会详细介绍 V 在前后端开发中的应用&#xff0c;并给出一个具体…...

GPT-O3:简单介绍

GPT-O3&#xff1a;人工智能领域的重大突破 近日&#xff0c;OpenAI发布了其最新的AI模型GPT-O3&#xff0c;这一模型在AGI评估中取得了惊人的成绩&#xff0c;展现出强大的能力和潜力。GPT-O3的出现标志着人工智能领域的重大进步&#xff0c;预计将在2025年实现更大的突破。 …...

重温设计模式--适配器模式

文章目录 适配器模式&#xff08;Adapter Pattern&#xff09;概述适配器模式UML图适配器模式的结构目标接口&#xff08;Target&#xff09;&#xff1a;适配器&#xff08;Adapter&#xff09;&#xff1a;被适配者&#xff08;Adaptee&#xff09;&#xff1a; 作用&#xf…...

API部署大模型

由于生产测试环境的服务器配置较低 不能够支撑大模型运行的配置 所以需要将大模型封装部署在A服务器上 在B服务器上进行调用 封装时可以使用FastAPI与Websocket两种通信方式进行通信 Websocket 在A服务器端部署大模型&#xff08;服务端&#xff09; import asyncio import …...

Linux -- 同步与条件变量

目录 同步 条件变量 pthread_cond_t pthread_cond_init&#xff08;初始化条件变量&#xff09; pthread_cond_destroy&#xff08;销毁条件变量&#xff09; pthread_cond_wait&#xff08;线程等待条件变量&#xff09; 重要提醒 pthread_cond_boardcast&#xff08…...

Linux之ARM(MX6U)裸机篇----1.开发环境搭建

下载开启FTP服务 作用&#xff1a;用于电脑与linux系统之前文件传输 如上&#xff0c;编辑完成后重启 Window下FTP客户端安装使用http://www.filezilla.cn/download网址下载 新建网络连接站点 主机后写虚拟机的ip地址&#xff0c;用ifconfig查出ipv4的地址 笔记本电脑中虚拟…...

【C语言】结构体模块化编程

在模块化编程中&#xff0c;结构体作为数据存储的主要方式之一&#xff0c;它不仅用于存储数据&#xff0c;还帮助实现代码的封装与隐私保护。通过将结构体定义放在 .c 文件中并使用 get_ 和 set_ 函数进行访问&#xff0c;我们可以实现对结构体数据的保护&#xff0c;同时降低…...

SpringCloudAlibaba技术栈-Nacos

1、什么是Nacos&#xff1f; Nacos是个服务中心&#xff0c;就是你项目每个功能模块都会有个名字&#xff0c;比如支付模块,我们先给这个模块起个名字就叫paymentService,然后将这个名字和这个模块的配置放到Nacos中&#xff0c;其他模块也是这样的。好处是这样能更好地管理项…...

Windows11家庭版启动Hyper-V

Hyper-V 是微软的硬件虚拟化产品&#xff0c;允许在 Windows 上以虚拟机形式运行多个操作系统。每个虚拟机都在虚拟硬件上运行&#xff0c;可以创建虚拟硬盘驱动器、虚拟交换机等虚拟设备。使用虚拟化可以运行需要较旧版本的 Windows 或非 Windows 操作系统的软件&#xff0c;以…...

《信管通低代码信息管理系统开发平台》Linux环境安装说明

1 简介 信管通低代码信息管理系统应用平台提供多环境软件产品开发服务&#xff0c;包括单机、局域网和互联网。我们专注于适用国产硬件和操作系统应用软件开发应用。为事业单位和企业提供行业软件定制开发&#xff0c;满足其独特需求。无论是简单的应用还是复杂的系统&#xff…...

第一节:电路连接【51单片机-L298N-步进电机教程】

摘要&#xff1a;本节介绍如何搭建一个51单片机L298N步进电机控制电路&#xff0c;所用材料均为常见的模块&#xff0c;简单高效的方式搭建起硬件环境 一、硬件清单 ①51单片机模块 ②恒流模块 ③开关电源 ④L298N模块 ⑤二相四线步进电机 ⑥电线若干 二、接线 三、L298N模…...

YoloDotNet 识别图像中特定关键点的位置

文章目录 1、初始化 Yolo 对象2、加载图像与检测关键点3、处理检测结果4、自定义关键点绘制和处理5、注意事项1、初始化 Yolo 对象 设置 YoloOptions,包括模型路径、模型类型(如果有专门的关键点检测模型类型则指定)、GPU 使用相关参数等。例如: var yoloOptions = new Yo…...

山景BP1048增加AT指令,实现单片机串口控制播放音乐(一)

1、设计目的 山景提供的SDK是蓝牙音箱demo&#xff0c;用户使用ADC按键或者IR遥控器&#xff0c;进行人机交互。然而现实很多场景&#xff0c;需要和单片机通信&#xff0c;不管是ADC按键或者IR接口都不适合和单片机通信。这里设计个AT指令用来和BP1048通信。AT指令如下图所示…...

Leetcode3218. 切蛋糕的最小总开销 I

题目描述&#xff1a; 有一个 m x n 大小的矩形蛋糕&#xff0c;需要切成 1 x 1 的小块。 给你整数 m &#xff0c;n 和两个数组&#xff1a; horizontalCut 的大小为 m - 1 &#xff0c;其中 horizontalCut[i] 表示沿着水平线 i 切蛋糕的开销。verticalCut 的大小为 n - 1 …...

基于自然语言处理(NLP)的智能客服系统

基于自然语言处理&#xff08;NLP&#xff09;的智能客服系统是现代客户服务领域的一项重要技术&#xff0c;它通过模拟人类对话的方式&#xff0c;为用户提供及时、准确和个性化的服务。以下是关于基于NLP的智能客服系统的一些关键要素和功能&#xff1a; 1. 自然语言理解&am…...

RAG实战:构建基于本地大模型的智能问答系统

RAG实战&#xff1a;构建基于本地大模型的智能问答系统 引言 在当今AI快速发展的时代&#xff0c;如何构建一个既智能又可靠的问答系统是一个重要课题。本文将介绍如何使用RAG&#xff08;检索增强生成&#xff09;技术&#xff0c;结合本地大模型&#xff0c;构建一个高效的智…...

三维扫描在汽车/航空行业应用

三维扫描技术应用范围广泛&#xff0c;从小型精密零件到大型工业设备&#xff0c;都能实现快速、准确的测量。 通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维…...

基于AI IDE 打造快速化的游戏LUA脚本的生成系统

前面写了一篇关于使用AI IDE进行C安全开发的博客《使用AI IDE 助力 C 高性能安全开发&#xff01;》&#xff0c; 得到许多同学们的喜欢&#xff0c;今天我们来继续在游戏开发中扩展一下AI的能力&#xff0c;看看能不能给游戏研发团队一些启发。 在游戏研发中&#xff0c;Lua曾…...

http的访问过程或者访问页面会发生什么

1. 建立连接 客户端与服务器之间需要建立 TCP 连接&#xff0c;常用步骤如下&#xff1a; DNS解析&#xff1a;客户端将目标 URL 转换为服务器的 IP 地址。三次握手&#xff1a;TCP 协议通过三次握手建立可靠连接&#xff0c;确保双方具备通信能力。传输层连接建立&#xff1…...

Lua 函数

Lua 函数 1. 概述 Lua是一种轻量级的编程语言&#xff0c;常用于游戏开发、脚本编写和嵌入式系统。在Lua中&#xff0c;函数是一等公民&#xff0c;意味着它们可以作为变量传递&#xff0c;也可以作为参数传递给其他函数。本文将详细介绍Lua中的函数&#xff0c;包括函数的定…...

产品升级!Science子刊同款ARGs-HOST分析,get!

凌恩生物明星chanpin 抗性宏基因-宿主分析 Science子刊同款分析 数据挖掘更进一步&#xff01; 抗生素的大量使用与滥用使微生物体内编码抗生素抗性的基因在环境中选择性富集&#xff0c;致病菌通过基因突变或者水平基因转移获得抗生素抗性基因后&#xff0c;导致抗生素治疗…...

Kubernetes PV及PVC的使用

前提条件 拥有Kubernetes集群环境&#xff0c;可参考&#xff1a;Kubernetes集群搭建理解Kubernetes部署知识&#xff0c;可参考&#xff1a;使用Kubernetes部署第一个应用 、Deloyment控制器拥有NFS服务&#xff0c;可参考&#xff1a;Linux环境搭建NFS服务 概述 Persistent…...

struct udp_sock

这个struct udp_sock结构体是Linux内核网络栈中用于表示一个UDP套接字的数据结构。它继承自struct inet_sock,这意味着它包含了所有IPv4或IPv6套接字共享的基础信息和函数指针。下面是对struct udp_sock中一些关键成员的解释: struct inet_sock inet;:这是udp_sock结构体的第…...

《机器学习》数据预处理简介

目录 1. 数据清洗&#xff08;Data Cleaning&#xff09; &#xff08;1&#xff09;处理缺失值 &#xff08;2&#xff09;处理异常值 &#xff08;3&#xff09;处理重复数据 2. 数据转换&#xff08;Data Transformation&#xff09; &#xff08;1&#xff09;特征缩…...

USB接口实现CDC(usb转串口功能)

主控&#xff1a;stm32f429 PHY芯片&#xff1a;usb3320 Cubemx System Core-RCC connectivity-USB_OTG_HS Middleware and Software Packs-USB_DEVICE 时钟配置&#xff1a;根据自己使用的MCU工作频率设置 Generate Code Keil5 打开工程 usbd_cdc_if.c这个文件&…...

ubuntu 网络管理--NetworkManager

ubuntu 网络管理--NetworkManager 1 介绍2 NetworkManager 命令2 nmcli 命令显示可用的wifi AP连接wifi检查网络连接 ?? 如何删除删除网络连接查看设备状态添加一个新的以太网连接设置静态 IP 地址启用并测试连接添加新的wifi连接 3 其他命令参考 1 介绍 NetworkManager 是标…...

FLV视频封装格式详解

目录(?)[-] OverviewFile Structure The FLV headerThe FLV File BodyFLV Tag Definition FLVTAGAudio TagsVideo TagsSCRIPTDATA onMetaDatakeyframes Overview Flash Video(简称FLV),是一种流行的网络格式。目前国内外大部分视频分享网站都是采用的这种格式. File Structure…...

每天五分钟机器学习:核函数

本文重点 在学习支持向量机算法之前,我们要继续学习一些数学基础,本文我们将学习核函数的概念。当数据线性不可分的时候,此时就需要核函数出场了,它可以将低维不可分的数据映射到高维可分数据,此时就可以完成数据分类了。 核函数的定义 核函数K(x, y)定义为两个数据点x…...

Flutter开发HarmonyOS 鸿蒙App的好处、能力以及把Flutter项目打包成鸿蒙应用

Flutter开发HarmonyOS的好处&#xff1a; Flutter是谷歌公司开发的一款开源、免费的UI框架&#xff0c;可以让我们快速的在Android和iOS上构建高质量App。它最大的特点就是跨平台、以及高性能。 目前 Flutter 已经支持 iOS、Android、Web、Windows、macOS、Linux 的跨平台开发…...

4-pandas常用操作

前言 一、DataFrame修改index、columns 1.获取index df2 pd.DataFrame(np.arange(9).reshape(3,3),index[sh,cs,bj],columns[a,b,c]) df2.index 2.修改index df2.index [shanghai,changsha,beijing] df2.columns [A,B,C] # 注意赋值的顺序 3.批量修改&#xff…...

Suno Api V4模型无水印开发「综合实战开发自己的音乐网站」 —— 「Suno Api系列」第14篇

历史文章 Suno AI API接入 - 将AI音乐接入到自己的产品中&#xff0c;支持120并发任务 Suno Api V4模型无水印开发「灵感模式」 —— 「Suno Api系列」第1篇 Suno Api V4模型无水印开发「自定义模式」 —— 「Suno Api系列」第2篇 Suno Api V4模型无水印开发「AI生成歌词」…...

【0376】Postgres内核 分配 last safe MultiXactId

上一篇: 【0375】Postgres内核 XLOG 之 设置下一个待分配 MultiXactId 和 offset 文章目录 1. 最后一个安全的 MultiXactId1.1 计算 multi wrap limit1.2 计算 multi stop limit1.3 计算 multi warn limit1.4 计算 multi vacuum limit2. 初始化 MultiXactState 成员3. 完成 mu…...

大模型时代的NL2SQL初探

大模型时代的NL2SQL初探 NL2SQL的基本概念NL2SQL的实现逻辑现代NL2SQL框架与技术大语言模型&#xff08;LLM&#xff09;在NL2SQL中的应用向量数据库的作用NL2SQL的应用场景未来展望 在当今信息化时代&#xff0c;数据库已成为各行各业的数据存储核心。然而&#xff0c;直接使用…...

Linux环境下使用tomcat+nginx部署若依项目

Linux Tomcat MySQL Java 是构建动态网站系统的完美解决方案之一&#xff0c;具有免费、高 效、扩展性强且资源消耗低等优良特性。 Java Web 凭借其优秀的开发框架和良好的生态被广 泛应用于社会各行业的信息化系统构建。 本实验以若依管理系统&#xff08; http://ruo…...

京准电钟解读,NTP网络授时服务器如何提升DCS系统效率

京准电钟解读&#xff0c;NTP网络授时服务器如何提升DCS系统效率 京准电钟解读&#xff0c;NTP网络授时服务器如何提升DCS系统效率 NTP 网络授时服务器为防火墙内的网络设备、终端、服务器提供准确、可靠和安全的高精度卫星时间参考&#xff0c;可为它支持数万台支持标准的网…...

06 - Django 视图view

HttpRequest 和 HttpResponse Django中的视图主要用来接受Web请求&#xff0c;并做出响应。 视图的本质就是一个Python中的函数 视图的响应分为两大类 以Json数据形式返回(JsonResponse)以网页的形式返回 重定向到另一个网页 (HttpResponseRedirect)错误视图(4XX,5XX) (Htt…...

MySQL数据库(锁)

1、MySQL有哪些锁&#xff1f; 全局锁&#xff1a;flush tables with read lock 执行以下语句之后&#xff0c;使用全局锁&#xff0c;整个数据库就处于只读状态了&#xff0c;这时其他线程执行对数据的增删改或者对表结构的更改操作操作&#xff0c;都会被阻塞。 全局锁的应…...

Mac Android studio 升级LadyBug 版本,所产生的bug

当Build 出现&#xff0c;这样的文字以后&#xff1a; Your build is currently configured to use incompatible Java 21.0.3 and Gradle 7.3.3. Cannot sync the project. We recommend upgrading to Gradle version 8.9. The minimum compatible Gradle version is 8.5. …...

springboot/ssm社区助老志愿者服务平台Java代码编写web志愿捐赠活动项目

springboot/ssm社区助老志愿者服务平台Java代码编写web志愿捐赠活动项目 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&am…...

基于Java+Jsp Servlet Mysql实现的Java Web在线商城项目系统设计与实现

一、前言介绍&#xff1a; 1.1 项目摘要 随着互联网技术的飞速发展&#xff0c;电子商务已成为现代商业活动的重要组成部分。在线商城作为电子商务的一种重要形式&#xff0c;以其便捷性、高效性和广泛覆盖性&#xff0c;受到了越来越多消费者的青睐。同时&#xff0c;随着消…...

安装K8s集群

文章首发于我的博客 &#xff1a;https://blog.liuzijian.com/post/9aa6d426-a01c-05b0-6f7a-5da4343f0f9e.html 因阿里云加速服务调整&#xff0c;镜像加速服务自2024年7月起不再支持&#xff0c;拉取镜像&#xff0c;下载网络插件等操作&#xff0c;需要科学上网访问DockerHu…...