HBASE与Java
1. 概述
在本文中,我们将研究HBase 数据库 Java 客户端库。HBase 是一个分布式数据库,它使用 Hadoop 文件系统来存储数据。
我们将创建一个 Java 示例客户端和一个表,我们将向其中添加一些简单的记录。
2. HBase 数据结构
在 HBase 中,数据被分组到列族中。列族的所有列成员都具有相同的前缀。
例如,列family1:qualifier1 和 family1:qualifier2 都是family1列族的成员。所有列族成员一起存储在文件系统上。
在列族中,我们可以放置具有指定限定符的行。我们可以将限定符视为一种列名。
让我们看一个来自 Hbase 的示例记录:
Family1:{
'Qualifier1':'row1:cell_data',
'Qualifier2':'row2:cell_data',
'Qualifier3':'row3:cell_data'
}
Family2:{
'Qualifier1':'row1:cell_data',
'Qualifier2':'row2:cell_data',
'Qualifier3':'row3:cell_data'
}
我们有两个列族,每个列族都有三个限定符,其中包含一些单元格数据。每行都有一个行键——它是一个唯一的行标识符。我们将使用行键来插入、检索和删除数据。
3. HBase客户端Maven依赖
在我们连接到 HBase 之前,我们需要添加hbase-client 和*hbase *依赖项:
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>${hbase.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
<version>${hbase.version}</version>
</dependency>
4. HBase 设置
我们需要设置 HBase 以便能够从 Java 客户端库连接到它。安装超出了本文的范围,但您可以在线查看一些 HBase 安装指南 。
接下来,我们需要通过执行以下命令在本地启动一个 HBase master:
hbase master start
5. 从 Java 连接到 HBase
为了以编程方式从 Java 连接到 HBase,我们需要定义一个 XML 配置文件。我们在 localhost 上启动了 HBase 实例,因此我们需要将其输入到配置文件中:
<configuration>
<property>
<name>hbase.zookeeper.quorum</name>
<value>localhost</value>
</property>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
</configuration>
现在我们需要将 HBase 客户端指向该配置文件:
Configuration config = HBaseConfiguration.create();
String path = this.getClass()
.getClassLoader()
.getResource("hbase-site.xml")
.getPath();
config.addResource(new Path(path));
接下来,我们检查与 HBase 的连接是否成功——如果失败,将抛出MasterNotRunningException:
HBaseAdmin.checkHBaseAvailable(config);
6. 创建数据库结构
在我们开始向 HBase 添加数据之前,我们需要创建用于插入行的数据结构。我们将创建一个包含两个列族的表:
private TableName table1 = TableName.valueOf("Table1");
private String family1 = "Family1";
private String family2 = "Family2";
首先,我们需要创建一个到数据库的连接并获取admin对象,我们将使用它来操作数据库结构:
Connection connection = ConnectionFactory.createConnection(config)
Admin admin = connection.getAdmin();
然后,我们可以通过将HTableDescriptor类的实例传递给admin对象的*createTable()*方法来创建表:
HTableDescriptor desc = new HTableDescriptor(table1);
desc.addFamily(new HColumnDescriptor(family1));
desc.addFamily(new HColumnDescriptor(family2));
admin.createTable(desc);
7. 添加和检索元素
创建表后,我们可以通过创建一个Put对象并在Table对象上调用*put()*方法来向其中添加新数据:
byte[] row1 = Bytes.toBytes("row1")
Put p = new Put(row1);
p.addImmutable(family1.getBytes(), qualifier1, Bytes.toBytes("cell_data"));
table1.put(p);
可以使用Get类来检索先前创建的行:
Get g = new Get(row1);
Result r = table1.get(g);
byte[] value = r.getValue(family1.getBytes(), qualifier1);
row1是行标识符——我们可以使用它从数据库中检索特定行。调用时:
Bytes.bytesToString(value)
返回的结果将是之前插入的cell_data。
8. 扫描过滤
我们可以扫描表格,使用Scan对象检索给定限定符内的所有元素(请注意ResultScanner扩展了Closable,因此请务必在完成后对其调用close()):
Scan scan = new Scan();
scan.addColumn(family1.getBytes(), qualifier1);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
System.out.println("Found row: " + result);
}
该操作将打印qualifier1内的所有行以及一些附加信息,例如时间戳:
Found row: keyvalues={Row1/Family1:Qualifier1/1488202127489/Put/vlen=9/seqid=0}
我们可以使用过滤器检索特定记录。
首先,我们正在创建两个过滤器。filter1指定扫描查询将检索大于row1 的元素,而filter2指定我们只对限定符等于qualifier1的行感兴趣:
Filter filter1 = new PrefixFilter(row1);
Filter filter2 = new QualifierFilter(
CompareOp.GREATER_OR_EQUAL,
new BinaryComparator(qualifier1));
List<Filter> filters = Arrays.asList(filter1, filter2);
然后我们可以从Scan查询中得到一个结果集:
Scan scan = new Scan();
scan.setFilter(new FilterList(Operator.MUST_PASS_ALL, filters));
try (ResultScanner scanner = table.getScanner(scan)) {
for (Result result : scanner) {
System.out.println("Found row: " + result);
}
}
创建FilterList时,我们传递了Operator.MUST_PASS_ALL - 这意味着必须满足所有过滤器。如果只需要满足一个过滤器,我们可以选择Operation.MUST_PASS_ONE。在结果集中,我们将只有与指定过滤器匹配的行。
9. 删除行
最后,要删除一行,我们可以使用Delete类:
Delete delete = new Delete(row1);
delete.addColumn(family1.getBytes(), qualifier1);
table.delete(delete);
我们正在删除位于family1中的row1。