# 數據模型
在 HBase 中,數據存儲在由行列構成的二維表中。這是與一個關系數據庫(RDBMS)重疊的術語,但這不是一個有幫助的比喻。相反,將 HBase 表視為多維映射會很有幫助。
*HBase 數據模型術語*
**表**
HBase 表由多行組成。
**行**
HBase 中的一行由一個行鍵和一個或多個具有與之關聯的值的列組成。在行存儲時,順序按照字母進行排序。因此,行鍵的設計非常重要。其目標是以相關行彼此靠近的方式存儲數據。常見的行鍵模式是網站域名。如果您的行鍵是域名,則應該反向存儲它們(org.apache.www,org.apache.mail,org.apache.jira)。這樣,所有 Apache 域名都在表中彼此靠近,而不是基于子域名的第一個字母展開。
**列**
HBase 中的列由列族和列限定符組成,它們由`:`(冒號)字符分隔。
**列族**
出于性能原因,列族通常在物理上擁有一簇列及其值。每個列族都有一組存儲屬性,例如是否應將其值緩存在內存中,如何壓縮其數據或對其行鍵進行編碼等。表中的每一行都具有相同的列族,但給定的行可能不會在給定的列族中存儲任何內容。
**列限定符**
列限定符被添加到列族中,以提供給定數據段的索引。給定列族`content`,列限定符可能是`content:html`,另一個可能是`content:pdf`。雖然列族在創建表時是固定的,但列限定符是可變的,并且行之間可能有很大差異。
**單元格**
單元格是行,列族和列限定符的組合,它包含一個值和一個時間戳,時間戳表示值的版本。
**時間戳**
時間戳與每個值一起寫入,它是該值給定版本的標識符。默認情況下,時間戳表示寫入數據時 RegionServer 上的時間,但是當您將數據放入單元格時,可以指定不同的時間戳值。
## 21.概念視角
在Jim R. Wilson的博客文章[了解 HBase 和 BigTable](http://jimbojw.com/#understanding%20hbase) 中,你可以閱讀一篇非常容易理解的關于HBase數據模型的解釋。另一個很好的解釋可以在 Amandeep Khurana 的 [基本模式設計簡介](http://0b4af6cdc2f0c5998459-c0245c5c937c5dedcca3f1764ecc9b2f.r43.cf2.rackcdn.com/9353-login1210_khurana.pdf)中找到。
通過閱讀不同的觀點可能有助于深入了解 HBase 架構設計。鏈接的文章所涉及到的內容與本節中的信息相同。
以下示例是 [BigTable](http://research.google.com/archive/bigtable.html) 論文第 2 頁上的一個略微修改的形式。有一個名為`webtable`的表包含兩行(`com.cnn.www`和`com.example.www`)和三個列族,名為`contents`,`anchor`和`people`。在此示例中,對于第一行(`com.cnn.www`),`anchor`包含兩列(`anchor:cssnsi.com`,`anchor:my.look.ca`),`contents`包含一列(`contents:html`)。此示例包含具有行鍵`com.cnn.www`的行的 5 個版本,以及具有行鍵`com.example.www`的行的一個版本。 `contents:html`列限定符包含給定網站的整個HTML。 `anchor`列族的限定符每個都包含指向該行所代表的站點的外部站點的鏈接,以及它在其鏈接的`anchor`中使用的文本。 `people`列系列表示與該站點關聯的人員。
> 列名
>
> 按照慣例,列名由其列族前綴和*限定符*組成。例如,列 *contents:html* 由列族`contents`和`html`限定符組成。冒號字符(`:`)從列族*限定符*中分隔列族。
*表 6. Table* `webtable`
| 行鍵 | 時間戳 | ColumnFamily `contents` | ColumnFamily `anchor` | ColumnFamily `people` |
| :-- | :-- | :-- | :-- | --- |
| “com.cnn.www” | T9 | | `anchor:cnnsi.com = "CNN"` | |
| "com.cnn.www" | T8 | | `anchor:my.look.ca = "CNN.com"` | |
| "com.cnn.www" | T6 | `contents:html = "<html>…"` | | |
| "com.cnn.www" | T5 | `contents:html = "<html>…"` | | |
| "com.cnn.www" | T3 | `contents:html = "<html>…"` | | |
| “com.example.www” | t5 | `contents:html = "<html>…"` | | `people:author = "John Doe"` |
此表中看起來為空的單元格在 HBase 中不占用空間,或實際上不存在。這就是HBase“稀疏”的原因。表格視圖不是查看 HBase 中數據的唯一方法,甚至也不是最準確的方法。以下表示與多維映射相同的信息。這只是一個出于演示目的的模型,可能并不完全準確。
```
{
"com.cnn.www": {
contents: {
t6: contents:html: "<html>..."
t5: contents:html: "<html>..."
t3: contents:html: "<html>..."
}
anchor: {
t9: anchor:cnnsi.com = "CNN"
t8: anchor:my.look.ca = "CNN.com"
}
people: {}
}
"com.example.www": {
contents: {
t5: contents:html: "<html>..."
}
anchor: {}
people: {
t5: people:author: "John Doe"
}
}
}
```
------
## 22.物理視角
雖然在概念級別,表可以看作一組稀疏的行,但在物理意義上它們是按照列族存儲的。可以隨時將新的列限定符(column_family:column_qualifier)添加到現有列族中。
*表 7. ColumnFamily* `webtable`
| Row Key | Time Stamp | 列族`anchor` |
| --- | --- | --- |
| `"com.cnn.www"` | t9 | `anchor:cnnsi.com = "CNN"` |
| `"com.cnn.www"` | t8 | `anchor:my.look.ca = "CNN.com"` |
*表 8. ColumnFamily* `contents`
| Row Key | Time Stamp | ColumnFamily `contents:` |
| --- | --- | --- |
| `"com.cnn.www"` | t6 | `contents:html = "…?"` |
| `"com.cnn.www"` | t5 | `contents:html = "…?"` |
| `"com.cnn.www"` | t3 | `contents:html = "…?"` |
概念視角中顯示的空單元格不占據物理存儲空間。因此,在時間戳`t8`處對`contents:html`列的值的請求將不返回任何值。類似地,在時間戳`t9`處對`anchor:my.look.ca`值的請求將不返回任何值。但是,如果未提供時間戳,則將返回特定列的最新值。給定多個版本,最新版本也是第一個版本,因為時間戳按降序存儲。因此,如果沒有指定時間戳,則對行`com.cnn.www`中所有列的值的請求將是:來自時間戳`t6`的`contents:html`的值,來自時間戳`t9`的`anchor:cnnsi.com`的值,來自時間戳`t8`的`anchor:my.look.ca`。
有關 Apache HBase 如何存儲數據的內部結構的更多信息,請參見 [regions.arch](#regions.arch) 。
-----
## 23.命名空間
命名空間是與關系數據庫系統中的數據庫類似的表的邏輯分組。這種抽象為即將出現的多租戶相關功能奠定了基礎:
* 配額管理( [HBASE-8410](https://issues.apache.org/jira/browse/HBASE-8410) ) - 限制命名空間可以使用的資源數量(即區域,表)。
* 命名空間安全管理( [HBASE-9206](https://issues.apache.org/jira/browse/HBASE-9206) ) - 為用戶提供另一級別的安全管理。
* 區域服務器組( [HBASE-6721](https://issues.apache.org/jira/browse/HBASE-6721) ) - 可以將命名空間/表固定到 RegionServers 的子集上,從而保證粗粒度的隔離級別。
### 23.1.命名空間管理
一個空間可以被創建,被刪除或被更改。通過指定表單的完全限定表名,在表創建期間確定命名空間成員資格:
```xml
<table namespace>:<table qualifier>
```
*例 7*
```
#Create a namespace
create_namespace 'my_ns'
```
```
#create my_table in my_ns namespace
create 'my_ns:my_table', 'fam'
```
```
#drop namespace
drop_namespace 'my_ns'
```
```
#alter namespace
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
```
### 23.2.預定義的名稱空間
有兩個預定義的特殊命名空間:
* hbase - 系統命名空間,用于包含 HBase 內部表
* default - 沒有明確指定名稱空間的表將自動落入此名稱空間
*例 8*
```
#namespace=foo and table qualifier=bar
create 'foo:bar', 'fam'
#namespace=default and table qualifier=bar
create 'bar', 'fam'
```
----
## 24.表
表在模式定義時預先聲明。
----
## 25.行
行鍵是無解釋的字節。行按字典順序排序,最低順序首先出現在表中。空字節數組用于表示表的名稱空間的開始和結束。
-----
## 26.列族
Apache HBase 中的列分組為列族。列族的所有列成員都具有相同的前綴。例如,列 *courses:history*和*courses:math*都是*courses* 列族的成員。冒號字符(`:`)從列族限定符中分隔列族。列族前綴必須由可打印字符組成。限定符的右部(列族限定符)可以由任意字節組成。列族必須在模式定義時預先聲明,而列不需要在模式定義時定義,且可以在表啟動和運行時動態變化。
從物理上講,所有列族成員都存儲在文件系統中。由于調優和存儲規范是在列族級別完成的,因此建議所有列族成員具有相同的一般訪問模式和大小特征。
-----
## 27.單元格
_{row,column,version}_ 它是一個元組并確切地指定了 HBase 中的`cell`。單元格內容是未解釋的字節
---
## 28.數據模型操作
四個主要的數據模型操作是 Get,Put,Scan 和 Delete。通過[表](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html)實例應用操作。
### 28.1.Get
[Get](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Get.html) 操作返回指定行的屬性。Get操作通過 [Table.get](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#get-org.apache.hadoop.hbase.client.Get-) 執行
### 28.2.Put
[Put](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Put.html) 操作添加到表中的新行(如果鍵是新的)或者可以更新現有行(如果鍵已存在)。 Puts 通過 [Table.put](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#put-org.apache.hadoop.hbase.client.Put-) (非 writeBuffer)或 [Table.batch](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#batch-java.util.List-java.lang.Object:A-) (非 writeBuffer)執行
### 28.3.Scan
[Scan](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html) 允許對指定屬性的多行進行迭代。
下面是對表進行掃描的示例。假設一個表填充了具有鍵“row1”,“row2”,“row3”的行,然后另一組是具有鍵“abc1”,“abc2”和“abc3”的行。以下示例將展示如何設置 Scan 實例以返回以“row”開頭的行。
```java
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Table table = ... // instantiate a Table instance
Scan scan = new Scan();
scan.addColumn(CF, ATTR);
scan.setRowPrefixFilter(Bytes.toBytes("row"));
ResultScanner rs = table.getScanner(scan);
try {
for (Result r = rs.next(); r != null; r = rs.next()) {
// process result...
}
} finally {
rs.close(); // always close the ResultScanner!
}
```
請注意,通常,為掃描指定特定停止點的最簡單方法是使用 [InclusiveStopFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/InclusiveStopFilter.html) 類。
### 28.4.Delete
[Delete](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Delete.html) 操作從表中刪除一行。刪除通過 [Table.delete](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#delete-org.apache.hadoop.hbase.client.Delete-) 執行。
HBase 不會修改現有數據,所以刪除的操作是通過創建名為 *tombstones* 的新標記來處理刪除操作。這些*tombstones* 標記以及刪除的值在主要的壓縮(major compactions)中得到了清理。
有關刪除列版本的更多信息,請參閱 [version.delete](#version.delete) ,有關壓縮的詳細信息,請參閱[compaction](#compaction)。
----
## 29.版本
*{row,column,version}* 元組確切地指定了 HBase 中的`cell`。可以有一個無限數量的單元格,其中行和列相同但單元格地址僅在其版本維度上有所不同。
雖然行和列鍵表示為字節,但版本則使用長整數(long integer)類型指定。通常這個長時間類型包含時間實例,例如`java.util.Date.getTime()`或`System.currentTimeMillis()`返回的時間實例,即:*當前時間與 UTC 時間 1970 年 1 月 1 日午夜之間的差異(以毫秒為單位)*。
HBase版本維度按遞減順序存儲,以便在從存儲文件中讀取時,首先找到最近的值。
在 HBase 中,`cell`版本的語義存在很多混淆。特別是:
* 如果對單元格的多次寫入具有相同的版本,則只能讀取最后寫入的內容。
* 可以按非增加版本順序寫入單元格。
下面我們將介紹 HBase 中的版本維度當前是如何工作的。有關 HBase 版本的討論,請參見 [HBASE-2406](https://issues.apache.org/jira/browse/HBASE-2406) 。HBase 中的[彎曲時間](https://www.ngdata.com/bending-time-in-hbase/)可以很好地讀取 HBase 中的版本或時間維度。它提供了比這里更多的版本控制細節。
在撰寫本文時,文章中提到的限制*覆蓋現有時間戳的值*不再適用于 HBase。本節基本上是由 Bruno Dumon 撰寫的概要。
### 29.1.指定要存儲的版本數
為給定列存儲的最大版本數是列架構的一部分,該值在表創建時指定,或通過`alter`命令,或通過`HColumnDescriptor.DEFAULT_VERSIONS`指定。在 HBase 0.96 之前,保留的默認版本數為`3`,但是在 0.96 中,更新版本已更改為`1`。
例 9.修改列族的最大版本數
> 此示例使用 HBase Shell 在列族`f1`中保留所有列的最多 5 個版本。您也可以使用 [HColumnDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HColumnDescriptor.html) 。
>
> ```shell
> hbase> alter ‘t1′, NAME => ‘f1′, VERSIONS => 5
> ```
>
例 10.修改列族的最小版本數
>您還可以指定每個列族存儲的最小版本數。默認情況下,此值設置為 0,表示該功能已禁用。以下示例通過 HBase Shell 將列族`f1`中所有列的最小版本數設置為`2`。您也可以使用 [HColumnDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HColumnDescriptor.html) 。
>
>```shell
>hbase> alter ‘t1′, NAME => ‘f1′, MIN_VERSIONS => 2
>```
>
從 HBase 0.98.2 開始,您可以通過在 *hbase-site.xml* 中設置`hbase.column.max.version`,為所有新創建的列指定的最大版本數指定全局默認值。參見 [hbase.column.max.version](#hbase.column.max.version) 。
### 29.2.版本和 HBase 操作
在本節中,我們將查看每個HBase 核心操作的版本維度的行為。
#### 29.2.1.Get/Scan
Get是在 Scans 之上實現的。以下對 [Get](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Get.html) 的討論同樣適用于[掃描](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html)。
默認情況下,即如果未指定顯式版本,則在執行`get`時,將返回版本具有最大值的單元格(可能是也可能不是最新編寫的單元格,請參閱后面的內容)。可以通過以下方式修改默認行為:
* 要返回多個版本,請參閱 [Get.setMaxVersions()](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Get.html#setMaxVersions--)
* 要返回最新版本以外的其他版本,請參見 [Get.setTimeRange()](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Get.html#setTimeRange-long-long-)
要檢索小于或等于給定值的最新版本,從而在某個時間點給出記錄的“最新”狀態,只需使用從 0 到所需版本的范圍,并將最大版本設置為 1 。
#### 29.2.2.默認版本的Get示例
以下 Get 將僅檢索行的當前版本
```java
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR); // returns current version of value
```
#### 29.2.3.給定版本的Get示例
以下 Get 將返回該行的最后 3 個版本。
```java
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
get.setMaxVersions(3); // will return last 3 versions of row
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR); // returns current version of value
List<KeyValue> kv = r.getColumn(CF, ATTR); // returns all versions of this column
```
#### 29.2.4.Put
執行 put 總是在某個時間戳創建`cell`的新版本。默認情況下,系統使用服務器的`currentTimeMillis`,但您可以在針對每一列指定版本(=長整數)。這意味著您可以在過去或將來指定時間,或者將long值用于非時間目的。
要覆蓋現有值,請在與要覆蓋的單元格完全相同的行,列和版本上執行 put。
**隱式版本示例**
HBase 將使用當前時間隱式地對以下 Put 進行版本控制。
```java
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put(Bytes.toBytes(row));
put.add(CF, ATTR, Bytes.toBytes( data));
table.put(put);
```
**顯式版本示例**
以下 Put 具有顯式設置的版本時間戳。
```java
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put( Bytes.toBytes(row));
long explicitTimeInMs = 555; // just an example
put.add(CF, ATTR, explicitTimeInMs, Bytes.toBytes(data));
table.put(put);
```
注意:HBase 內部使用版本時間戳來處理生存時間計算等事情。通常最好避免自己設置此時間戳。首選使用行的單獨時間戳屬性,或將時間戳作為行鍵的一部分,或兩者都使用。
#### 29.2.5.Delete
有三種不同類型的內部刪除標記。請參閱 Lars Hofhansl 的博客,討論他試圖添加另一個,[掃描 HBase:前綴刪除標記](http://hadoop-hbase.blogspot.com/2012/01/scanning-in-hbase.html)(Scanning in HBase: Prefix Delete Marker)。
* 刪除:對于特定版本的列。
* 刪除列:適用于列的所有版本。
* 刪除系列:適用于特定 ColumnFamily 的所有列
刪除整行時,HBase 將在內部為每個 ColumnFamily 創建一個tombstone(邏輯刪除標記),而不是每個單獨的列。
通過創建*tombstone*標記刪除工作。例如,假設我們要刪除一行。為此您可以指定版本,否則默認使用`currentTimeMillis`。這意味著 *刪除版本小于或等于此版本的所有單元格*。 HBase 從不在原址修改數據,因此例如delete操作不會立即刪除(或標記為已刪除)存儲文件中與delete條件相對應的條目。相反,標記一個tombstone標志,它將屏蔽刪除的值。當HBase進行主要壓縮時,將處理tombstone來實際刪除值,同時刪除tombstone標記。如果刪除行時指定的版本大于行中任何值的版本,則刪除整行。
有關刪除和版本控制如何交互的信息性討論,請參閱用戶郵件列表中的思路 [Put w / timestamp→Deleteall→Put w / timestamp failed](http://comments.gmane.org/gmane.comp.java.hadoop.hbase.user/28421) 。
有關內部 KeyValue 格式的更多信息,另請參見 [keyvalue](#keyvalue) 。
除非在列族中設置`KEEP_DELETED_CELLS`選項,否則在下一次主要壓縮存儲期間將清除刪除標記(請參閱[保留已刪除的單元格](#cf.keep.deleted)。要將刪除保留一段可配置的時間,可以通過 *hbase-site.xml* 中的 `hbase.hstore.time.to.purge.deletes` 屬性設置刪除 TTL。如果未設置`hbase.hstore.time.to.purge.deletes`或設置為 0,則在下一次主要壓縮過程中將清除所有刪除標記,包括將來具有時間戳的標記。否則,將保留具有將來時間戳的刪除標記,直到在標記的時間戳加上`hbase.hstore.time.to.purge.deletes`的值所表示的時間之后發生的主要壓縮,以毫秒為單位。
> HBase 0.94中此行為表示對引入的意外更改的修復,在 [HBASE-10118](https://issues.apache.org/jira/browse/HBASE-10118) 中得到修復。該變更已被移植到 HBase 0.94 和更新的分支機構。
### 29.3.HBase-2.0.0 中的可選新版本和刪除行為
在`hbase-2.0.0`中,操作員可以通過將列描述符屬性`NEW_VERSION_BEHAVIOR`設置為 true 來指定備用版本和刪除處理(要在列族描述符上設置屬性,必須先禁用該表,然后更改列族描述符);有關編輯列族描述符屬性的示例,請參閱[保留已刪除單元格](#cf.keep.deleted)。
“新版本行為”撤消了下面列出的限制,即如果在同一位置,`Delete`操作總是屏蔽`Put`操作(在相同的行,列族,限定符和時間戳,而無論哪個首先到達)。版本統計也會更改,因為已刪除的版本被視為總版本計數。這樣做是為了確保在主要的壓縮過程中不會改變結果。有關討論請參閱`HBASE-15968`以及鏈接的問題。
目前使用這種新配置運行成本;每次比較時,我們都將計算單元MVCC分解,從而消耗更多的CPU。在測試中,我們發現性能下降在 0%到 25%之間。
如果復制,建議您使用新的串行復制特性(請參閱`HBASE-9465`;串行復制功能未進入`hbase-2.0.0`但應該在后續的 hbase-2.x 版本中發布),就像現在一樣,突變到達的順序是一個關鍵因素。
### 29.4.目前的限制
以下限制在 hbase-2.0.0 中得到解決。請參閱上面的部分,[可選新版本和 HBase-2.0.0中的刪除行為](#new.version.behavior)。
#### 29.4.1.Deletes屏蔽Puts
Deletes操作屏蔽Puts操作,甚至Puts操作發生在Deletes操作之后。參見 [HBASE-2256](https://issues.apache.org/jira/browse/HBASE-2256) 。請記住,刪除會寫一個tombstone(邏輯刪除標記),這個tombstone只有在下一次主要壓縮運行后才會消失。假設你刪除了所有內容?T。在此之后你運行了一個帶有時間戳?T 的新 put。這個 put,即使它發生在刪除之后,也會被刪除tombstone標記屏蔽。同時執行put操作并不會失敗,但是當執行get時,您會注意到put操作沒有作用。在主要壓縮運行后它將再次開始工作。如果您對行添加使用始終增加的版本,則這些問題不應成為問題。但即使你不關心時間,它們也會發生:在完成刪除并立刻進行put操作時,它們兩個操作有可能在同一毫秒內發生。
#### 29.4.2.主壓縮會更改查詢結果
*...在 t1,t2 和 t3 創建三個單元版本,最大版本設置為 2.因此,在獲取所有版本時,僅返回 t2 和 t3 處的值。但是如果你在 t2 或 t3 刪除了版本,t1 上的版本將再次出現。顯然,一旦主壓縮運行,這樣的行為將不再存在......(參見 [ HBase中的彎曲時間](https://www.ngdata.com/bending-time-in-hbase/) 中的垃圾回收部分)*
## 30.排序順序
HBase 中所有數據模型的操作都將按照排序順序返回數據。首先是行,然后是列族,后面是列限定符,最后是時間戳(反向排序,因此首先返回最新的時間戳)。
## 31.列的元數據
列族的內部 KeyValue 實例之外沒有列的元數據存儲。因此,盡管 HBase 不僅可以支持每行的大量列,而且還可以支持行之間的異構列,因此有必要跟蹤列名。
獲取列族存在的完整列集合的唯一方法是處理所有行。有關 HBase 如何在內部存儲數據的更多信息,請參閱 [keyvalue](#keyvalue) 。
## 32.Joins
HBase是否支持join操作是發行版列表上的一個常見問題,這有一個簡單的答案:它不能,至少在RDBMS支持它們的方式上是這樣(例如,在 SQL 中使用 equi-joins 或 outer-joins)。如本章所述,HBase 中的讀取數據模型操作是 Get 和 Scan。
但是,這并不意味著您的應用程序不支持等值連接功能,但必須自己實現。向HBase寫入數據時有兩種主要策略,一種是反規范化數據,另一種是在應用程序或MapReduce代碼中有查找表并以此在HBase表之間進行連接(并且正如 RDBMS 所示,有幾種策略可以根據大小而定這些表,例如,嵌套循環與散列連接)。那么哪種方法最好?這取決于你想要做什么,因此沒有一個答案適用于每個用例。
## 33.ACID
參見 [ACID 語義](/acid-semantics.html)。更多的,可以參考Lars Hofhansl 寫的一份關于[HBase中ACID](http://hadoop-hbase.blogspot.com/2012/03/acid-in-hbase.html)的筆記。
- HBase? 中文參考指南 3.0
- Preface
- Getting Started
- Apache HBase Configuration
- Upgrading
- The Apache HBase Shell
- Data Model
- HBase and Schema Design
- RegionServer Sizing Rules of Thumb
- HBase and MapReduce
- Securing Apache HBase
- Architecture
- In-memory Compaction
- Backup and Restore
- Synchronous Replication
- Apache HBase APIs
- Apache HBase External APIs
- Thrift API and Filter Language
- HBase and Spark
- Apache HBase Coprocessors
- Apache HBase Performance Tuning
- Troubleshooting and Debugging Apache HBase
- Apache HBase Case Studies
- Apache HBase Operational Management
- Building and Developing Apache HBase
- Unit Testing HBase Applications
- Protobuf in HBase
- Procedure Framework (Pv2): HBASE-12439
- AMv2 Description for Devs
- ZooKeeper
- Community
- Appendix