使用Apache HBase處理海量數據深入學習

近些年來,NoSQL發展趨勢越發高漲,是因爲web2.0的興起,傳統的關系型數據庫(sql)已經對大規模高並發顯得力不從心,在處理漲量數據問題,NoSQL更能勝任

過去的幾年中,在多種方式的數據存儲和查詢上,我們都看到了真正意義上的爆炸式發展。其中被稱爲NoSQL的數據庫站在了改革的前沿,正在形成新的持久化存儲備選方案。NoSQL的流行很大程度應當歸功于如Google、Amazon、Twitter和Facebook等大型公司,因爲他們聚集了大量的數據需要進行保存、查詢和分析。且越來越多的公司正在收集海量的數據,並且需要能夠有效的全部利用來充實自己的業務。例如社交網路需要分析用戶直接的社交關系並對關系用戶進行推薦,同時幾乎每個大型網站都有自己的推薦引擎向你推薦可能想要購買的商品。當數據積累越來越多,他們需要一個簡單的方式來擴展整個系統而不是重新構建。
從19世紀70年代開始,關系型數據庫 (RDBMS)幾乎統治了數據管理場景。但是當業務不斷擴大,存儲和處理的數據量也不斷增長,關系型數據庫越來越難以擴展。一開始你可能從單機到主從節點,然後再數據庫之上加入一道緩存層用于存儲載入熱點讀寫數據。當查詢效能降低時,索引(indexes)常常是首先被丟棄的,接下來根據反範式( Denormalization )迅速避免關聯(joins),因爲該操作會很大程度消耗效能。之後你可能評估最耗效能的一些查詢,修改使得這些查詢能夠變成有效的主鍵查詢,或者將大表中的數據分布到多個數據庫切片中(shards)。這個時候,你再回顧一下,會發現關系型數據庫的很多關鍵優勢已經被放棄了——引用完整性(referential integrity)、事務(ACID transactions)、索引(indexes)等等。當然,這裏描述的場景是在你的業務非常成功的情況下,發展很快速需要處理越來越多的數據,持續以高比例增長的數據。換句話說,你就是下一個Twitter。
你是嗎?也許你正研究一個環境監測專案,需要部署一個世界範圍內的傳感器網路,而所有的傳感器會産生海量的數據。又或者你在研究DNA序列。假如你明白或者認爲你要面對海量數據存儲需求,有數十億行及數百萬列的情況,你應該考慮HBase。這類新數據庫設計初衷就是在商業伺服器集群中能夠完成從基礎建設到水平擴展階段,而不需要垂直擴展設法去買更高級的機器(而且最終還是可能沒法買到更好的機器)。
初入HBase
HBase是一個能夠提供及時、隨機讀寫,能夠存儲數十億行和數百萬列的數據庫。它設計是要運行于一個商業伺服器的集群之上,當新伺服器添加之後能夠自動擴展,還能保證同樣的效能。另外,還要有很高的容錯性,因爲數據是分割至伺服器集群中,保存在一個冗余的文件系統比如HDFS。當某些伺服器異常時,你的數據仍然是安全的。這些數據會在當前活動的伺服器中自動均衡直到替換伺服器上線。HBase是高一致性的數據存儲。你修改的內容能夠馬上在其他所有的客戶前展示。
HBase是在谷歌的Bigtable之後建立的,谷歌在2006年發布了一份論文“稀疏的、分布式的、持久化多維排序圖”。所以如果你習慣了關系型數據庫,HBase初看來很陌生。還有表的概念,卻不同于關系型數據庫的表。不支持典型的關系型數據庫概念如:關聯(joins)、索引(indexes)、事務(ACID transactions)等。但你放棄了這些特性,卻得到了擴展性和容錯性。HBase實質是一個帶有自動數據版本控制的鍵值(key-value)存儲。
你能夠按照你希望的那樣進行增刪改查的操作。也能夠在HBase的表中按照順序掃描數據行。當在HBase中進行數據掃描時,數據行總是按照行主鍵(row key)順序返回。每行數據都由一個唯一排序後的行主鍵(可以認爲是關系型數據庫的主鍵)和任意數量的列,每列都屬于一個列簇(column family)並且包含一個或多個版本的值。值都是簡單的二進制數組,根據應用需要可以轉換成需要展示或存儲的形式。HBase並未試圖對開發者隱藏面向列的數據模型,而且Java 的API顯然比其他你可能使用的接口更加底層。比如JPA,甚至JDBC都比HBase的API更加抽象。HBase的操作基本在原生的層面。
我們來了解如何通過命令行使用HBase。HBase自帶基于JRuby開發的shell工具,能夠定義和管理表、對數據執行增刪改查操作、掃描表以及執行一些相關的維護。進入shell後,輸入help就能獲得完整的幫助信息。也可以使用 help <group> 命令來獲得指定命令或者命令組的幫助信息。例如,help ‘create’ 就提供了關于創建新表的幫助信息。HBase在産品環境中應該部署到伺服器集群中,但也可以下載下來然後啓動運行一個單機模式,只需要花幾分鍾時間。第一件要做的事情就是使用HBase的shell。下面的示例中演示了通過shell新建一個博客表、展示HBase中的有效表、添加一個博客實體、查詢該實體以及掃描博客表。

