关系型数据库
ID | UserName | Password |
---|---|---|
1 | Tom | 123456 |
2 | Mike | 123456 |
列式数据库
RowKey | Column Family |
---|---|
rk_id | cf:col1=1 cf:col2=2 |
rk_username | cf:name1=Tom cf:name2=Mike |
rk_pwd | cf:pwd1=123456 cf:pwd2=123456 |
分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。
一致性(所有节点在同一时间具有相同的数据)
可用性(保证每个请求不管成功或失败都有响应,但不保证获取的数据的正确性)
分区容错性(系统中任意信息的丢失或失败不会影响系统的运行,系统如果不能在某个时限内达成数据一致性,就必须在上面两个操作之间做出选择)
NameSpace: 关系型数据库的"数据库"(database)
表(table):用于存储管理数据,具有稀疏的、面向列的特点。HBase中的每一张表,就是所谓的大表(Bigtable),可以有上亿行,上百万列。对于为值为空的列,并不占用存储空间,因此表可以设计的非常稀疏。
行(Row):在表里面,每一行代表着一个数据对象,每一行都是以一个行键(Row Key)来进行唯一标识的, 行键并没有什么特定的数据类型, 以二进制的字节来存储
列(Column): HBase的列由 Column family 和 Column qualifier 组成, 由冒号: 进行行间隔, 如 family: qualifier
行键(RowKey):类似于MySQL中的主键,HBase根据行键来快速检索数据,一个行键对应一条记录。与MySQL主键不同的是,HBase的行键是天然固有的,每一行数据都存在行键。
列族(ColumnFamily):是列的集合。列族在表定义时需要指定,而列在插入数据时动态指定。列中的数据都是以二进制形式存在,没有数据类型。在物理存储结构上,每个表中的每个列族单独以一个文件存储。一个表可以有多个列簇。
列修饰符(Column Qualifier) : 列族中的数据通过列标识来进行映射, 可以理解为一个键值对(key-value), 列修饰符(Column Qualifier) 就是key 对应关系型数据库的列
时间戳(TimeStamp):是列的一个属性,是一个64位整数。由行键和列确定的单元格,可以存储多个数据,每个数据含有时间戳属性,数据具有版本特性。可根据版本(VERSIONS)或时间戳来指定查询历史版本数据,如果都不指定,则默认返回最新版本的数据。
区域(Region):HBase自动把表水平划分成的多个区域,划分的区域随着数据的增大而增多。
HBase | 关系型数据库 | |
---|---|---|
数据库大小 | PB级别 | GB TB |
数据类型 | Bytes | 丰富的数据类型 |
事务支持 | ACID只支持单个Row级别 | 全面的ACID支持, 对Row和表 |
索引 | 只支持Row-key | 支持 |
吞吐量 | 百万写入/秒 | 数千写入/秒 |
ID | FILE NAME | FILE PATH | FILE TYPE | FILE SIZE | CREATOR |
---|---|---|---|---|---|
1 | file1.txt | /home | txt | 1024 | tom |
2 | file2.txt | /home/pics | jpg | 5032 | jerry |
RowKey | FILE INFO | SAVE INFO |
---|---|---|
1 | name:file1.txt type:txt size:1024 | path:/home/pics creator:Jerry |
2 | name:file2.jpg type:jpg size:5032 | path:/home creator:Tom |
下载安装包 http://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.7.0.tar.gz
配置伪分布式环境
环境变量配置
export HBASE_HOME=/usr/local/development/hbase-1.2.4
export PATH=$HBASE_HOME/bin:$PATH
配置hbase-env.sh
export JAVA_HOME=/usr/local/development/jdk1.7.0_15
export HBASE_MANAGES_ZK=false --如果你是使用hbase自带的zk就是true,如果使用自己的zk就是false
配置hbase-site.xml
<property>
<name>hbase.rootdirname> --hbase持久保存的目录
<value>hdfs://hadoop001:8020/opt/hbasevalue>
property>
<property>
<name>hbase.cluster.distributedname> --是否是分布式
<value>truevalue>
property>
<property>
<name>hbase.zookeeper.property.clientPortname> --指定要连接zk的端口
<value>2181value>
property>
<property>
<name>hbase.zookeeper.property.dataDirname> <value>/home/hadoop/app/hbase/zkDatavalue>
property>
启动hbase(启动的hbase的时候要保证hadoop集群已经启动)
/hbase/bin/start-hbase.sh
输入hbase shell(进入shell命令行)
可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。
角色功能:
HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据。
作用:
名称 | 命令表达式 |
---|---|
创建表 | create '表名', '列族名1','列族名2','列族名n' |
添加记录 | put '表名','行名','列名:','值 |
查看记录 | get '表名','行名' |
查看表中的记录总数 | count '表名' |
删除记录 | delete '表名', '行名','列名' |
删除一张表 | 第一步 disable '表名' 第二步 drop '表名' |
查看所有记录 | scan "表名称" |
查看指定表指定列所有数据 | scan '表名' ,{COLUMNS=>'列族名:列名'} |
更新记录 | 重写覆盖 |
hbase shell
create 'user','base_info'
disable 'user'
drop 'user'
create_namespace 'test'
list_namespace
create 'test:user','base_info'
list_namespace_tables 'test'
put 'user','rowkey_10','base_info:username','Tom'
put 'user','rowkey_10','base_info:birthday','2014-07-10'
put 'user','rowkey_10','base_info:sex','1'
put 'user','rowkey_10','base_info:address','Tokyo'
put 'user','rowkey_16','base_info:username','Mike'
put 'user','rowkey_16','base_info:birthday','2014-07-10'
put 'user','rowkey_16','base_info:sex','1'
put 'user','rowkey_16','base_info:address','beijing'
put 'user','rowkey_22','base_info:username','Jerry'
put 'user','rowkey_22','base_info:birthday','2014-07-10'
put 'user','rowkey_22','base_info:sex','1'
put 'user','rowkey_22','base_info:address','Newyork'
put 'user','rowkey_24','base_info:username','Nico'
put 'user','rowkey_24','base_info:birthday','2014-07-10'
put 'user','rowkey_24','base_info:sex','1'
put 'user','rowkey_24','base_info:address','shanghai'
put 'user','rowkey_25','base_info:username','Rose'
put 'user','rowkey_25','base_info:birthday','2014-07-10'
put 'user','rowkey_25','base_info:sex','1'
put 'user','rowkey_25','base_info:address','Soul'
scan 'user'
get 'user','rowkey_16'
get 'user','rowkey_16','base_info'
get 'user','rowkey_16','base_info:username'
get 'user', 'rowkey_16', {COLUMN => ['base_info:username','base_info:sex']}
delete 'user', 'rowkey_16', 'base_info:username'
truncate 'user'
alter 'user', NAME => 'f2'
alter 'user', 'delete' => 'f2'
可以通过HbaseUi界面查看表的信息
端口60010打不开的情况,是因为hbase 1.0 以后的版本,需要自己手动配置,在文件 hbase-site
hbase.master.info.port
60010
设计HBase表时需要注意的特点
如何设计HBase表
DDI 目的是为了克服HBase架构上的缺陷(join繁琐 只有row key索引等)
设计表保存应用中用户互粉的信息
设计1:
设计2
设计3
最终设计(DDI)
案例总结
HBase 用于在线业务服务, 不适合做统计分析
Hive 适合数据分析 统计
CDH5之前需要配置 CDH5之后不需要配置
Hive 表与HBase表之间需要建立映射关系
CREATE TABLE hbase_table_1(key int, value string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping"=":key,cf1:val") TBLPROPERTIES("hbase.table.name"="xyz");
不支持load data导入数据, 要用insert 方式创建新表加载数据
load data local inpath '/home/1.txt' overwrite into table a;
insert overwrite tabale hbase_a select * from a;
hive on HBase实战
CREATE TABLE student
(no string,
classno string,
stuno string,
score int
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES
("hbase.columns.mapping" = ":key,stuinfo:classno,stuinfo:stuno,stuinfo:score")
TBLPROPERTIES ("hbase.table.name"="student");
insert overwrite table student
select reverse(classno) as key,classno,stuno,score from student1;
hive on HBase使用场景
什么是HappyBase
HappyBase 是FaceBook员工开发的操作HBase的python库, 其基于Python Thrift, 但使用方式比Thrift简单, 已被广泛应用
启动hbase thrift server : hbase-daemon.sh start thrift
安装happy base
使用happy base时可能出现的问题(windows系统)
如何使用HappyBase
import happybase
connection = happybase.Connection('somehost')
Connection.open()
:connection = happybase.Connection('somehost', autoconnect=False)
# before first use:
connection.open()
Connection
这个类提供了一个与HBase交互的入口, 比如获取HBase中所有的表: Connection.tables()
:print(connection.tables())
connection.create_table('users',{'cf1': dict()})
创建表之后可以传入表名获取到Table类的实例:
table = connection.table('mytable')
查询操作
# api
table.scan() #全表查询
table.row(row_keys[0]) # 查询一行
table.rows(row_keys) # 查询多行
#封装函数
def show_rows(table, row_keys=None):
if row_keys:
print('show value of row named %s' % row_keys)
if len(row_keys) == 1:
print(table.row(row_keys[0]))
else:
print(table.rows(row_keys))
else:
print('show all row values of table named %s' % table.name)
for key, value in table.scan():
print(key, value)
#api
table.put(row_key, {cf:cq:value})
def put_row(table, column_family, row_key, value):
print('insert one row to hbase')
#put 'user','rowkey_10','base_info:username','Tom'
#{'cf:cq':’数据‘}
table.put(row_key, {'%s:name' % column_family:'name_%s' % value})
def put_rows(table, column_family, row_lines=30):
print('insert rows to hbase now')
for i in range(row_lines):
put_row(table, column_family, 'row_%s' % i, i)
#api
table.delete(row_key, cf_list)
#函数封装
def delete_row(table, row_key, column_family=None, keys=None):
if keys:
print('delete keys:%s from row_key:%s' % (keys, row_key))
key_list = ['%s:%s' % (column_family, key) for key in keys]
table.delete(row_key, key_list)
else:
print('delete row(column_family:) from hbase')
table.delete(row_key)
#api
conn.delete_table(table_name, True)
#函数封装
def delete_table(table_name):
pretty_print('delete table %s now.' % table_name)
conn.delete_table(table_name, True)
import happybase
hostname = ‘192.168.199.188’
table_name = ‘users’
column_family = ‘cf’
row_key = ‘row_1’
conn = happybase.Connection(hostname)
def show_tables():
print(‘show all tables now’)
tables = conn.tables()
for t in tables:
print t
def create_table(table_name, column_family):
print(‘create table %s’ % table_name)
conn.create_table(table_name, {column_family:dict()})
def show_rows(table, row_keys=None):
if row_keys:
print(‘show value of row named %s’ % row_keys)
if len(row_keys) == 1:
print table.row(row_keys[0])
else:
print table.rows(row_keys)
else:
print(‘show all row values of table named %s’ % table.name)
for key, value in table.scan():
print key, value
def put_row(table, column_family, row_key, value):
print(‘insert one row to hbase’)
table.put(row_key, {‘%s:name’ % column_family:‘name_%s’ % value})
def put_rows(table, column_family, row_lines=30):
print(‘insert rows to hbase now’)
for i in range(row_lines):
put_row(table, column_family, ‘row_%s’ % i, i)
def delete_row(table, row_key, column_family=None, keys=None):
if keys:
print(‘delete keys:%s from row_key:%s’ % (keys, row_key))
key_list = [‘%s:%s’ % (column_family, key) for key in keys]
table.delete(row_key, key_list)
else:
print(‘delete row(column_family:) from hbase’)
table.delete(row_key)
def delete_table(table_name):
pretty_print(‘delete table %s now.’ % table_name)
conn.delete_table(table_name, True)
def pool():
pretty_print(‘test pool connection now.’)
pool = happybase.ConnectionPool(size=3, host=hostname)
with pool.connection() as connection:
print connection.tables()
def main():
# show_tables()
# create_table(table_name, column_family)
# show_tables()
table = conn.table(table_name)
show_rows(table)
put_rows(table, column_family)
show_rows(table)
#
# # 更新操作
# put_row(table, column_family, row_key, 'xiaoh.me')
# show_rows(table, [row_key])
#
# # 删除数据
# delete_row(table, row_key)
# show_rows(table, [row_key])
#
# delete_row(table, row_key, column_family, ['name'])
# show_rows(table, [row_key])
#
# counter(table, row_key, column_family)
#
# delete_table(table_name)
if name == “main”:
main()
### 4.2 HappyBase案例
- 用户行为分析案例 通过HBase记录用户行为
- 建表
```sql
create 'user_profile','action'
```
- 表说明
- user_X 作为rowkey
- 对某件物品(用kwXXXXX关键词表示)做了什么操作作为cq,比如
- s search
- c click
- a add to shopping cart
- o order
- p pay
- 录入数据
```sql
put 'user_profile', 'user1', 'action:s','kw1'
put 'user_profile', 'user1', 'action:s','kw188'
put 'user_profile', 'user1', 'action:s','kw123'
put 'user_profile', 'user1', 'action:s','kw2'
put 'user_profile', 'user1', 'action:c','kw288'
put 'user_profile', 'user1', 'action:s','kw222'
put 'user_profile', 'user1', 'action:o','kw1'
class HBaseManager:
config = {
'BATCH_SIZE':1000
}
def __init__(self, host='localhost',port=9090, namespace='default', table_name=''):
""" Connect to HBase server.
This will use the host, namespace, table name, and batch size as defined in
the global variables above.
"""
self.conn = happybase.Connection(host = host,port=port,
table_prefix = namespace,table_prefix_separator=':')
self.conn.open()
self.table = self.conn.table(table_name)
self.batch = self.table.batch(batch_size = self.config['BATCH_SIZE'])
def append_row(self,rowkey,family,col,content):
self.table.put(rowkey, { '%s:%s' % (family,col) : content } )
def close(self):
self.conn.close()
def filter_rows(self,filter=None):
if filter:
rs = self.table.scan(filter=filter)
return rs
else :
rs = self.table.scan()
return rs
from hbasemanager import HBaseManager
hbase = HBaseManager(host='192.168.10.202',namespace='default',table_name='user_profile')
# hbase.append_row('rk0001','cf','name','zhang')
hbase.append_row('user1', 'action','s', 'kw1')
hbase.append_row('user1', 'action','s', 'kw188')
hbase.append_row('user1', 'action','s', 'kw123')
hbase.append_row('user2', 'action','s', 'kw2')
hbase.append_row('user2', 'action','c', 'kw288')
hbase.append_row('user2', 'action','s', 'kw222')
hbase.append_row('user1','action','o', 'kw1')
# --哪个用户通过点击广告(c),值包含88
# scan 'user_profile', FILTER=>"ColumnPrefixFilter('c') AND ValueFilter(=,'substring:88')"
filter = "ColumnPrefixFilter('c') AND ValueFilter(=,'substring:88')"
# for user,action in hbase.filter_rows(filter):
# print user,action
for user,action in hbase.filter_rows():
print (user,action)