1.Hive是数据仓库,Hive是基于Hdfs强大的存储能力,保证了可存储的数据量非常大,数据存储的文件为普通的文件;
2.Hive的运算是基于mapreduce运算模型,可对仓库中的数据进行查询;
3.查询速度比较慢,适用于数据清洗,数据分析等,不适用于联机事务处理(联机事务处理(OLTP)是指利用计算机网络,将分布于不同地理位置的业务处理计算机设备或网络与业务管理中心网络连接,以便于在任何一个网络节点上都可以进行统一、实时的业务处理活动或客户服务。);
1.mysql数据库依赖于本地文件系统,数据存储文件不是普通的文件,而是通过精心设计的文件,每条记录都具有索引,查询速度非常快,适用于联机事务处理。
2.HBase为nosql数据库,是基于hdfs文件系统,存储容量很大,数据存储文件是经过设计的文件,虽然查询数据需要通过网络传输,但查询速度依然很快,适用于联机事务处理。
概念特性 :HBASE是一个数据库----可以提供数据的实时随机读写。
HBASE与mysql、oralce、db2、sqlserver等关系型数据库不同,它是一个NoSQL数据库(非关系型数据库)。
1.Hbase的表模型与关系型数据库的表模型不同:
2.Hbase的表模型中有:行的概念;但没有字段的概念
3.Hbase的表中每行存储的都是一些key-value对
4.Hbase的表中有列族的划分,用户可以指定将哪些kv插入哪个列族(base_info,extra_info)
5.Hbase的表在物理存储上,是按照列族来分割的,不同列族的数据一定存储在不同的文件中
6.Hbase的表中的每一行都固定有一个行键,而且每一行的行键在表中不能重复
7.Hbase中的数据,包含行键,包含key,包含value,都是byte[ ]类型,hbase不负责为用户维护数据类型
8.HBASE对事务的支持很差
9.行中存的都是key-value对,每行中的key-value对中的key可以是各种各样,每行中的key-value对的数量也可以是各种各样
Hbase的表数据存储在HDFS文件系统中,从而hbase具备如下特性:存储容量可以线性扩展; 数据存储的安全性可靠性极高!
其中有一个管理角色: HMaster(一般2台,一台active,一台backup)
其他的数据节点角色: HRegionServer(很多台,看数据容量)
安装准备:
首先,要有一个HDFS集群,并正常运行; regionserver应该跟hdfs中的datanode在一起
其次,还需要一个zookeeper集群,并正常运行
然后,安装HBASE
角色分配如下:
Hdp01: namenode datanode regionserver hmaster zookeeper
Hdp02: datanode regionserver zookeeper
Hdp03: datanode regionserver zookeeper
参考:https://blog.csdn.net/wuliu_forever/article/details/87966901
1.解压hbase安装包:tar -zxvf hbase-1.2.1-bin.tar.gz -C apps/
2.修改conf/hbase-env.sh
export JAVA_HOME=/root/apps/jdk
export HBASE_MANAGES_ZK=false
3.修改conf/hbase-site.xml
<configuration>
<property>
<name>hbase.rootdirname>
<value>hdfs://n1:9000/hbasevalue>
property>
<property>
<name>hbase.cluster.distributedname>
<value>truevalue>
property>
<property>
<name>hbase.zookeeper.quorumname>
<value>n1:2181,n2:2181,n3:2181value>
property>
configuration>
4.修改 conf/regionservers
n1
n2
n3
5.启动hbase集群:
bin/start-hbase.sh
启动完后,还可以在集群中找任意一台机器启动一个备用的master
bin/hbase-daemon.sh start master
新启的这个master会处于backup状态
6.启动hbase的命令行客户端
bin/hbase shell
Hbase> list // 查看表
Hbase> status // 查看集群状态
Hbase> version // 查看集群版本
7.浏览器查看hbase
n1:16010
1.管理HRegionServer,实现其负载均衡。
2.管理和分配HRegion,比如在HRegion split时分配新的HRegion;在HRegionServer退出时迁移其负责的HRegion到其他HRegionServer上。
创建、删除、修改Table的定义。实现DDL操作(namespace和table的增删改,column familiy的增删改等)。
1.管理namespace和table的元数据(实际存储在HDFS上)。
2.权限控制(ACL)。
3.监控集群中所有HRegionServer的状态(通过Heartbeat和监听ZooKeeper中的状态)。
1.管理自己所负责的region数据的读写。
2.读写HDFS,管理Table中的数据。
3.Client直接通过HRegionServer读写数据(从HMaster中获取元数据,找到RowKey所在的HRegion/HRegionServer后)。
1、一个表,有表名
2、一个表可以分为多个列族(不同列族的数据会存储在不同文件中)
3、表中的每一行有一个“行键rowkey”,而且行键在表中不能重复
4、表中的每一对kv数据称作一个cell
5、hbase可以对数据存储多个历史版本(历史版本数量可配置)
6、整张表由于数据量过大,会被横向切分成若干个region(用rowkey范围标识),不同region的数据也存储在不同文件中
7、hbase会对插入的数据按顺序存储:
hbase中只支持byte[]
此处的byte[] 包括了: rowkey,key,value,列族名,表名
create ‘t_user_info’,‘base_info’,‘extra_info’
表名 列族名 列族名
put ‘t_user_info’,‘001’,‘base_info:username’,‘zhangsan’
put ‘t_user_info’,‘001’,‘base_info:age’,‘18’
put ‘t_user_info’,‘001’,‘base_info:sex’,‘female’
put ‘t_user_info’,‘001’,‘extra_info:career’,‘it’
put ‘t_user_info’,‘002’,‘extra_info:career’,‘actoress’
put ‘t_user_info’,‘002’,‘base_info:username’,‘liuyifei’
delete ‘t_user_info’,‘001’,‘base_info:sex’
删除整行数据:
deleteall ‘t_user_info’,‘001’
注意:将表删除前必须distable 表。
disable ‘t_user_info’
drop ‘t_user_info’
插入到hbase中去的数据,hbase会自动排序存储:
排序规则: 首先看行键,然后看列族名,然后看列(key)名; 按字典顺序
Hbase的这个特性跟查询效率有极大的关系
比如:一张用来存储用户信息的表,有名字,户籍,年龄,职业…等信息
然后,在业务系统中经常需要:
查询某个省的所有用户
经常需要查询某个省的指定姓的所有用户
思路:如果能将相同省的用户在hbase的存储文件中连续存储,并且能将相同省中相同姓的用户连续存储,那么,上述两个查询需求的效率就会提高。
做法:将查询条件拼到rowkey内
原理:(以网络爬虫为例)
1.将获取到的URL通过特定的算法计算,得到8个bit和索引角标,对应在64K(长度可以更长)的二进制数组中的8个索引上。
2.如果指定索引出现任意一个bit的数值为0,说明该URL没有被爬到,将改索引处的bit值更换为1。
3.如果指定索引处所有的值均为1,说明该URL已经被爬到。
作用:布隆过滤器对没有被保存的资源判断是准确的。对已经保存的资源做出的判断不是百分百准确(准确率与二进制数组的长度是有关系的)。
package com.initialize;
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.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
/**
*
* 1、构建连接
* 2、从连接中取到一个表DDL操作工具admin
* 3、admin.createTable(表描述对象);
* 4、admin.disableTable(表名);
5、admin.deleteTable(表名);
6、admin.modifyTable(表名,表描述对象);
*
* @author hunter.d
*
*/
public class HbaseClientDemo {
Connection conn = null;
@Before
public void getConn() throws IOException {
//构建一个连接对象
Configuration conf = HBaseConfiguration.create();//会自动加载hbase-site.xml
conf.set("hbase.zookeeper.quorum","n1:2181,n2:2181,n3:2181");
conn = ConnectionFactory.createConnection(conf);
}
/**
* DDL
* 创建表
*/
@Test
public void testCreateTable() throws Exception{
//从连接中构造一个DDL操作器
Admin admin = conn.getAdmin();
//创建一个标定义描述对象
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("user_info"));
//创建列族定义描述对象
HColumnDescriptor hColumnDescriptor_1 = new HColumnDescriptor("base_info");
hColumnDescriptor_1.setMaxVersions(3);
HColumnDescriptor hColumnDescriptor_2 = new HColumnDescriptor("extra_info");
//将列族定义信息对象放入表定义对象中
hTableDescriptor.addFamily(hColumnDescriptor_1);
hTableDescriptor.addFamily(hColumnDescriptor_2);
//用ddl操作器对象:admin来创建表
admin.createTable(hTableDescriptor);
//关闭连接
admin.close();
conn.close();
}
/**
* 删除表
*/
@Test
public void testDropTable() throws Exception{
Admin admin = conn.getAdmin();
//停用表
admin.disableTable(TableName.valueOf("user_info"));
//删除表
admin.deleteTable(TableName.valueOf("user_info"));
admin.close();
conn.close();
}
/**
* 修改表定义--添加一个列族
*/
@Test
public void testAlterTable() throws Exception{
Admin admin = conn.getAdmin();
//取出旧的表定义信息
HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("user_info"));
//新构造一个列族定义
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("other_info");
hColumnDescriptor.setBloomFilterType(BloomType.ROWCOL);//设置该列族的布隆过滤器类型
//将列族定义添加到表定义对象中
tableDescriptor.addFamily(hColumnDescriptor);
//将修改过的表定义交给admin去提交
admin.modifyTable(TableName.valueOf("user_info"), tableDescriptor);
admin.close();
conn.close();
}
}
package com.initialize;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
public class HbaseClientDML {
Connection conn = null;
@Before
public void getConn() throws IOException {
//构建一个连接对象
Configuration conf = HBaseConfiguration.create();//会自动加载hbase-site.xml
conf.set("hbase.zookeeper.quorum","n1:2181,n2:2181,n3:2181");
conn = ConnectionFactory.createConnection(conf);
}
/**
* 增,改:put来覆盖
*/
@Test
public void testPut() throws Exception{
//获取一个操作指定表的table对象,进行DML操作
Table table = conn.getTable(TableName.valueOf("user_info"));
//构造要插入的数据为一个Put类型(一个put对象只能对应一个rowkey)的对象
Put put = new Put(Bytes.toBytes("001"));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"),Bytes.toBytes("张三"));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("18"));
put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));
Put put2 = new Put(Bytes.toBytes("002"));
put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("李四"));
put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("28"));
put2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("上海"));
ArrayList<Put> puts = new ArrayList<>();
puts.add(put);
puts.add(put2);
//插进去
table.put(puts);
table.close();
conn.close();
}
/***
* 循环插入大量数据
*/
@Test
public void testManyPuts() throws Exception{
Table table = conn.getTable(TableName.valueOf("user_info"));
ArrayList<Put> puts = new ArrayList<>();
for(int i=0;i<10000;i++){
Put put = new Put(Bytes.toBytes(""+i));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("usernaem"), Bytes.toBytes("张三" +i));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes((18+i) + ""));
put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));
puts.add(put);
}
table.put(puts);
}
/**
* 删
*/
@Test
public void testDelete() throws Exception{
Table table = conn.getTable(TableName.valueOf("user_info"));
//构造一个对象封装要删除的数据信息
Delete delete1 = new Delete(Bytes.toBytes("001"));
Delete delete2 = new Delete(Bytes.toBytes("002"));
delete2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"));
ArrayList<Delete> dels = new ArrayList<>();
dels.add(delete1);
dels.add(delete2);
table.delete(dels);
table.close();
conn.close();
}
/**
* 查
*/
@Test
public void testGet() throws Exception{
Table table = conn.getTable(TableName.valueOf("user_info"));
Get get = new Get("002".getBytes());
Result result = table.get(get);
//从结果中取用户指定的某个key和value的值
byte[] value = result.getValue("base_info".getBytes(), "age".getBytes());
System.out.println(new String(value));
System.out.println("======================");
//遍历整行结果中的所有kv单元格
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell cell = cellScanner.current();
byte[] rowArray = cell.getRowArray();//本kv所属行键的字节数组
byte[] familyArray = cell.getFamilyArray();//列族名的字节数组
byte[] qualifierArray = cell.getQualifierArray();//列明的字节数组
byte[] valueArray = cell.getValueArray();//value字节数组
System.out.println("行键:" + new String(rowArray, cell.getRowOffset(), cell.getRowLength()));
System.out.println("列族名:" + new String(familyArray, cell.getFamilyOffset(), cell.getFamilyLength()));
System.out.println("列名:" + new String(qualifierArray, cell.getQualifierOffset(), cell.getQualifierLength()));
System.out.println("value:" + new String(valueArray, cell.getValueOffset(), cell.getValueLength()));
}
table.close();
conn.close();
}
/**
* 按行键范围查询数据
*/
@Test
public void testScan() throws Exception{
Table table = conn.getTable(TableName.valueOf("user_info"));
//包含起始行键,不包含结束行键,但是如果真的是想要查询出末尾的那个行键,可以在尾行键上拼接一个不可见的字符(\000)
Scan scan = new Scan("10".getBytes(), "10000\001".getBytes());
ResultScanner scanner =table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
while(iterator.hasNext()){
Result result =iterator.next();
//遍历整行结果中的所有kv单元格
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell cell = cellScanner.current();
byte[] rowArray = cell.getRowArray();//本kv所属行键的字节数组
byte[] familyArray = cell.getFamilyArray();//列族名的字节数组
byte[] qualifierArray = cell.getQualifierArray();//列明的字节数组
byte[] valueArray = cell.getValueArray();//value字节数组
System.out.println("行键:" + new String(rowArray, cell.getRowOffset(), cell.getRowLength()));
System.out.println("列族名:" + new String(familyArray, cell.getFamilyOffset(), cell.getFamilyLength()));
System.out.println("列名:" + new String(qualifierArray, cell.getQualifierOffset(), cell.getQualifierLength()));
System.out.println("value:" + new String(valueArray, cell.getValueOffset(), cell.getValueLength()));
}
System.out.println("----------------------");
}
}
@Test
public void test(){
String a = "000";
String b = "000\0";
System.out.println(a);
System.out.println(b);
byte[] bytes = a.getBytes();
byte[] bytes2 = b.getBytes();
System.out.println("");
}
}