代碼如下
$ bin/hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Type "exit<RETURN>" to leave the HBase Shell
Version 0.96.0-hadoop2, r1531434, Fri Oct 11 15:28:08 PDT 2013

hbase(main):001:0> create 'blog', 'info', 'content'
0 row(s) in 6.0670 seconds

=> Hbase::Table - blog

hbase(main):002:0> list
TABLE
blog
fakenames
my-table
3 row(s) in 0.0300 seconds

=> ["blog", "fakenames", "my-table"]

hbase(main):003:0> put 'blog', '20130320162535', 'info:title', 'Why use HBase?'
0 row(s) in 0.0650 seconds

hbase(main):004:0> put 'blog', '20130320162535', 'info:author', 'Jane Doe'
0 row(s) in 0.0230 seconds

hbase(main):005:0> put 'blog', '20130320162535', 'info:category', 'Persistence'
0 row(s) in 0.0230 seconds

hbase(main):006:0> put 'blog', '20130320162535', 'content:', 'HBase is a column-oriented...'
0 row(s) in 0.0220 seconds

hbase(main):007:0> get 'blog', '20130320162535'
COLUMN CELL
content: timestamp=1386556660599, value=HBase is a column-oriented...
info:author timestamp=1386556649116, value=Jane Doe
info:category timestamp=1386556655032, value=Persistence
info:title timestamp=1386556643256, value=Why use HBase?
4 row(s) in 0.0380 seconds

hbase(main):008:0> scan 'blog', { STARTROW => '20130300', STOPROW => '20130400' }
ROW COLUMN+CELL
20130320162535 column=content:, timestamp=1386556660599, value=HBase is a column-oriented...
20130320162535 column=info:author, timestamp=1386556649116, value=Jane Doe
20130320162535 column=info:category, timestamp=1386556655032, value=Persistence
20130320162535 column=info:title, timestamp=1386556643256, value=Why use HBase?
1 row(s) in 0.0390 seconds


上面的命令中,我們首先新建了一個包含列簇info 和 content的博客表。列出所有的表並且看到我們新建的博客表以後,我們向表中添加了一些數據。put命令指定了表名,唯一行主鍵,列簇的主鍵由列簇名和限定名(qualifier)組成,例如info是列簇名,而title和author就是限定名。所以,info:title就指向在列簇info中值爲“Why use HBase?”的列title,info:title同樣也被作爲列主鍵。接下來,我們使用命令查詢一行單獨數據,並且最終在一個限定的行主鍵範圍內掃描了博客表數據。指定了開始行20130300(包含)和結束行20130400 (不包含),和你預想的一樣,我們能夠查詢到在此範圍內的所有數據。上面博客的例子中,因爲行主鍵就是發布的時間,所以實際上包含了所有2013三月份的數據。
HBase的一個重要特性就是,你定義了列簇,然後根據列限制名,可以再列簇中添加任意數量的列。HBase優化了磁盤的列存儲方式,不存在的列不會占用空間,這樣使得存儲更有效率。而關系型數據庫缺必須保存一個空值(null)數據。數據行是由包含的列組成的,所以如果行中沒有任何列理論上它是不存在的。接著上面的列子,下面會從一個數據行中刪除一些指定的列。

