HBase的數(shù)據(jù)模型

簡(jiǎn)述

在HBase中悬槽,數(shù)據(jù)存儲(chǔ)在表中,表分為行和列护赊。與關(guān)系型數(shù)據(jù)庫不同的是HBase有一個(gè)列族(Column Family)的概念,它將一列或者多列組織在一起砾跃,HBase的列必須屬于某一個(gè)列族骏啰。


數(shù)據(jù)模型

對(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!
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末较木,一起剝皮案震驚了整個(gè)濱河市红符,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伐债,老刑警劉巖预侯,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異峰锁,居然都是意外死亡萎馅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門虹蒋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糜芳,“玉大人,你說我怎么就攤上這事魄衅∏涂ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵晃虫,是天一觀的道長(zhǎng)皆撩。 經(jīng)常有香客問我,道長(zhǎng)哲银,這世上最難降的妖魔是什么扛吞? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮荆责,結(jié)果婚禮上滥比,老公的妹妹穿的比我還像新娘。我一直安慰自己草巡,他們只是感情好守呜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布型酥。 她就那樣靜靜地躺著,像睡著了一般查乒。 火紅的嫁衣襯著肌膚如雪弥喉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天玛迄,我揣著相機(jī)與錄音由境,去河邊找鬼。 笑死蓖议,一個(gè)胖子當(dāng)著我的面吹牛虏杰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勒虾,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼纺阔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了修然?” 一聲冷哼從身側(cè)響起笛钝,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎愕宋,沒想到半個(gè)月后玻靡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡中贝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年囤捻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邻寿。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝎土,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出老厌,到底是詐尸還是另有隱情瘟则,我是刑警寧澤黎炉,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布枝秤,位于F島的核電站,受9級(jí)特大地震影響慷嗜,放射性物質(zhì)發(fā)生泄漏淀弹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一庆械、第九天 我趴在偏房一處隱蔽的房頂上張望薇溃。 院中可真熱鬧,春花似錦缭乘、人聲如沸沐序。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽策幼。三九已至邑时,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間特姐,已是汗流浹背晶丘。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唐含,地道東北人浅浮。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像捷枯,于是被迫代替她去往敵國(guó)和親滚秩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349