天天看点

Hadoop学习笔记(四):HBase

hbase是在一个hdfs上开发的面向列的分布式数据库。hbase不是关系型数据库,不支持sql。

htable一些基本概念

row key

行主键, hbase不支持条件查询和order by等查询,读取记录只能按row key(及其range)或全表扫描,因此row key需要根据业务来设计以利用其存储排序特性(table按row key字典序排序如1,10,100,11,2)提高性能。

column family(列族)

在表创建时声明,每个column family为一个存储单元。在上例中设计了一个hbase表blog,该表有两个列族:article和author。

column(列)

hbase的每个列都属于一个列族,以列族名为前缀,如列article:title和article:content属于article列族,author:name和author:nickname属于author列族。

column不用创建表时定义即可以动态新增,同一column family的columns会群聚在一个存储单元上,并依column key排序,因此设计时应将具有相同i/o特性的column设计在一个column family上以提高性能。

timestamp

hbase通过row和column确定一份数据,这份数据的值可能有多个版本,不同版本的值按照时间倒序排序,即最新的数据排在最前面,查询时默认返回最新版本。如上例中row key=1的author:nickname值有两个版本,分别为1317180070811对应的“一叶渡江”和1317180718830对应的“yedu”(对应到实际业务可以理解为在某时刻修改了nickname为yedu,但旧值仍然存在)。timestamp默认为系统当前时间(精确到毫秒),也可以在写入数据时指定该值。

value

每个值通过4个键唯一索引,tablename+rowkey+columnkey+timestamp=>value,例如上例中{tablename=’blog’,rowkey=’1’,columnname=’author:nickname’,timestamp=’ 1317180718830’}索引到的唯一值是“yedu”。

存储类型

tablename 是字符串

rowkey 和 columnname 是二进制值(java 类型 byte[])

timestamp 是一个 64 位整数(java 类型 long)

value 是一个字节数组(java类型 byte[])。

shell操作

  hbase提供了丰富的访问接口,其中hbase shell是常用的便捷方式。

     • hbase shell

     • java clietn api

     • jython、groovy dsl、scala

     • rest

     • thrift(ruby、python、perl、c++…)

     • mapreduce

     • hive/pig

   创建表

<code>&gt; create 'test','data1','data2'</code>

   column family是schema的一部分,而column不是。这里的data1和data2是column family。

   增加记录

<code>&gt;put 'test','1','data1:name','luc' &gt;put 'test','1','data1:age','24' &gt;put 'test','1','data2:height','170cm' &gt;put 'test','1','data2:weight','65kg' &gt;put 'test','1','data1:nickname','vichao'</code>

 column完全动态扩展,每行可以有不同的columns。(ps:好像有点胖啊,要减肥~~)

   根据rowkey查询

<code>&gt; get 'test','1'</code>

htable按rowkey字典序(1,10,100,11,2)自动排序,每行包含任意数量的columns,columns按columnkey(data1:age,data1:name,data1:nickname,data2:height,data2:weight)自动排序。

   更新操作

查询值:

<code>&gt; </code>get 'test','1','data1:nickname'

更新nickname为'vic':

<code>&gt; </code>put 'test','1','data1:nickname','vic'

查询更新后的结果:(返回的将是vic)

<code>&gt; get ‘blog’,’1’,’data1:nickname’</code>

知识点回顾:查询默认返回最近的值。

查询nickname的多个(本示例为2个)版本值

<code>&gt; get 'test','1',{column =&gt; 'data1:nickname',versions =&gt; 2}</code>

知识点回顾:每个column可以有任意数量的values,按timestamp倒序自动排序。

如何只查询到以前的旧版本呢,需要借助timestamp

<code>&gt;</code>get 'test','1',{column=&gt;'data1:nickname',timestamp=&gt;1373707746997}

知识点回顾:tabelname+rowkey+column+timestamp=&gt;value

  删除记录

delete只能删除一个column

<code>&gt;delete 'test','1','data1:nickname'</code>

删除rowkey的所有column用deleteall

<code>&gt;deleteall 'test','1'</code>

   删除表

练习完毕,把练习表删了吧,删除之前需要先disable

<code>&gt;disable 'test' &gt;drop 'test'</code>

java api操作

    javaapi操作还是比较简单的,各种api类和api函数,直接上代码了

      这里要注意的一点是连接到hbase需要将将hbase环境的hbase-site.xml文件引入到工程中,就像jdbc的数据库连接一样,不然是连不上hbase滴。

hbase mapreduce操作

     直接上代码了:

 优化

       针对行的键按数据排列的次序进行随机处理;

       每个任务只实例化一个htable对象;

       htable.put(put)执行put操作时不使用任何缓冲。可以通过使用htable.setautoflush(false),设置禁用自动刷入,并设置写缓冲大小,同时在任务的最后设置htable.flushcommits()或者htable.close(),以确保缓冲中最后没有剩下的未刷入的数据;

       设计行键的时候要多加考虑,可以使用复合键,如果键是整数,则应该使用二进制形式以节省存储空间;

hbase和rdbms的比较

       hbase:       

       hbase是一个分布式的面向列的数据存储系统;

       hbase表可以很高和很宽(数十亿行,数百万列);

       水平分区并在数千个商用机节点上自动复制;

       表的模式是物理存储的直接反映;

       不支持sql;

       不需要强一致性和参照完整性;

       不支持索引;行是顺序存储的,每行中的列也是,不存在索引膨胀的问题,插入性能和表的大小无关

      事务好像仅仅支持针对某一行的一系列put/delete操作。不同行、不同表间的操作是无法放在一个事务中的;

       hbase不支持条件查询和order by等查询,读取记录只能按row key(及其range)或全表扫描;

      没有内置对连接操作的支持,但是由于表的宽度可以很大,一个宽行可以容下一个主键相关的所有数据,并不需要使用连接;

       rdbms:

       支持sql;

       需要强一致性和参照完整性;

       支持事务,索引等;

hbase的特性

      没有索引,行是顺序存储的,每行中的列也是,不存在索引膨胀的问题,插入性能和表的大小无关;

      自动分区,在表增长的时候,表会自动分裂成区域,并分布到可用的节点上;

      线性扩展和对于新节点的自动处理,增加一个节点,把它指向现有的集群,并运行regionserver,区域会自动重新进行平衡,负载会均匀分布;

      普通商用硬件支持;

      容错,大量节点意味着每个节点的重要性并不突出,不用担心单个节点失效;

      批处理,支持mapreduce操作,可以用全并行的分布式作业来处理数据;