代碼如下
hbase(main):009:0> delete 'blog', '20130320162535', 'info:category'
0 row(s) in 0.0490 seconds

hbase(main):010:0> get 'blog', '20130320162535'
COLUMN CELL
content: timestamp=1386556660599, value=HBase is a column-oriented...
info:author timestamp=1386556649116, value=Jane Doe
info:title timestamp=1386556643256, value=Why use HBase?
3 row(s) in 0.0260 seconds


如上所示,你能夠從表中刪除一個指定列如info:category。你也可以使用deleteall命令刪除一行中的所有列,從而刪除這行數據。更新數據的話,只需要再次使用put命令即可。HBase默認會保持單列三個版本的數據,所以假如你向 info:title put了一個新值,HBase會同時保留新舊兩個值。
上面例子中的命令展示了如何在HBase中增、刪、改、查數據。數據查詢只有兩種方式:使用get命令查詢單行數據;通過scan查詢多行數據。在HBase中查詢數據時,你應當注意只查詢你需要的信息。由于HBase是從每個列簇中分別獲取數據,如果你只需要一個列簇的數據,就能夠指定只獲取該部分。下面的例子中,我們只查詢博客 title 列,指定行主鍵範圍爲2013年3月到4月。

代碼如下
hbase(main):011:0> scan 'blog', { STARTROW => '20130300', STOPROW => '20130500', COLUMNS => 'info:title' }
ROW COLUMN+CELL
20130320162535 column=info:title, timestamp=1386556643256, value=Why use HBase?
1 row(s) in 0.0290 seconds


通過設置行主鍵範圍、限制需要的列名稱、需要查詢的數據版本,你能夠優化HBase的數據訪問。當然上面的例子中,全都是通過shell完成的,你也能夠使用HBase的API完成相同甚至更多的事情。
HBase是一個分布式數據庫,原本是設計運行在上千台甚至更多的伺服器集群中。因此,HBase的安裝自然比在單台伺服器上安裝一套獨立的關系型數據庫更加複雜。同時,所有分布式計算中都存在的典型問題HBase也不能避免,比如遠程處理的合作與管理、鎖、數據分布、網路延遲以及伺服器間的交互。好在HBase利用了很多成熟技術,比如Apache Hadoop和Apache ZooKeeper解決了很多類似的問題。下面的圖中展示了HBase的主要架構組件。

使用Apache HBase處理海量數據深入學習

