C++访问操作读写Hbase.docx
《C++访问操作读写Hbase.docx》由会员分享,可在线阅读,更多相关《C++访问操作读写Hbase.docx(15页珍藏版)》请在冰豆网上搜索。
C++访问操作读写Hbase
使用C++(通过Thrift)访问/操作/读写Hbase
无奈,网上关于C++访问Hbase的文章实在太少,所以只好自己折腾一下,然后写出来了。
要使用C++访问Hbase,可以走的途径少之又少,据说当前最好的方法就是通过Thrift来实现:
http:
//thrift.apache.org/
所以本文分成几部分:
(1)安装Thrift;
(2)用Thrift生成访问Hbase所需的C++文件;(3)在程序中通过Thrift来访问Hbase。
另外,本文只包含读写Hbase数据的例子,不包含配置Hbase的方法,如需这些内容,请自行搜索。
首先声明一下,本文基于以下环境:
操作系统:
RHEL5.3,64位
Thrift版本:
0.7.0
要访问的Hbase版本:
0.20.6
我使用0.90.4的Hbase安装包来生成C++所需的Hbase.h等文件(用新版的应该能兼容旧版的)
下面开始,一步步来。
(1)安装Thrift
不是一件很轻松的事。
如果你的系统比较干净,可能很顺利地就搞定了,如果有依赖库缺失问题或者库冲突问题,那么就只能根据具体情况,一个个问题去fix了,谁知道会有多少麻烦。
我运气比较好,在一个干净的系统上,很快就完成了。
Thrift至少会依赖于两个系统中一般不会带的库:
libevent,boost。
libevent到这里下载:
http:
//monkey.org/~provos/libevent/我使用的版本是:
2.0.12-stable
boost到这里下载:
http:
//www.boost.org/我使用的版本是:
1.47.0
安装libevent:
1
2
3
./configure--prefix=/usr/local/libevent
make
makeinstall
安装boost(boost不像一般的Linux源码安装包一样,它的安装不是configure,make,makeinstall,有点怪):
1
./bootstrap.sh--prefix=/usr/local/boost
不出错的话接着执行以下命令开始编译(也可以通过编辑project-config.jam文件调整编译参数):
1
2
./b2
./b2install
安装Thrift:
1
2
3
4
chmod+xconfigure
./configure--with-boost=/usr/local--prefix=/usr/local/thrift
make
makeinstall
至此,安装Thrift的工作就完成了。
(2)用Thrift生成访问Hbase所需的C++文件
访问Hbase需要在你的程序中使用若干.h,.cpp文件,这些文件是用Thrift生成的。
解压Hbase源码安装包:
1
2
tarzxfhbase-0.90.4.tar.gz
cdhbase-0.90.4
在解压出来的文件中,你可以找到一个名为Hbase.thrift的文件,这个文件定义了如何通过Thrift接口来访问Hbase。
用这个Thrift文件,可以生成访问Hbase所需的C++文件:
[shel]
/usr/local/thrift/bin/thrift–gencpp./src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift
[/shell]
会发现生成了gen-cpp目录:
1
2
3
lsgen-cpp/
Hbase_constants.cpp Hbase_constants.h Hbase.cpp Hbase.h Hbase_server.skeleton.cpp Hbase_types.cpp Hbase_types.h
除了Hbase_server.skeleton.cpp之外,其余文件都是在我们的程序里要用到的,将它们拷贝到我们的工程目录下。
(3)在程序中使用Thrift来访问Hbase
要能通过Thrift访问Hbase,你必须首先要打开HBase的Thrift服务,请参考其他文档确保这一点是可用的。
下一步,我们在程序中如何读取Hbase的数据?
我们先看看hbase源码安装包中自带的例子:
在解压出来的安装包中的examples/thrift/目录下的DemoClient.cpp文件,有如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
boost:
:
shared_ptrsocket(newTSocket("localhost",9090));
boost:
:
shared_ptrtransport(newTBufferedTransport(socket));
boost:
:
shared_ptrprotocol(newTBinaryProtocol(transport));
HbaseClientclient(protocol);
try{
transport->open();
//dosomething
transport->close();
}catch(TException&tx){
printf("ERROR:
%s\n",tx.what());
}
我们就仿照这个例子来做。
从DemoClient.cpp可见,我们要先创建三个指针socket,transport和protocol,后两个分别依赖于前两个,最后再创建一个client对象,我们操作Hbase就是使用这个client对象。
在操作Hbase前,需要先打开到HbaseThriftservice的连接,即transport->open(),在操作完Hbase之后,需要关闭连接,即transport->close(),这下就比较清楚了:
我们可以写一个自己的类CHbaseOperate,它应该有一个open函数和一个close函数,分别用于打开、关闭连接,还应该有读写Hbase的基本功能。
读写Hbase的方法,请参考Hbase.h中的函数,例子还是看DemoClient.cpp。
下面上代码:
HbaseOperate.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#ifndef__HBASE_OPERATE_H
#define__HBASE_OPERATE_H
#include
#include
#include
#include
#include"Hbase.h"
/**
*ClasstooperateHbase.
*
*@authorDarranZhang()
*@version11-08-24
*@declarationThesecodesareonlyfornon-commercialuse,andaredistributedonan"ASIS"basis,WITHOUTWARRANTYOFANYKIND,eitherexpressorimplied.
*Youmustnotremovethisdeclarationatanytime.
*/
usingnamespaceapache:
:
thrift;
usingnamespaceapache:
:
thrift:
:
protocol;
usingnamespaceapache:
:
thrift:
:
transport;
usingnamespaceapache:
:
hadoop:
:
hbase:
:
thrift;
typedefstructhbaseRet{
std:
:
stringrowValue;
time_tts;
hbaseRet(){
ts=0;
}
}hbaseRet;
classCHbaseOperate
{
public:
CHbaseOperate();
virtual~CHbaseOperate();
private:
boost:
:
shared_ptrsocket;
boost:
:
shared_ptrtransport;
boost:
:
shared_ptrprotocol;
HbaseClient*client;
std:
:
string hbaseServiceHost;
int hbaseServicePort;
bool isConnected;
public:
bool connect();
bool connect(std:
:
stringhost,intport);
bool disconnect();
bool putRow(conststd:
:
string&tableName,
conststd:
:
string&rowKey,
conststd:
:
string&column,
conststd:
:
string&rowValue);
bool getRow(hbaseRet&result,
conststd:
:
string&tableName,
conststd:
:
string&rowKey,
conststd:
:
string&columnName);
};
#endif
HbaseOperate.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include"HbaseOperate.h"
#include"log4cxx/log4cxx.h"
#include"log4cxx/propertyconfigurator.h"
staticlog4cxx:
:
LoggerPtrlogger(log4cxx:
:
Logger:
:
getLogger("HbaseOperate.cpp"));
/**
*ClasstooperateHbase.
*
*@authorDarranZhang()
*@version11-08-24
*@declarationThesecodesareonlyfornon-commercialuse,andaredistributedonan"ASIS"basis,WITHOUTWARRANTYOFANYKIND,eitherexpressorimplied.
*Youmustnotremovethisdeclarationatanytime.
*/
usingnamespacestd;
CHbaseOperate:
:
CHbaseOperate():
socket((TSocket*)NULL),transport((TBufferedTransport*)NULL),protocol((TBinaryProtocol*)NULL),client(NULL),hbaseServicePort(9090),isConnected(false)
{
}
CHbaseOperate:
:
~CHbaseOperate()
{
if(isConnected){
disconnect();
}
if(NULL!
=client){
deleteclient;
client=NULL;
}
}
/**
*ConnectHbase.
*
*/
boolCHbaseOperate:
:
connect()
{
if(isConnected){
LOG4CXX_INFO(logger,"Alreadyconnected,don'tneedtoconnectitagain");
returntrue;
}
try{
socket.reset(newTSocket(hbaseServiceHost,hbaseServicePort));
transport.reset(newTBufferedTransport(socket));
protocol.reset(newTBinaryProtocol(transport));
client=newHbaseClient(protocol);
transport->open();
}catch(constTException&tx){
LOG4CXX_ERROR(logger,"ConnectHbaseerror:
"< returnfalse;
}
isConnected=true;
returnisConnected;
}
/**
*ConnectHbase.
*
*/
boolCHbaseOperate:
:
connect(std:
:
stringhost,intport)
{
hbaseServiceHost=host;
hbaseServicePort=port;
returnconnect();
}
/**
*DisconnectfromHbase.
*
*/
boolCHbaseOperate:
:
disconnect()
{
if(!
isConnected){
LOG4CXX_ERROR(logger,"Haven'tconnectedtoHbaseyet,can'tdisconnectfromit");
returnfalse;
}
if(NULL!
=transport){
try{
transport->close();
}catch(constTException&tx){
LOG4CXX_ERROR(logger,"DisconnectHbaseerror:
"< returnfalse;
}
}else{
returnfalse;
}
isConnected=false;
returntrue;
}
/**
*PutarowtoHbase.
*
*@paramtableName [IN]Thetablename.
*@paramrowKey [IN]Therowkey.
*@paramcolumn [IN]The"columnfamily:
qualifier".
*@paramrowValue [IN]Therowvalue.
*@returnTrueforsuccessfullyputtherow,falseotherwise.
*/
boolCHbaseOperate:
:
putRow(conststring&tableName,conststring&rowKey,conststring&column,conststring&rowValue)
{
if(!
isConnected){
LOG4CXX_ERROR(logger,"Haven'tconnectedtoHbaseyet,can'tputrow");
returnfalse;
}
try{
std:
:
vectormutations;
mutations.push_back(Mutation());
mutations.back().column=column;
mutations.back().value=rowValue;
client->mutateRow(tableName,rowKey,mutations);
}catch(constTException&tx){
LOG4CXX_ERROR(logger,"OperateHbaseerror:
"< returnfalse;
}
returntrue;
}
/**
*GetaHbaserow.
*
*@paramresult [OUT]Theobjectwhichcontainsthereturneddata.
*@paramtableName [IN]TheHbasetablename,e.g."MyTable".
*@paramrowKey [IN]TheHbaserowkey,e.g."kdr23790".
*@paramcolumnName [IN]The"columnfamily:
qualifier".
*@returnTrueforsuccessfullygettherow,falseotherwise.
*/
boolCHbaseOperate:
:
getRow(hbaseRet&result,conststd:
:
string&tableName,conststd:
:
string&rowKey,conststd:
:
string&columnName)
{
if(!
isConnected){
LOG4CXX_ERROR(logger,"Haven'tconnectedtoHbaseyet,can'treaddatafromit");
returnfalse;
}
std:
:
vector:
string>columnNames;
columnNames.push_back(columnName);
std:
:
vectorrowResult;
try{
client->getRowWithColumns(rowResult,tableName,rowKey,columnNames);
}catch(constTException&tx){
LOG4CXX_ERROR(logger,"OperateHbaseerror:
"< returnfalse;
}
if(0==rowResult.size()){
LOG4CXX_WARN(logger,"Gotnorecordwiththekey:
["< returnfalse;
}
std:
:
map:
string,TCell>:
:
const_iteratorit=rowResult[rowResult.size()-1].columns.begin();
result.rowValue=it->second.value;
result.ts=it->second.timestamp;
returntrue;
}
注意我在程序中使用了Apachelog4cxx这个记录日志的库来打印/保存程序运行日志,使用方法可参考【此链接】。
如果你不想用,可以自己改为std:
: