hbase编程指南
来源:互联网 发布:tensorflow theano 编辑:程序博客网 时间:2024/05/19 21:16
hbase编程指南
@(博客文章)[hbase, 大数据]
- hbase编程指南
- 一概述
- 一创建项目
- 1pomxml
- 2在eclipse中运行的注意事项
- 3是否需要addResource
- TODO 在eclipse运行时为什么要增加这句即使将hbase的目录加入了classpath
- 一创建项目
- 二Best Practices
- 三常用API
- 一创建Configuration及Connection对象
- 二表管理
- 1创建表
- 2判断表是否存在
- 3删除表
- 三插入数据
- 1插入单条数据
- 2使用缓存
- 四读取数据单个数据和一批数据
- 1遍历返回数据的方法
- 五扫描表
- 六更改表结构
- 四常见异常
- 1javaioIOException No FileSystem for scheme hdfs
本文示范了如何创建表,删除表,更改表结构,还有put, get, scan等操作。
完整代码请见:
https://github.com/lujinhong/hbasecommons
一、概述
(一)创建项目
1、pom.xml
pom.xml中除了hbase以外,还需要添加hadoop相关的依赖:
<dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.5.0</version> </dependency>
2、在eclipse中运行的注意事项
将hadoop/hbase的配置文件加入classpath中。
3、是否需要addResource
config.addResource(new Path("/Users/liaoliuqing/Downloads/conf_loghbase/hbase", "hbase-site.xml"));
TODO: 在eclipse运行时为什么要增加这句?即使将hbase的目录加入了classpath。
config.addResource(“hbase-site.xml”);不生效,看看集群环境是 否一样。
二、Best Practices
- Connection是非常heavy的,但线程安全,一般而言,一个应用创建一个连接即可。如果实在需要创建多个,可以考虑pool,但一般不需要。
- Table,Admin, Scanner都是lighweigh的,但非线程安全。
- 上面几个接口都必须记住close,但connection应该作好封装,避免某处调用将其close了。另外,这几个接口都是AutoClosable的,可以使用新的try语法。
- Use BufferedMutator for streaming / batch Puts. BufferedMutator replaces HTable.setAutoFlush(false) and is the supported high-performance streaming writes API.
- 将hbase-site.xml添加至classpath中,而不是手工调用add方法。
三、常用API
(一)创建Configuration及Connection对象
在客户端中连接hbase,首先需要创建一个Connection对象,然后就可以使用connection获取Table, Admin, Scanner等对象,进行相应的操作。
Configuration config = HBaseConfiguration.create();Connection connection = ConnectionFactory.createConnection(config);
基本方法如上:
(1)创建一个Configuration对象,它会从classpath中查找hadoop/hbase的配置文件。
(2)创建Connection对象。
正如上面所如,创建connection是一个很heavy的操作,应该谨慎使用。最好将其封装在一个方法中getConnection()的方法中返回,而不是直接创建,同时考虑使用单例模式,如:
private static Connection connection = null;private HBaseHelper(Configuration conf) throws IOException { configuration = conf; connection = ConnectionFactory.createConnection(configuration); this.admin = connection.getAdmin();}/* * 用于获取一个HBaseHelper对象的入口,需要提供一个Configuration对象,这个配置主要指定hbase-site.xml与core- * site.xml。 * 使用单例,保证只创建一个helper,因为每创建一个connection都是高代价的,如果需要多个连接,请使用Pool。 */public static HBaseHelper getHelper(Configuration configuration) throws IOException { if (helper == null) { helper = new HBaseHelper(configuration); } return helper;}
然后通过getConnection()方法获取到connection对象:
public Configuration getConfiguration() { return configuration;}
由于HBaseHelper是实例对象,因此其成员变量也是只有一个的。
同时提供一个close()用于关掉Connection对象,因为如果用户随意关闭了connection,会导致需要经常重新创建Connection对象:
@Overridepublic void close() throws IOException { admin.close(); connection.close();}
这个方法只会在整个应用关闭后才应该调用,比如某些框架的cleanUp()方法等,一般情况下只要应用程序还在运行就不应该调用这个方法。
由于HBaseHelper实现了较多功能,所以这里将HBaseHelper设为单例,如果只需要将Connection设为单例也是可以的,此时代码相对简单。
private static Connection connection = null;public static Connection getConnection(Configuration config) throws IOException { if (connection == null) { connection = ConnectionFactory.createConnection(config); } return connection;}
(二)表管理
1、创建表
创建表的完整应用如下:
public void createTable(TableName table, int maxVersions, byte[][] splitKeys, String... colfams) throws IOException { HTableDescriptor desc = new HTableDescriptor(table); for (String cf : colfams) { HColumnDescriptor coldef = new HColumnDescriptor(cf); coldef.setMaxVersions(maxVersions); desc.addFamily(coldef); } if (splitKeys != null) { admin.createTable(desc, splitKeys); } else { admin.createTable(desc); }}
几个参数的意思分别为表名,最多保留多少个版本,用于预分区的keys,family的名称。
同时还应封装将见的应用方式:
public void createTable(String table, String... colfams) throws IOException { createTable(TableName.valueOf(table), 1, null, colfams);}public void createTable(TableName table, String... colfams) throws IOException { createTable(table, 1, null, colfams);}public void createTable(String table, int maxVersions, String... colfams) throws IOException { createTable(TableName.valueOf(table), maxVersions, null, colfams);}public void createTable(TableName table, int maxVersions, String... colfams) throws IOException { createTable(table, maxVersions, null, colfams);}public void createTable(String table, byte[][] splitKeys, String... colfams) throws IOException { createTable(TableName.valueOf(table), 1, splitKeys, colfams);}
关键步骤为:
(1)获取一个Admin对象,用于管理表。这个对象在HBaseHelper中创建了,所以这里就不创建了。
(2)创建一个HTableDescriptor对象,表示一个表,但这个表还不存在。与下面的Table类对比。这个对象还可以设置很多属性,如压缩格式,文件大小等。
(3)判断表是否已经存在,若存在的话,先disable, 然后delete。
(4)创建表。
Admin, HTableDescriptor对象都是轻量级的,只要有需要就可以创建,
2、判断表是否存在
public boolean existsTable(String table) throws IOException { return existsTable(TableName.valueOf(table));}public boolean existsTable(TableName table) throws IOException { return admin.tableExists(table);}
其实上面的代码就是直接调用hbase API的tableExists()方法,但不需要每次重新创建admin对象等。
3、删除表
public void disableTable(String table) throws IOException { disableTable(TableName.valueOf(table));}public void disableTable(TableName table) throws IOException { admin.disableTable(table);}public void dropTable(String table) throws IOException { dropTable(TableName.valueOf(table));}public void dropTable(TableName table) throws IOException { if (existsTable(table)) { if (admin.isTableEnabled(table)) disableTable(table); admin.deleteTable(table); }}
(三)插入数据
1、插入单条数据
下面定义了各种常见的put方式,最后一种其实并不常用。
public void put(String table, String row, String fam, String qual, String val) throws IOException { put(TableName.valueOf(table), row, fam, qual, val);}public void put(TableName table, String row, String fam, String qual, String val) throws IOException { Table tbl = connection.getTable(table); Put put = new Put(Bytes.toBytes(row)); put.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual), Bytes.toBytes(val)); tbl.put(put); tbl.close();}public void put(String table, String row, String fam, String qual, long ts, String val) throws IOException { put(TableName.valueOf(table), row, fam, qual, ts, val);}public void put(TableName table, String row, String fam, String qual, long ts, String val) throws IOException { Table tbl = connection.getTable(table); Put put = new Put(Bytes.toBytes(row)); put.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual), ts, Bytes.toBytes(val)); tbl.put(put); tbl.close();}public void put(String table, String[] rows, String[] fams, String[] quals, long[] ts, String[] vals) throws IOException { put(TableName.valueOf(table), rows, fams, quals, ts, vals);}public void put(TableName table, String[] rows, String[] fams, String[] quals, long[] ts, String[] vals) throws IOException { Table tbl = connection.getTable(table); for (String row : rows) { Put put = new Put(Bytes.toBytes(row)); for (String fam : fams) { int v = 0; for (String qual : quals) { String val = vals[v < vals.length ? v : vals.length - 1]; long t = ts[v < ts.length ? v : ts.length - 1]; System.out.println("Adding: " + row + " " + fam + " " + qual + " " + t + " " + val); put.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual), t, Bytes.toBytes(val)); v++; } } tbl.put(put); } tbl.close();}
这里每次put一个数据均会创建一个Table对象,然后close这个对象。虽然说这个对象是轻量级的,但如果发生一个循环里面,则不断的创建及destory对象还是会有较大的消耗的,这种情况应该考虑复用Table对象,或者使用下面介绍的缓存技术。
2、使用缓存
在hbase1.0.0以后,使用BufferedMutator处理缓存,这些数据会先在客户端中保存,直到缓冲区满了,或者是显示调用flush方法数据才会通过PRC请求发送至hbase。
/* * 将一系列的数据put进table的fam:qual中,由rows和vals来定义写入的数据,它们的长期必须相等。 */public void put(String table, String[] rows, String fam, String qual, String[] vals) throws IOException { if (rows.length != vals.length) { LOG.error("rows.lenght {} is not equal to val.length {}", rows.length, vals.length); } try (BufferedMutator mutator = connection.getBufferedMutator(TableName.valueOf(table));) { for (int i = 0; i < rows.length; i++) { Put p = new Put(Bytes.toBytes(rows[i])); p.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual), Bytes.toBytes(vals[i])); mutator.mutate(p); //System.out.println(mutator.getWriteBufferSize()); } mutator.flush(); }}public void put(String table, String[] rows, String fam, String qual, String[] vals) throws IOException { put(TableName.valueOf(table), rows, fam, qual, vals);}
最后的输出是缓冲区大小,默认是2M,由参数hbase.client.write.buffer.决定。可以通过下面方法得到:
mutator.getWriteBufferSize()
怎样设置缓冲区大小呢?
(四)读取数据:单个数据和一批数据
/* * 获取table表中,所有rows行中的,fam:qual列的值。 */public Result get(String table, String row, String fam, String qual) throws IOException { return get(TableName.valueOf(table), new String[]{row}, new String[]{fam}, new String[]{qual})[0];}public Result get(TableName table, String row, String fam, String qual) throws IOException { return get(table, new String[]{row}, new String[]{fam}, new String[]{qual})[0];}public Result[] get(TableName table, String[] rows, String fam, String qual) throws IOException { return get(table, rows, new String[]{fam}, new String[]{qual});}public Result[] get(String table, String[] rows, String fam, String qual) throws IOException { return get(TableName.valueOf(table), rows, new String[]{fam}, new String[]{qual});}public Result[] get(String table, String[] rows, String[] fams, String[] quals) throws IOException { return get(TableName.valueOf(table), rows, fams, quals);}/* * 获取table表中,所有rows行中的,fams和quals定义的所有行。 */public Result[] get(TableName table, String[] rows, String[] fams, String[] quals) throws IOException { Table tbl = connection.getTable(table); List<Get> gets = new ArrayList<Get>(); for (String row : rows) { Get get = new Get(Bytes.toBytes(row)); get.setMaxVersions(); if (fams != null) { for (String fam : fams) { for (String qual : quals) { get.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual)); } } } gets.add(get); } Result[] results = tbl.get(gets); tbl.close(); return results;}
1、遍历返回数据的方法
for (Result result : results) { for (Cell cell : result.rawCells()) { System.out.println("Cell: " + cell + ", Value: " + Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); } }
如果直接调用result.toString(),则只返回前面那部分,即cell,而没有value部分。
(五)扫描表
将表打印出来:
public void dump(String table) throws IOException { dump(TableName.valueOf(table));}public void dump(TableName table) throws IOException { try (Table t = connection.getTable(table); ResultScanner scanner = t.getScanner(new Scan())) { for (Result result : scanner) { dumpResult(result); } }}public void dumpResult(Result result) { for (Cell cell : result.rawCells()) { System.out.println("Cell: " + cell + ", Value: " + Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); }}
(六)更改表结构
//有问题,而且一般不建议在代码中更改表结构。public static void modifySchema(Connection connection) throws IOException { try (Admin admin = connection.getAdmin()) { TableName tableName = TableName.valueOf(TABLE_NAME); if (!admin.tableExists(tableName)) { System.out.println("Table does not exist."); System.exit(-1); } HTableDescriptor table = new HTableDescriptor(tableName); // Update existing table HColumnDescriptor newColumn = new HColumnDescriptor("NEWCF"); newColumn.setCompactionCompressionType(Algorithm.GZ); newColumn.setMaxVersions(HConstants.ALL_VERSIONS); admin.addColumn(tableName, newColumn); // Update existing column family HColumnDescriptor existingColumn = new HColumnDescriptor(FAMILY); existingColumn.setCompactionCompressionType(Algorithm.GZ); existingColumn.setMaxVersions(HConstants.ALL_VERSIONS); table.modifyFamily(existingColumn); admin.modifyTable(tableName, table); // Disable an existing table admin.disableTable(tableName); // Delete an existing column family admin.deleteColumn(tableName, FAMILY.getBytes("UTF-8")); // Delete a table (Need to be disabled first) admin.deleteTable(tableName); }}
四、常见异常
1、java.io.IOException: No FileSystem for scheme: hdfs
解决方法:将hadoop相关的jar包添加至classpath中。
- hbase编程指南
- hbase编程指南
- hbase编程指南
- hbase编程指南
- Hbase指南
- hbase 编程
- c++连接hbase指南
- Hbase 权威指南
- HBase权威指南 翻译
- hbase界面操作指南
- HBase权威指南中文版
- HBase分布式安装指南
- hbase 安装指南
- hbase安装指南
- HBase性能优化指南
- hadoop 权威指南 HBase
- Hbase 快速启动指南
- HBase性能优化指南
- hdu4513(manacher)
- DataTable转Excel并对0开头的数值保留0显示
- cordova app强制横屏
- 关于Handler和Looper
- json解析,jquery解析遍历json
- hbase编程指南
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (
- OSG OSGearth vs2010编译
- Sharpssh连接linux上传下载文件
- order by 列加索引
- MySQL中文全文检索demoSQL
- Iptables防火墙使用
- Parallel Computing Toolbox(PCT)
- Android知识梳理之BroadcastReceiver整理