上圖中可以看到,存在單個HBase主節點以及多個域伺服器。(HBase可以運行在多主節點集群中,但同時只會有單個活動主節點)。HBase的表分割並存儲在多個域中,每個域保存表中一定範圍數據,由主節點將多個域分配至一個域伺服器。
HBase是一個面向列的存儲,即數據按照列存儲而不是行。這樣使得數據訪問方式比面向行的傳統數據存儲系統更加高效。例如HBase中如果列簇中不包含數據,則根本不會存儲任何信息。而對于一個關系型數據庫來說,則會存儲null值。另外,若在HBase中查詢數據,只需要指定你需要的列簇,因爲在一行數據中可能存在上百萬行數據,你需要確定你只查詢自己需要的數據。
HBase使用ZooKeeper(分布式協作服務)來管理域分配至域伺服器,以及在域伺服器崩潰時,能夠通過將崩潰的域伺服器中的域載入至其他有效的域伺服器上來恢複功能。
域包括記憶體數據(MemStore)以及持久化數據(HFile),域伺服器中的所有域共用一個先寫日志(write-ahead log [WAL]),該日志用于在還未持久化存儲前保存新數據,並且當域伺服器崩潰後能夠恢複數據。每個域都保存了一定範圍內的行主鍵,當域包含的數據量超過定義的範圍時,HBase會將域分割至兩個子域,這樣就擴展了HBase。
當表增大時,集群中會構建和分割出越來越多的域。當用戶查詢一個指定行主鍵或者指定範圍內的主鍵,HBase給出這些主鍵所在的域,用戶可以直接與這些域存在的域伺服器通信。這樣的設計最小化搜索指定行時可能出現的問題的數量,並且優化了數據回傳時HBase的磁盤傳輸。關系型數據庫則可能在從磁盤回傳數據之前要進行大規模的磁盤掃描,甚至在有索引建立的情況下也一樣。
HDFS組件使用了Hadoop分布式文件系統,分布式、高容錯性、可擴展文件系統用于防止數據丟失,能夠將數據切分爲塊且分散在整個集群中,這是HBase實際存儲數據的地方。嚴格來說只要實現了Hadoop文件系統的API的任何形式數據都可以被純粹,一般來說HBase會發布在運行了HDFS的Hadoop集群中。實際上,當你第一次在單機上下載和安裝HBase時,如果你沒用修改配置,使用的就是本地文件系統。
用戶通過有效的API與HBase交互時,包括本地Java API、基于REST的接口和一些RPC接口(Apache Thrift, Apache Avro)。也可以通過Groovy, Jython, 和Scala來訪問接口(Domain Specific Language [DSL])

之前學習了HBase的整體架構,現在了解一下我們的應用如何通過Java API與HBase進行交互。如同之前提到的,你也同樣可以通過其他的RPC(Remote Procedure Call)技術手段與HBase交互,比如Apache Thrift通過REST網關的方式,但我們主要使用Java API的方式。API提供了DDL(數據定義語言)和DML(數據操作語言)你會發現和關系型數據庫SQL的語言很相似。假設我們要存儲用戶信息,我們先開始建立一張新表。下列代碼展示如何使用HBaseAdmin類。

代碼如下
Configuration conf = HBaseConfiguration.create();
HBaseAdmin admin = new HBaseAdmin(conf);
HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf("people"));
tableDescriptor.addFamily(new HColumnDescriptor("personal"));
tableDescriptor.addFamily(new HColumnDescriptor("contactinfo"));
tableDescriptor.addFamily(new HColumnDescriptor("creditcard"));
admin.createTable(tableDescriptor);


用戶表定義包含三個列簇:個人信息、聯系信息以及信用卡。你需要用HTableDescriptor構建一張表,並且使用HColumnDescriptor添加一個或多個列簇。然後調用createTable方法建表。完成之後來添加一些數據。下面的代碼展示了如何使用Put類插入John Doe的數據,指定名稱和電子郵件指定(爲了簡單期間,這裏忽略了通常應該有的錯誤處理)

代碼如下
Configuration conf = HBaseConfiguration.create();
HTable table = new HTable(conf, "people");
Put put = new Put(Bytes.toBytes("doe-john-m-12345"));
put.add(Bytes.toBytes("personal"), Bytes.toBytes("givenName"), Bytes.toBytes("John"));
put.add(Bytes.toBytes("personal"), Bytes.toBytes("mi"), Bytes.toBytes("M"));
put.add(Bytes.toBytes("personal"), Bytes.toBytes("surame"), Bytes.toBytes("Doe"));
put.add(Bytes.toBytes("contactinfo"), Bytes.toBytes("email"), Bytes.toBytes("john.m.doe@gmail.com"));
table.put(put);
table.flushCommits();
table.close();


上面的代碼中示例是Put類提供了唯一行主鍵作爲構造方法參數。接下來我們會添加值,必須包括列簇、列標識符、二進制數組形式的值。或許你會注意到,HBase API的常用工具類中的Bytes類是經常用到的,它提供了一些方法能夠在原始類型、字符串與二進制數組間轉換。(添加一個toBytes()靜態引用方法能夠節省大堆代碼)接下來我們將數據存入表中,刷新提交確認本地緩存的改變能夠生效,最終關閉表。更新數據也和之前展示的代碼方式相同。與關系型數據庫不同,HBase即使只有一列改變也必須更新整行數據。假如你只需要更新一列,只需要在Put類和HBase中指定需要更新的列。也會有確認並更新的動作,本質上就是一系列並發操作,只是在用戶確認待替換的值之後才進行更新動作。
如下面的代碼所示,使用Get類來查詢我們剛剛創建完成的數據。(從這裏開始,會忽略一些代碼如構建配置,實例化HTable、提交及關閉)

