簡(jiǎn)述
在HBase中悬槽,數(shù)據(jù)存儲(chǔ)在表中,表分為行和列护赊。與關(guān)系型數(shù)據(jù)庫不同的是HBase有一個(gè)列族(Column Family)的概念,它將一列或者多列組織在一起砾跃,HBase的列必須屬于某一個(gè)列族骏啰。
對(duì)于HBase中的表而言,有唯一的行鍵Rowkey抽高,每一行對(duì)應(yīng)一列或者多列器一,列中的值可以有多個(gè)版本,受版本厨内。版本指的是祈秕,當(dāng)同Rowkey的數(shù)據(jù)寫入的時(shí)候,根據(jù)時(shí)間戳的不同雏胃,保留的副本數(shù)请毛。一般而言,保留版本數(shù)的方式是在創(chuàng)建表的時(shí)候指定瞭亮,當(dāng)然亦可以后續(xù)修改方仿。如:
hbase(main):004:0> disable 'tabledemo'
hbase(main):005:0> alter 'tabledemo', NAME => 'f2', VERSIONS => 10
Updating all regions with the new schema...
8/8 regions updated.
Done.
0 row(s) in 1.2530 seconds
hbase(main):010:0> enable 'tabledemo'
數(shù)據(jù)模型的重要概念
HBase被稱為無模式數(shù)據(jù)庫,因?yàn)镠Base的表沒有列定義,同時(shí)HBase也不支持表關(guān)聯(lián)仙蚜。以下對(duì)HBase幾種關(guān)鍵的組織模型進(jìn)行介紹:
Namespace(表命名空間):表命名空間不是強(qiáng)制的此洲,當(dāng)想把多個(gè)表分到一個(gè)組去統(tǒng)一管理的時(shí)候才會(huì)用到表命名空間。這個(gè)概念之前沒提到委粉,因?yàn)槌鯇W(xué)者一般用不到呜师,當(dāng)數(shù)據(jù)庫中沒有那么多表的時(shí)候也用不到這個(gè)概念,不過接下來會(huì)在一個(gè)專門的章節(jié)介紹一下這個(gè)概念贾节。
Table(表):一個(gè)表由一個(gè)或者多個(gè)列族組成汁汗。數(shù)據(jù)屬性,比如超時(shí)時(shí)間(TTL)栗涂,壓縮算法(COMPRESSION)等知牌,都在列族的定義中定義。定義完列族后表是空的斤程,只有添加了行角寸,表才有數(shù)據(jù)。
Row(行):一個(gè)行包含了多個(gè)列忿墅,這些列通過列族來分類扁藕。行中的數(shù)據(jù)所屬列族只能從該表所定義的列族中選取,不能定義這個(gè)表中不存在的列族球匕,否則你會(huì)得到一個(gè)NoSuchColumnFamilyException纹磺。由于HBase是一個(gè)列式數(shù)據(jù)庫帖烘,所以一個(gè)行中的數(shù)據(jù)可以分布在不同的服務(wù)器上亮曹。
Column Family(列族):列族是多個(gè)列的集合。其實(shí)列式數(shù)據(jù)庫只需要列就可以了秘症,為什么還需要有列族呢照卦?因?yàn)镠Base會(huì)盡量把同一個(gè)列族的列放到同一個(gè)服務(wù)器上,這樣可以提高存取性能乡摹,并且可以批量管理有關(guān)聯(lián)的一堆列役耕。所有的數(shù)據(jù)屬性都是定義在列族上。在HBase中聪廉,建表定義的不是列瞬痘,而是列族,列族可以說是HBase中最重要的概念板熊。
Column Qualifier(列):多個(gè)列組成一個(gè)行框全。列族和列經(jīng)常用Column Family:Column Qualifier來一起表示。列是可以隨意定義的干签,一個(gè)行中的列不限名字津辩、不限數(shù)量,只限定列族。
Cell(單元格):一個(gè)列中可以存儲(chǔ)多個(gè)版本的數(shù)據(jù)喘沿。而每個(gè)版本就稱為一個(gè)單元格(Cell)闸度,所以在HBase中的單元格跟傳統(tǒng)關(guān)系型數(shù)據(jù)庫的單元格概念不一樣。HBase中的數(shù)據(jù)細(xì)粒度比傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)更細(xì)一級(jí)蚜印,同一個(gè)位置的數(shù)據(jù)還細(xì)分成多個(gè)版本莺禁。
Timestamp(時(shí)間戳/版本號(hào)):你既可以把它稱為是時(shí)間戳,也可以稱為是版本號(hào)晒哄,因?yàn)樗怯脕順?biāo)定同一個(gè)列中多個(gè)單元格的版本號(hào)的睁宰。當(dāng)你不指定版本號(hào)的時(shí)候,系統(tǒng)會(huì)自動(dòng)采用當(dāng)前的時(shí)間戳來作為版本號(hào)寝凌;而當(dāng)你手動(dòng)定義了一個(gè)數(shù)字來當(dāng)作版本號(hào)的時(shí)候柒傻,這個(gè)Timestamp就真的是只有版本號(hào)的意義了。
數(shù)據(jù)模型的操作
HBase對(duì)表的操作
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
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.io.compress.Compression.Algorithm;
public class Example {
private static final String TABLE_NAME = "MY_TABLE_NAME_TOO";
private static final String CF_DEFAULT = "DEFAULT_COLUMN_FAMILY";
public static void createOrOverwrite(Admin admin, HTableDescriptor table) throws IOException {
if (admin.tableExists(table.getTableName())) {
admin.disableTable(table.getTableName());
admin.deleteTable(table.getTableName());
}
admin.createTable(table);
}
public static void createSchemaTables(Configuration config) throws IOException {
try (Connection connection = ConnectionFactory.createConnection(config);
Admin admin = connection.getAdmin()) {
HTableDescriptor table = new HTableDescriptor(TableName.valueOf(TABLE_NAME));
table.addFamily(new HColumnDescriptor(CF_DEFAULT).setCompressionType(Algorithm.NONE));
System.out.print("Creating table. ");
createOrOverwrite(admin, table);
System.out.println(" Done.");
}
}
public static void modifySchema (Configuration config) throws IOException {
try (Connection connection = ConnectionFactory.createConnection(config);
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 = admin.getTableDescriptor(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(CF_DEFAULT);
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, CF_DEFAULT.getBytes("UTF-8"));
// Delete a table (Need to be disabled first)
admin.deleteTable(tableName);
}
}
public static void main(String... args) throws IOException {
Configuration config = HBaseConfiguration.create();
//Add any necessary configuration files (hbase-site.xml, core-site.xml)
config.addResource(new Path(System.getenv("HBASE_CONF_DIR"), "hbase-site.xml"));
config.addResource(new Path(System.getenv("HADOOP_CONF_DIR"), "core-site.xml"));
createSchemaTables(config);
modifySchema(config);
}
}
讀數(shù)據(jù)
Get get = new Get(Bytes.toBytes("row1"));
Result r = htable.get(get);
byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns current version of value
含有版本的Get
Get get = new Get(Bytes.toBytes("row1"));
get.setMaxVersions(3); // will return last 3 versions of row
Result r = htable.get(get);
byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns current version of value
List<KeyValue> kv = r.getColumn(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns all versions of this column
寫數(shù)據(jù)
Put put = new Put(Bytes.toBytes(row));
put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), Bytes.toBytes( data));
htable.put(put);
指明版本
Put put = new Put( Bytes.toBytes(row));
long explicitTimeInMs = 555; // just an example
put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), explicitTimeInMs, Bytes.toBytes(data));
htable.put(put);
刪除數(shù)據(jù)
// Instantiating Delete class
Delete delete = new Delete(Bytes.toBytes("row1"));
delete.deleteColumn(Bytes.toBytes("cf"), Bytes.toBytes("attr1"));
delete.deleteFamily(Bytes.toBytes("cf"));
// deleting the data
table.delete(delete);
scan
HTable htable = ... // instantiate HTable
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("attr"));
scan.setStartRow( Bytes.toBytes("row")); // start key is inclusive
scan.setStopRow( Bytes.toBytes("row" + (char)0)); // stop key is exclusive
ResultScanner rs = htable.getScanner(scan);
try {
for (Result r = rs.next(); r != null; r = rs.next()) {
// process result...
} finally {
rs.close(); // always close the ResultScanner!
}