一、前言
对于前两篇的特别概念化的介绍了Hbase,这章用通俗易懂的语言来结束上两章里面的专业术语。
回忆上回内容:8.6 、hbase核心概念:HBase并不是一个列式存储的数据库,HBase是以列式存储的格式在磁盘上存储数据。
解惑:
什么是列式存储?列存储不同于传统的关系型数据库,其数据在表中是按行存储的,列方式所带来的重要好处之一就是,由于查询中的选择规则是通过列来定义的,因 此整个数据库是自动索引化的。按列存储每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量,一个字段的数据聚集存储,那就 更容易为这种聚集存储设计更好的压缩/解压算法。这张图讲述了传统的行存储和列存储的区别:
二、很多朋友会问我Hbase这么好为什么不能取代Mysql?
解答如下:
因为玩Hbase对运维人员的要求较高,一旦出现Bug很容易造成业务断链,能玩的6的只有公司的背景需要有一定开源技术水平的支撑。
对于传统型中小型公司 组建专有的Hadoop运维团队甚至是研发团队,从公司规划与发展上来说是比较困难的事情。
Hbase的特点只有牛逼的读写速度,修改和事务性处理这方面表现力太挫,如果事务性处理是公司的核心业务,那就别用Hbase了,除了阿里巴巴之外
我没看到哪家银行交易系统用Hbase弄的!
所以hbase暂时不能取代mysql,除非你有媲美阿里巴巴的技术,这我一点话都没有!
我个人推荐业务场景,只涉及到大量的读写,在Mysql上已经没有优化空间了,并且核心业务事务性处理比较少,没有大量复杂的关系查询。
并且自己的DAO,PO层改起来不麻烦和一定的大数据开源技术储备,和阅读源码以及快速修复Bug的能力,建议上手Hbase。
三、几款Hbase的ORM框架这里重点介绍Kundera
http://stackoverflow.com/questions/3257034/java-orm-for-hbase
Kundera是一个带有JPA接口的“Polyglot Object Mapper”。Kundera背后的想法是使NoSQL数据库的工作变得简单而有趣。昆德拉正在开发具有以下目标:
-
使用NoSQL与处理SQL一样简单
-
作为NoSQL数据存储的JPA兼容映射解决方案。
-
为了帮助开发人员,忘记了NoSQL存储的复杂性,并专注于域模型。
-
跨数据存储进行切换,就像更改配置一样简单。
入门
昆德拉最新的稳定版本是3.8。它是一个基于maven的项目。您可以直接从github下载并使用以下命令进行构建:
mvn clean install -Dfile src / pom.xml
或者可以以下列方式直接在您的项目中添加为maven依赖关系:
-
将以下存储库添加到pom.xml中:
<repository> <id>sonatype-nexus</id> <name>Kundera Public Repository</name> <url>https://oss.sonatype.org/content/repositories/releases</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository>
-
添加数据存储特定的Kundera模块作为依赖(例如下面的Cassandra):
<dependency> <groupId>com.impetus.kundera.client</groupId> <artifactId>kundera-cassandra</artifactId> <version>${kundera.version}</version> </dependency>
通过上述对您的pom.xml的更改来构建您的项目,并开始使用Kundera!
四、国内Hbase 的轻量级ORM封装好的包
Hbase在处理billion级别的能力是毫无质疑的,目前优于其他的nosql数据库,如MongoDB、cassandra、Redis等, 配合它强大的rowkey查询,fileter,协处理器等,在海量数据库中发挥了强大的功能。但是HBase因为满足的是CAP原则中C和P,所以在查询过程中语句支持较弱,使用过程较为复杂。存在下面的一些痛点。
痛点
-
首先HBase只能存储byte数组的数据,数据存入到hbase中时都需要做相应的转换,读取的数据的时候也要相应的转换回来,使用麻烦。
-
第二,HBase在使用过程中,涉及到filter、协处理的使用,如果对API不熟悉,无法下手。
-
第三,hbase本身不提供分页的功能,每次分页需要在代码中记录当前读取的rowkey,在使用PageFilter读取一定数量的rowkey,然后继续读取,编程复杂度高。
-
最后,不熟悉hbase的开发人员,无法理解nosql、hbase的no schema,期望还是用关系数据库的方式操作hbase。
HBase ORM框架
基于以上的原因,所以我有了想写一个类似于hibernate那种对象关系映射框架(ORM)的想法,像操作对象一样方便的操作HBase数据库,但是它要是轻量级的,无侵入的,只提供CURD、分页、映射功能的一个简单功能。
一些特性:
-
使用注解的方式,将PO(Persistent Object)映射成HBase对应的表
-
提供CRUD的方法:create\research\update\delete
-
提供分页查询的功能
-
提供类似于hibernate中Criteria 风格的操作方式
Demo:
1、在po对象上添加相应的注解:@Table\@RowKey\@Column
@Table(name = "user")</br>
public class User {
@RowKey
private int id;
@Column(family = "info")
private int userId;
@Column(family = "info", name = "user_name1")
private String userName;
@Column(family =
2、使用HBaseColumnarClient实例操作PO对象
HBaseColumnarClient client = new HBaseColumnarClient(scanCaching, scanBatch);
DataSourceConfig config = new DataSourceConfig("hbase.properties");
HBaseSource source = new HBaseSource(config.getProperties());
client.setHBaseSource(source);
//create
client.putObject(user);
//delete
client.deleteObject(user);
//query
User user = client.findObject(Bytes.toB6
3、提供类似于Hibernate Criteria的风格操作hbase
// count the data
Filter[] filters = null;
long count =
Criteria.aggregate(User.class).fromRow(startRow).toRow(endRow)
.filters(filters).build().count(client);
// sum the column value
long sum =
Criteria.aggregate(User.class).fromRow(startRow).toRow(endRow)
.filters(filters).propertyName("age").build().sum(client);
// query by rowKey
User queryUser =
Criteria.find(User.class).byRowKey(Bytes.toBytes(id)).build().query(client);
// query from startRow to endRow
List<User> queryList =
Criteria.find(User.class).fromRow(startRow).toRow(endRow).build()
.queryList(client);
// query by page
PageBean<User> pageBean = new PageBean<User>() {};
pageBean.setPageSize(10);
pageBean.setStartRow(startRow);
pageBean.setStopRow(endRow);
PageBean<User> queryPage =
Criteria.find(User.class).pageBean(pageBean).build().queryPage(client);
// delete data
byte[] rowKey = Bytes.toBytes(id);
Criteria.delete(User.class).byRowKey(rowKey).buil1
希望大家喜欢这个框架,多提意见
项目地址:https://github.com/zacharyzhanghao/orm-hbase
五、springdatahadoop -- hbasetemplate
java 利用 sping-data-hadoop HbaseTemplate 操作hbase
转载请注明出处:http://blog.csdn.net/linlinv3/article/details/42737113
官网api地址:http://docs.spring.io/autorepo/docs/spring-data-hadoop/2.1.0.M1-hadoop24/api/org/springframework/data/hadoop/hbase/HbaseTemplate.html为了让自己的项目能够融合hbase ,这里讲解了 如何 利用hbasetemplate 对hbase进行操作
具体的hbase的特性和原理就不多说了
直接贴程序
配置文件
1、建立 spring-hbase.xml 获取连接池
第一种:直接在配置文件注明 hdfs的端口和zk的地址以及端口进行连接
[html] view plain copy print?
-
<?xml version="1.0" encoding="UTF-8"?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xmlns:hdp="http://www.springframework.org/schema/hadoop"
-
xmlns:beans="http://www.springframework.org/schema/beans"
-
xmlns:context="http://www.springframework.org/schema/context"
-
xsi:schemaLocation="
-
http://www.springframework.org/schema/beans
-
http://www.springframework.org/schema/beans/spring-beans.xsd
-
http://www.springframework.org/schema/hadoop
-
http://www.springframework.org/schema/hadoop/spring-hadoop.xsd
-
http://www.springframework.org/schema/context
-
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
-
-
<context:property-placeholder location="hbase.properties" />
-
-
<!-- 配置HbaseTemplate -->
-
<bean id="htemplate" class="org.springframework.data.hadoop.hbase.HbaseTemplate">
-
<property name="configuration" ref="hbaseConfiguration">
-
</property>
-
</bean>
-
<!-- 配置hadoop的基本信息 -->
-
<hdp:configuration>
-
fs.default.name="hdfs://192.168.0.173:8082"
-
</hdp:configuration>
-
<!-- 配置zookeeper地址和端口 -->
-
<hdp:hbase-configuration zk-quorum="192.168.0.173" zk-port="2181" />
-
</beans>
第二种:只需要配置zk的地址和端口,但是需要在classpath另外新增 hbase-site.xml的配置
spring-hbase.xml 配置:
[java] view plain copy print?
-
<?xml version="1.0" encoding="UTF-8"?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xmlns:hdp="http://www.springframework.org/schema/hadoop"
-
xmlns:beans="http://www.springframework.org/schema/beans"
-
xsi:schemaLocation="
-
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
-
http://www.springframework.org/schema/hadoop http://www.springframework.org/schema/hadoop/spring-hadoop.xsd">
-
<!-- 配置zookeeper的信息,远程连接hbase时使用 -->
-
<hdp:configuration resources="classpath:/hbase-site.xml" />
-
<hdp:hbase-configuration configuration-ref="hadoopConfiguration" />
-
<!-- 配置HbaseTemplate -->
-
<bean id="htemplate" class="org.springframework.data.hadoop.hbase.HbaseTemplate">
-
<property name="configuration" ref="hbaseConfiguration">
-
</property>
-
<property name="encoding" value="UTF-8"></property>
-
</bean>
-
</beans>
hbase-site.xml 配置 放在classpath下(直接扔到src下即可)
[java] view plain copy print?
-
<?xml version="1.0"?>
-
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
-
<configuration>
-
<property>
-
<name>hbase.zookeeper.quorum</name>
-
<value>192.168.0.173</value>
-
</property>
-
-
<property>
-
<name>hbase.zookeeper.property.clientPort</name>
-
<value>2181</value>
-
</property>
-
</configuration>
配置完成
程序代码
官网的api地址已经在上面发过了,这里只做了一个简单的demo,列举了简单的 get find execue 方法
[java] view plain copy print?
-
package cn.fulong.hbase;
-
-
import java.util.HashMap;
-
import java.util.List;
-
import java.util.Map;
-
-
import org.apache.hadoop.hbase.Cell;
-
import org.apache.hadoop.hbase.client.HTableInterface;
-
import org.apache.hadoop.hbase.client.Put;
-
import org.apache.hadoop.hbase.client.Result;
-
import org.apache.hadoop.hbase.client.Scan;
-
import org.apache.hadoop.hbase.util.Bytes;
-
import org.springframework.beans.factory.BeanFactory;
-
import org.springframework.context.ApplicationContext;
-
import org.springframework.context.support.ClassPathXmlApplicationContext;
-
import org.springframework.data.hadoop.hbase.HbaseTemplate;
-
import org.springframework.data.hadoop.hbase.RowMapper;
-
import org.springframework.data.hadoop.hbase.TableCallback;
-
-
import cn.fulong.view.HbaseModel;
-
public class HbaseTest {
-
//ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "application_hbase.xml" });
-
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "spring_hbase.xml" });
-
-
BeanFactory factory = (BeanFactory) context;
-
HbaseTemplate htemplate = (HbaseTemplate) factory.getBean("htemplate");
-
Map hMap = new HashMap<String, List<HbaseModel>>();
-
public String key;
-
public String familyName ;
-
public String qualifier;
-
public String value;
-
-
public String getValue() {
-
return value;
-
}
-
public void setValue(String value) {
-
this.value = value;
-
}
-
public String getFamilyName() {
-
return familyName;
-
}
-
public void setFamilyName(String familyName) {
-
this.familyName = familyName;
-
}
-
public String getQualifier() {
-
return qualifier;
-
}
-
public void setQualifier(String qualifier) {
-
this.qualifier = qualifier;
-
}
-
public String getKey() {
-
return key;
-
}
-
public void setKey(String key) {
-
this.key = key;
-
}
-
-
-
-
public static void main(String[] args) {
-
//PrefixFilter
-
HbaseTest h = new HbaseTest();
-
-
for(int i=0;i<=10000;i++){
-
h.setKey("linlin"+i);
-
h.setFamilyName("info");
-
h.setQualifier("service");
-
h.setValue(i+"技术创新和质量服务");
-
h.execute("linlintest", null);
-
}
-
-
List<Map<String,Object>> mapList1 = h.find("linlintest",null,null);
-
System.out.println("2");
-
}
-
/**
-
* 写数据
-
* @param tableName
-
* @param action
-
* @return
-
*/
-
public Boolean execute(String tableName, TableCallback<Boolean> action) {
-
return htemplate.execute(tableName, new TableCallback<Boolean>() {
-
public Boolean doInTable(HTableInterface table) throws Throwable {
-
boolean flag = false;
-
try{
-
byte[] rowkey = key.getBytes();
-
Put put = new Put(rowkey);
-
put.add(Bytes.toBytes(familyName),Bytes.toBytes(qualifier), Bytes.toBytes(value));
-
table.put(put);
-
flag = true;
-
}catch(Exception e){
-
e.printStackTrace();
-
}
-
return flag;
-
}
-
});
-
}
-
/**
-
* 通过表名和key获取一行数据
-
* @param tableName
-
* @param rowName
-
* @return
-
*/
-
public Map<String, Object> get(String tableName, String rowName) {
-
return htemplate.get(tableName, rowName,new RowMapper<Map<String,Object>>(){
-
public Map<String,Object> mapRow(Result result, int rowNum) throws Exception {
-
List<Cell> ceList = result.listCells();
-
Map<String,Object> map = new HashMap<String, Object>();
-
if(ceList!=null&&ceList.size()>0){
-
for(Cell cell:ceList){
-
map.put(Bytes.toString(cell.getFamilyArray(),cell.getFamilyOffset(),cell.getFamilyLength())+
-
"_"+Bytes.toString( cell.getQualifierArray(),cell.getQualifierOffset(),cell.getQualifierLength()),
-
Bytes.toString( cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
-
}
-
}
-
return map;
-
}
-
});
-
}
-
-
/**
-
* 通过表名 key 和 列族 和列 获取一个数据
-
* @param tableName
-
* @param rowName
-
* @param familyName
-
* @param qualifier
-
* @return
-
*/
-
public String get(String tableName ,String rowName, String familyName, String qualifier) {
-
return htemplate.get(tableName, rowName,familyName,qualifier ,new RowMapper<String>(){
-
public String mapRow(Result result, int rowNum) throws Exception {
-
List<Cell> ceList = result.listCells();
-
String res = "";
-
if(ceList!=null&&ceList.size()>0){
-
for(Cell cell:ceList){
-
res = Bytes.toString( cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
-
}
-
}
-
return res;
-
}
-
});
-
}
-
-
-
/**
-
* 通过表名,开始行键和结束行键获取数据
-
* @param tableName
-
* @param startRow
-
* @param stopRow
-
* @return
-
*/
-
public List<Map<String,Object>> find(String tableName , String startRow,String stopRow) {
-
Scan scan = new Scan();
-
if(startRow==null){
-
startRow="";
-
}
-
if(stopRow==null){
-
stopRow="";
-
}
-
scan.setStartRow(Bytes.toBytes(startRow));
-
scan.setStopRow(Bytes.toBytes(stopRow));
-
/* PageFilter filter = new PageFilter(5);
-
scan.setFilter(filter);*/
-
return htemplate.find(tableName, scan,new RowMapper<Map<String,Object>>(){
-
public Map<String,Object> mapRow(Result result, int rowNum) throws Exception {
-
-
List<Cell> ceList = result.listCells();
-
Map<String,Object> map = new HashMap<String,Object>();
-
Map<String,Map<String,Object>> returnMap = new HashMap<String,Map<String,Object>>();
-
String row = "";
-
if(ceList!=null&&ceList.size()>0){
-
for(Cell cell:ceList){
-
row =Bytes.toString( cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
-
String value =Bytes.toString( cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
-
String family = Bytes.toString(cell.getFamilyArray(),cell.getFamilyOffset(),cell.getFamilyLength());
-
String quali = Bytes.toString( cell.getQualifierArray(),cell.getQualifierOffset(),cell.getQualifierLength());
-
map.put(family+"_"+quali, value);
-
}
-
map.put("row",row );
-
}
-
return map;
-
}
-
});
-
}
-
-
-
/* public void scanValueByFilter(String tableName,String row) throws IOException{
-
HTable table = new HTable(conf, tableName);
-
Scan scan = new Scan();
-
scan.setFilter(new PrefixFilter(row.getBytes()));
-
ResultScanner resultScanner = table.getScanner(scan);
-
for(Result rs:resultScanner){
-
-
-
}
-
-
}*/
-
}
下载
具体可运行代码下载地址 http://download.csdn.net/detail/linlinv3/8580185
项目目录结构和所需jar包如下图所示:
六、HBase Object Mapper
介绍
这个紧凑型实用程序库是一个基于注释的HBase 对象映射器(用Java编写),可帮助您:
-
将bean类的对象转换为HBase行,反之亦然
-
用于从HBase表读取和/或写入Hadoop MapReduce作业
-
并编写有效的单元测试
Mapper
和Reducer
类 -
定义映射到HBase行的实体的数据访问对象
-
用于HBase表的行的单次/范围/批量访问
七、simplehbase
是阿里巴巴的一个开源项目。15年之后就不更新了,既然是阿里大神写的,应该不会太差,易用性更符合国情!
simplehbase是java和hbase之间的轻量级中间件。 主要包含以下功能。
-
数据类型映射:java类型和hbase的bytes之间的数据转换。
-
简单操作封装:封装了hbase的put,get,scan等操作为简单的java操作方式。
-
hbase query封装:封装了hbase的filter,可以使用sql-like的方式操作hbase。
-
动态query封装:类似于myibatis,可以使用xml配置动态语句查询hbase。
-
insert,update支持: 建立在hbase的checkAndPut之上。
-
hbase多版本支持:提供接口可以对hbase多版本数据进行查询,映射。
-
hbase批量操作支持。
-
hbase原生接口支持。
-
HTablePool管理。
-
HTable count和sum功能。
八、参考博客
Phoenix综述(史上最全Phoenix中文文档):
http://www.cnblogs.com/linbingdong/p/5832112.html
http://blog.csdn.net/shifenglov/article/details/50772636
hbase是否能取代mysql
http://blog.csdn.net/cqboy1991/article/details/26366781
GitHub一个外国大神封装的hbase的ORM层:hbase-object-mapper/
https://flipkart-incubator.github.io/hbase-object-mapper/
simplehbase 阿里大神开发的,知识库:
https://github.com/alibaba/simplehbase/wiki/_pageshbase-object-mapper