代碼如下
Get get = new Get(Bytes.toBytes("doe-john-m-12345"));
get.addFamily(Bytes.toBytes("personal"));
get.setMaxVersions(3);
Result result = table.get(get);


上面的代碼中實例化了Get類,並且提供了待查詢的行主鍵。接下來我們通過 addFamily 方法告知HBase:我們只需要從個人信息列簇中獲取數據。這樣能夠減少HBase在讀取數據時與磁盤的交互。我們還指定了結果中每列最多保存三個版本,這樣就能列出每列的曆史數據。最終會返回一個結果實例,包含所有可以查看的返回值列。
很多情況下你需要查詢多行數據,HBase使用掃描行來實現。正如在第二篇在HBase的shell工具中執行scan,下面主要討論Scan類。Scan類支持多種條件選項,比如待查詢的行主鍵範圍、需要包含的列和列簇、以及需要展示的最大數據版本。你也可以添加一個過濾器,通過自定義過濾邏輯限制需要返回哪些行和列。過濾器的常用場景就是分頁,例如我們可能想要獲取所有的姓Smith的人,每次一頁25人。下面的代碼展示了如何使用基本的scan方法。

代碼如下
Scan scan = new Scan(Bytes.toBytes("smith-"));
scan.addColumn(Bytes.toBytes("personal"), Bytes.toBytes("givenName"));
scan.addColumn(Bytes.toBytes("contactinfo"), Bytes.toBytes("email"));
scan.setFilter(new PageFilter(25));
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// ...
}


上面的代碼中,我們新建了一個Scan類,查詢以 smith- 開頭的行主鍵,使用 addColumn 來限制返回的列(這樣就能夠減少HBase與磁盤磁盤傳輸)爲 personal:givenName 和 contactinfo:email 兩列。scan中的PageFilter用于限制掃描的行數爲25.(也可以考慮使用在Scan構造函數中指定結束行主鍵的分頁過濾器)。我們使用結果掃描類來查看剛才的結果,循環並執行業務動作。在HBase中,唯一查詢多行數據的方式就是根據排序的行主鍵掃描,因此如何設計行主鍵就顯得很重要。稍候會對此再進行討論。
你也可以使用Delete類刪除HBase中的數據,和Put類相似刪除了一行中的所有列(意味著完全刪除了行),刪除了列簇、列、等類似的組合。
處理連接
上面的示例對如何處理連接以及遠程調用(RPC)沒有太多關注。HBase提供了HConnection類用于提供類似于連接池的功能共用連接,例如你使用 getTable() 方法來獲得一個HTable實例的引用。同樣,也有一個HConnectionManager類提供HConnection實例。類似Web應用中避免網路頻繁交換,可以有效地管理RPC的數量。在使用HBase時,返回的海量數據這類的問題很重要的。編寫HBase應用時要考慮類似的問題。

HBase不同于關系型數據庫比如SQL,有豐富的查詢能力。相反,它放棄了這樣的能力,以及其他的比如關系,join等。將注意力集中在提供高效能的擴展性和故障恢複。在使用HBase的時候需要根據行數據和列簇設計表結構和行主鍵以符合應用程序的數據訪問模式。這與你在關系型數據庫中完全不同,在關系型數據庫中,從一個普通的數據庫結構開始,獨立的表,使用SQL來使用joins等來組織需要的數據。在HBase中設計表式特別要考慮應用將會如何使用,預先設計數據的訪問方式。使用HBase而不是關系型數據庫能夠讓你更加接近底層的抽象實現細節和存儲機制。總之,應用能夠存儲海量數據,高擴展性,高效能以及伺服器容錯性,潛在的益處大大超過了投入。
在之前關于Java API的章節中,有提到過當在HBase中掃描數據時,行主鍵是很關鍵的,因爲它是限制行掃描數據的主要方式。HBase中也沒有類似關系型數據庫中SQL那種富查詢方式。常規做法就是構建一個設置了起始和結束行主鍵的掃描任務,可選的加入一些過濾器來進一步限制返回的行與列數據。爲了在掃描時能夠有較高的靈活性,設計主鍵時應該包括一些需要查詢的數據內容的子集。在人員和博客這個我們一直使用的例子中,行主鍵被設計成掃描時最常用的訪問方式。例如博客,原本行主鍵就是發布日期。這樣就能夠以時間升序的方式掃描展示博客文章,但這可能不是查看博客最常見的模式。所以比較好的行主鍵設計使用時間戳的逆序,使用公式(Long.MAX_VALUE – timestamp , Long長整型的最大值減去時間戳即爲時間戳逆序),這樣掃描時就會先返回最近發布的博客文章。這樣也能夠比較方便的掃描指定的時間區間,例如掃描展示過去一周或者一月的所有博客文章,在web應用中是很常見的做法。
以人員表爲例,我們使用複合主鍵,由姓、名、中名首字母以及個人身份識別碼(唯一),中間以連字符連接,來區別重名的人員。例如 Brian M. Smith 身份識別碼爲 12345 的人員行主鍵爲smith-brian-m-12345。掃描人員表時指定的開始與結束行主鍵組合,可以查詢指定姓的人員,姓的開頭爲指定字母組合的人員,或者有相同的姓,和名首字母的人員。例如,你希望找到姓爲Smith,名的首字母爲B的人員,可以使用smith-b爲開始行主鍵,smith-c爲結束行主鍵(開始行主鍵是包含的,而結束行主鍵不包含,所以能夠保證姓爲Smith,名的首字母爲B的人員都包含在掃描中)。能夠看到HBase支持部分主鍵的概念,意味著你不需要指定確切的主鍵,能夠爲創建合適的掃描範圍提供較高的靈活性。你能夠使用部分主鍵掃描和過濾器的組合來只查詢你需要的特定數據,能夠優化數據查詢,爲你的應用提供合適的數據訪問模式。
至此樣例中式操作了包含一類信息的單表,沒有其他關聯。HBase沒有類似關系型數據庫的外鍵關系,但是由于它單行數據支持數百萬列,所以HBase設計表時的一種方式就是將所有的關聯信息都保存在同一行中–稱之爲寬表設計。之所以稱之爲寬表,因爲你將所有關聯的數據都保存在單行數據中,數據列可能和數據項一樣多。在我們的博客例子中,你可能需要保存每篇文章的評論。根據寬表設計原則,可以設計一個列簇名爲評論,使用評論時間作爲列標識。這樣評論的列名形式爲 comments:20130704142510 和 comments:20130707163045。HBase查詢數據時,返回的列能夠按照一定原則排序,就像行主鍵一樣。所以爲了展示一篇博文和它所有的評論,你能夠請求content, info 列以及評論(comments)列簇從一行查出所有的數據。你也能夠添加一個過濾器來展示部分評論數據,分頁顯示。
人員表列簇也能夠重新設計,用于存儲聯系信息比如獨立地址、電話號碼以及email地址。列簇能夠讓一個人的所有個人信息存儲在一行數據中。 這樣的設計在列數據不算太多時能夠很好的適應,比如博客評論和個人聯系信息。假如你設計的東西如電子郵件收件箱、財務事務或者海量的自動收集傳感數據,這樣就需要將用戶的電子郵件、事務或者傳感讀書分散至多行數據(“高”表設計)並且爲了能夠有效的掃描和分頁設計合理的行主鍵。收件箱的行主鍵可能形式是 <用戶id>-<郵件收取時間戳逆序>這樣就能夠簡單的對一個用戶的收件箱進行掃描和分頁,同樣對財務事務行主鍵設計爲<用戶id>-<事務到達時間戳逆序>。這樣的設計被稱之爲“高”表設計,就是將相同的內容(比如同一傳感器的讀數、同一賬戶的事務)分散至多行數據,可以考慮用于收集不斷擴展的海量信息,比如在一個要從一個巨大的傳感器網路中進行數據收集的場景。
設計HBase的行主鍵和表結構是使用HBase的一個很重要的步驟,也會繼續作爲HBase的基礎架構來考慮。在HBase中還可以增加一些其他方式作爲可選的數據訪問通道。比如能夠使用Apache Lucene實現全文檢索,可以針對HBase內部數據或者外部檢索(搜索下HBASE-3529)。你也能夠構建(及維護)二級索引從而允許表使用代替行主鍵結構。例如在人員表中行主鍵是姓名和唯一身份id組成的符合主鍵。但如果我們希望能夠根據人員的生日、電話區號、電子郵件地址或者其他的方式來訪問時,我們就能夠添加二級索引實現這樣的交互。不過要注意,添加二級索引並不是輕量的操作,每次你向主表(例如人員表)寫入數據時,就會更新所有的二級索引!(是的,有些事情關系型數據庫做的很好,不過記住HBase是設計用于容納比傳統關系型數據庫多的多的數據的)。
我們介紹了HBase中的結構設計(不包含關系及SQL)。盡管HBase丟失了傳統關系型數據庫的一些特性,比如外鍵、參照完整性、多行數據事務、多級索引等等,需要應用需要的是HBase的固有特性,比如掃描,就像很多複雜的事物一樣,需要作出取舍。在HBase中,我們放棄了豐富的表結構設計和查詢的靈活度,但是獲得了擴大容納海量數據的能力,只需要簡單的向集群中添加伺服器即可。

更多相關文章
  • 在html中checkbox 的checked是複選框選中狀態,如果有多個checkbox就必須以[]形式,這表示checkbox是數組了,我們要獲取checked[]這類型的值就得以數組形式操作,下面看實例.關于js php教程 處理checkbox checked與取值學習筆記-->< ...
  • hive是基于Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射爲一張數據庫表,並提供簡單的sql查詢功能,可以將sql語句轉換爲MapReduce任務進行運行.Hive是建立在Hadoop上的數據倉庫基礎構
  • hash和solr在海量數據分布式搜索引擎中的應用教程
    Solr是一個獨立的企業級搜索應用伺服器,它對外提供類似于Web-service的API接口.用戶可以通過http請求,向搜索引擎伺服器提交一定格式的XML文件,生成索引.互聯網創業中大部分人都是草根創業,這個時候沒有強勁的伺服器,也沒有錢去買很昂貴的海量數據庫.在這樣嚴峻的條件下,一批又一批的創業 ...
  • simhash短文本查找計算海量數據相似
    simhash處理數據速度雖然很快,但是隨著業務的增長,simhash數據也會越來越大,達
  • 下面給各位同學整理了一些關于php array數組的相關處理函數and str字符串處理與正則表達式,希望文章對你會有所幫助.數組的相關處理函數:1)數組的鍵值操作函數 array_values();//獲取數組中的值array_keys();//獲取數組中的鍵in_array();//檢查一個值是
  • 本文章來給各位同學介紹jQuery數組($.each,$.grep,$.map,$.merge,$.inArray,$.unique,$.makeArray)處理函數詳解用法有需要了解的朋友可參考參考啊.1. $.each(array, [callback]) 遍曆[常用]解釋: 不同于例遍jQue ...
  • 在js中split.join.substring和indexOf這幾個字符串處理函數我們會經常使用到了,下面小編就爲各位介紹一下這三個函數的簡單用法.函數:split()功能:使用一個指定的分隔符把一個字符串分割存儲到數組例子: 代碼如下 str=”jpg|bmp|gif|ico|png”;arr=
  • mysql教程 sql LENGTH,RIGHT,CHAR_LENGTH字符處理函數LENGTH(str) OCTET_LENGTH(str) CHAR_LENGTH(str) CHARACTER_LENGTH(st
一周排行