Apache HBase 외부 API
Apache HBase 외부 API (Apache HBase External APIs)
네이티브 HBase API 외에 사용할 수 있는 외부 인터페이스(REST, Thrift, C/C++ 클라이언트, JDO, Scala, Jython)를 설명하는 페이지예요. REST는 URL 자체에 묶인 API로 테이블·행·셀·메타데이터를 리소스로 노출해요.
출처: 문서
본문
네이티브 HBase API 사용 방법은 User API Reference와 HBase APIs 챕터를 참고하세요.
REST
Representational State Transfer(REST)는 HTTP 사양의 주요 저자 중 한 명인 Roy Fielding의 박사 논문(2000)에서 소개됐어요.
REST 자체는 이 문서의 범위를 벗어나지만, 일반적으로 REST는 URL 자체에 묶인 API를 통해 클라이언트-서버 상호작용을 허용해요. 이 섹션은 HBase와 함께 제공되는 REST 서버를 구성·실행하는 방법을 논의해요. 이 서버는 HBase 테이블, 행, 셀, 메타데이터를 URL로 지정된 리소스로 노출해요. Jesse Anderson의 How-to: Use the Apache HBase REST Interface 시리즈 블로그도 좋아요.
REST 서버 시작·중지 (Starting and Stopping the REST Server)
포함된 REST 서버는 임베디드 Jetty 서블릿 컨테이너를 시작하고 그 안에 서블릿을 배포하는 데몬으로 실행할 수 있어요. 다음 명령 중 하나로 REST 서버를 포그라운드 또는 백그라운드로 시작하세요. 포트는 선택 사항이며 기본값은 8080이에요.
Foreground
$ bin/hbase rest start -p
Background, logging to a file in $HBASE_LOGS_DIR
$ bin/hbase-daemon.sh start rest -p
REST 서버를 중지하려면 포그라운드에서 실행 중이었다면 Ctrl-C를, 백그라운드에서 실행 중이었다면 다음 명령을 사용하세요.
$ bin/hbase-daemon.sh stop rest
REST 서버와 클라이언트 구성 (Configuring the REST Server and Client)
REST 서버와 클라이언트를 SSL로 구성하는 방법과 REST 서버의 doAs 가장(impersonation)에 대한 정보는 Configure the Thrift Gateway to Authenticate on Behalf of the Client와 Securing Apache HBase 챕터의 다른 부분을 참고하세요.
REST 엔드포인트 사용 (Using REST Endpoints)
다음 예제는 플레이스홀더 서버 http://example.com:8000을 사용하며, 아래 명령은 모두 curl이나 wget 명령으로 실행할 수 있어요. 헤더 없이 평문 텍스트(기본), "Accept: text/xml" 헤더로 XML, "Accept: application/json"으로 JSON, "Accept: application/x-protobuf"로 프로토콜 버퍼 출력을 요청할 수 있어요.
달리 명시되지 않으면 쿼리에는 GET, 생성·변형에는 PUT 또는 POST, 삭제에는 DELETE를 사용하세요.
클러스터 전역 엔드포인트 (Cluster-Wide Endpoints)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /version/cluster | GET | 이 클러스터에서 실행 중인 HBase 버전 |
| /version/rest | GET | HBase REST Server 버전 |
| /status/cluster | GET | 클러스터 상태 |
| / | GET | 모든 비시스템 테이블 목록 |
예시:
Get cluster version
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/version/cluster"
Get REST server version
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/version/rest"
Get cluster status
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/status/cluster"
List all non-system tables
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/"
네임스페이스 엔드포인트 (Namespace Endpoints)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /namespaces | GET | 모든 네임스페이스 나열 |
| /namespaces/namespace | GET | 특정 네임스페이스 설명 |
| /namespaces/namespace | POST | 새 네임스페이스 생성 |
| /namespaces/namespace/tables | GET | 특정 네임스페이스의 모든 테이블 나열 |
| /namespaces/namespace | PUT | 기존 네임스페이스 alter. 현재는 사용되지 않음 |
| /namespaces/namespace | DELETE | 네임스페이스 삭제. 네임스페이스는 비어 있어야 함 |
예시:
List all namespaces
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/namespaces/"
Describe a specific namespace
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/namespaces/special_ns"
Create a new namespace
curl -vi -X POST
-H "Accept: text/xml"
"example.com:8000/namespaces/special_ns"
List all tables in a specific namespace
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/namespaces/special_ns/tables"
Alter an existing namespace
curl -vi -X PUT
-H "Accept: text/xml"
"http://example.com:8000/namespaces/special_ns
Delete a namespace
curl -vi -X DELETE
-H "Accept: text/xml"
"example.com:8000/namespaces/special_ns"
테이블 엔드포인트 (Table Endpoints)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/exists | GET | 지정된 테이블이 존재하는지 반환 |
| /table/schema | GET | 지정된 테이블의 스키마 설명 |
| /table/schema | POST | 제공된 스키마 조각으로 기존 테이블 업데이트 |
| /table/schema | PUT | 새 테이블 생성, 또는 기존 테이블 스키마 교체 |
| /table/schema | DELETE | 테이블 삭제. /table/이 아닌 /table/schema 엔드포인트를 사용해야 함 |
| /table/regions | GET | 테이블 region 나열 |
예시:
Check if table exists
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/exists"
Get table schema
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/schema"
Update table schema
curl -vi -X POST
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/schema"
Create or replace table schema
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/schema"
Delete table
curl -vi -X DELETE
-H "Accept: text/xml"
"http://example.com:8000/users/schema"
List table regions
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/regions"
Get 연산 엔드포인트 (Endpoints for Get Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row | GET | 단일 행의 모든 컬럼 가져오기. 값은 Base-64 인코딩됨. 여러 컬럼을 담을 수 있는 유형(xml, json, protobuf 등)의 "Accept" 요청 헤더 필요 |
| /table/row/column:qualifier/timestamp | GET | 단일 컬럼 값 가져오기. 값은 Base-64 인코딩됨 |
| /table/row/column:qualifier | GET | 단일 컬럼 값 가져오기. 값은 Base-64 인코딩됨 |
| /table/row/column:qualifier?e=b64 | GET | URL-safe base64로 인코딩된 바이너리 rowkey·컬럼 이름으로 단일 컬럼 값 가져오기. 반환 값은 Base-64 인코딩됨 |
| /table/row_prefix*/column | GET | 주어진 행 접두사와 컬럼 패밀리와 일치하는 행 조합 가져오기. 반환 값은 Base-64 인코딩됨 |
| /table/row_prefix*/column:qualifier | GET | 주어진 행 접두사, 컬럼 패밀리, 퀄리파이어와 일치하는 행 조합 가져오기. 반환 값은 Base-64 인코딩됨 |
| /table/multiget?row=row&row=row/column:qualifier&row=... | GET | 행/컬럼 조합 Multi-Get. 값은 Base-64 인코딩됨 |
| /table/multiget?e=b64&row=row&row=row/column:qualifier&row=... | GET | URL-safe base64로 인코딩된 바이너리 rowkey·컬럼 이름으로 행/컬럼 조합 Multi-Get. 반환 값은 Base-64 인코딩됨 |
| /table/multiget?row=row&row=row/column:qualifier&filter=url_encoded_filter | GET | 필터가 있는 행/컬럼 조합 Multi-Get. 필터는 Thrift Filter Language로 지정한 뒤 application/x-www-form-urlencoded MIME 형식 문자열로 인코딩. 이 예제는 PrefixFilter('row1') 사용 |
| /table/multiget?row=row&row=row/column:qualifier&row=...&filter_b64=b64_encoded_filter | GET | 필터가 있는 행/컬럼 조합 Multi-Get. 필터는 Thrift Filter Language로 지정한 뒤 URL-safe base64로 인코딩. 이 예제는 PrefixFilter('row1') 사용 |
| /table/row/column:qualifier/?v=number_of_versions | GET | 주어진 셀의 지정된 수의 버전 Multi-Get. 값은 Base-64 인코딩됨 |
예시:
Get all columns of a single row
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1"
Get single column with timestamp
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1/cf:a/1458586888395"
Get single column
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1/cf:a"
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1/cf:a/"
Get single column with base64 encoding
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/cm93MQ/Y2Y6YQ?e=b64"
curl -vi -X GET
-H "Accept: text/xml"
-H "Encoding: base64"
"http://example.com:8000/users/cm93MQ/Y2Y6YQ/"
Get rows with prefix
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row*/cf"
Multi-get
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/multiget?row=row1&row=row2/cf:a"
Multi-get with base64
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/multiget?e=b64&row=cm93MQ&row=cm93Mg%2FY2Y6YQ"
Multi-get with filter
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/multiget?row=row1&row=row2/cf:a&filter=PrefixFilter%28%27row1%27%29"
Multi-get with base64 filter
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/multiget?row=row1&row=row2/cf:a&filter_b64=UHJlZml4RmlsdGVyKCdyb3cxJyk"
Get multiple versions
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1/cf:a?v=2"
Delete 연산 엔드포인트 (Endpoints for Delete Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row | DELETE | 단일 행의 모든 컬럼 삭제 |
| /table/row/column_family: | DELETE | 단일 행과 컬럼 패밀리의 모든 컬럼 삭제 |
| /table/row/column:qualifier/timestamp | DELETE | 단일 컬럼 삭제 |
| /table/row/column:qualifier | DELETE | 단일 컬럼 삭제 |
| /table/row/column:qualifier?e=b64 | DELETE | URL-safe base64로 인코딩된 바이너리 rowkey·컬럼 이름으로 단일 컬럼 삭제 |
예시:
Delete all columns of a row
curl -vi -X DELETE
"http://example.com:8000/users/row1"
Delete all columns of a row and column family
curl -vi -X DELETE
"http://example.com:8000/users/row1/cf"
Delete a single column with timestamp
curl -vi -X DELETE
"http://example.com:8000/users/row1/cf:a/1458586888395"
Delete a single column
curl -vi -X DELETE
"http://example.com:8000/users/row1/cf:a"
curl -vi -X DELETE
-H "Accept: text/xml"
"http://example.com:8000/users/row1/cf:a/"
Delete with base64 encoding
curl -vi -X DELETE
"http://example.com:8000/users/cm93MQ/Y2Y6YQ?e=b64"
curl -vi -X DELETE
-H "Encoding: base64"
"http://example.com:8000/users/cm93MQ/Y2Y6YQ/"
스캔 연산의 상태 유지(stateful) 엔드포인트 (Stateful endpoints for Scan Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/scanner/ | PUT | Scanner 객체 가져오기. 다른 모든 Scan 연산에 필요. batch 매개변수를 스캔이 배치로 반환할 행 수로 조정 |
| /table/scanner/ | PUT | Scanner 객체에 필터를 제공하거나 다른 방식으로 Scanner를 구성하려면 텍스트 파일을 만들고 필터를 추가 |
| /table/scanner/scanner-id | GET | 스캐너에서 다음 배치 가져오기. 셀 값은 바이트 인코딩됨. 스캐너가 소진되면 HTTP 상태 204 반환 |
| table/scanner/scanner-id | DELETE | 스캐너 삭제 및 사용 리소스 해제 |
필터 파일 예시는 다음을 포함해야 해요.
예시:
Create a scanner
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/scanner/"
Create a scanner with filter from file
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type:text/xml"
-d @filter.txt
"http://example.com:8000/users/scanner/"
Get next batch from scanner
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/scanner/145869072824375522207"
Delete scanner
curl -vi -X DELETE
-H "Accept: text/xml"
"http://example.com:8000/users/scanner/145869072824375522207"
스캔 연산의 무상태(stateless) 엔드포인트 (Stateless endpoints for Scan Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/* | GET | 전체 테이블 스캔. 무상태 스캐너 엔드포인트는 결과를 반환하기 위해 후속 호출이 필요 없음 |
| /table/*?limit=number_of_rows | GET | 테이블의 첫 번째 행 스캔 |
| /table/*?column=column:qualifier | GET | 테이블의 주어진 컬럼 스캔 |
| /table/*?column=column1:qualifier1,column2:qualifier2 | GET | 테이블의 둘 이상의 컬럼 스캔 |
| /table/*?startrow=row&limit=number_of_rows | GET | 시작 행과 한도로 테이블 스캔 |
| /table/row_prefix* | GET | 행 접두사로 테이블 스캔 |
| /table/*?reversed=true | GET | 역순으로 테이블 스캔 |
| /table/*?filter=url_encoded_filter | GET | PrefixFilter('row1') 필터로 스캔. 필터는 Thrift Filter Language로 지정한 뒤 application/x-www-form-urlencoded MIME 형식 문자열로 인코딩 |
| /table/*?filter_b64=b64_encoded_filter | GET | PrefixFilter('row1') 필터로 스캔. 필터는 Thrift Filter Language로 지정한 뒤 URL-safe base64로 인코딩 |
예시:
Scan entire table
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*"
Scan with limit
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?limit=1"
Scan single column
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?column=cf:a"
Scan multiple columns
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?column=cf:a,cf:b"
Scan with start row and limit
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?startrow=row1&limit=2"
Scan with row prefix
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/row1*"
Scan in reverse
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?reversed=true"
Scan with filter
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?filter=PrefixFilter%28%27row1%27%29"
Scan with base64 filter
curl -vi -X GET
-H "Accept: text/xml"
"http://example.com:8000/users/*?filter_b64=UHJlZml4RmlsdGVyKCdyb3cxJyk"
stateful scanner API는 클라이언트가 스캔 도중 REST 서버 실패 시 스캔을 재시작할 것을 기대해요. 무상태(stateless)는 스캔 연산과 관련된 어떤 상태도 저장하지 않으며 모든 매개변수가 쿼리 매개변수로 지정돼요.
무상태 엔드포인트는 작은 결과에 최적화되어 있고, stateful scanner API는 큰 결과에도 사용할 수 있어요.
스캔 매개변수는 다음과 같아요.
startrow— 스캔의 시작 행.endrow— 스캔의 끝 행.column— 스캔할 컬럼의 쉼표 구분 목록.starttime,endtime— 특정 버전 타임스탬프 범위 내의 컬럼만 검색하려면 시작·끝 시간을 모두 지정해야 함.maxversions— 반환할 각 컬럼의 버전 수를 제한.batchsize— 각 next() 호출에 대해 반환되는 최대 값 수를 제한.limit— 스캔 연산에서 반환할 행 수.cacheblocks— RegionServer에서 Block Cache를 사용할지 여부. 기본true.reversed—true로 설정하면 역방향 스캔이 실행. 기본false.filter— 스캔의 필터를application/x-www-form-urlencodedMIME 형식 문자열로 지정할 수 있게 함.filter_b64— HBASE-28518 패치가 포함된 버전에서filter_b64는 URL-safe base64 인코딩 필터를 지정할 수 있게 함.filter와filter_b64를 모두 지정하면filter_b64만 고려됨.includeStartRow— 시작 행을 스캔에 포함할지 여부. 기본true.includeStopRow— 끝 행(중지 행)을 스캔에 포함할지 여부. 기본false.
includeStartRow와 includeStopRow는 HBASE-28627을 포함한 버전에서만 지원돼요. 이 패치가 없는 버전은 이 매개변수를 무시하거나, 기본값이 아닌 값으로 설정하면 오류를 낼 거예요.
시작 행, 끝 행, limit 매개변수에 대해 더:
- 시작 행, 끝 행, limit이 모두 지정되지 않으면 전체 테이블이 스캔됨.
- 시작 행과 limit(예: N)이 지정되면 스캔 연산은 지정된 시작 행부터 N개의 행을 반환.
- limit만 지정되면 스캔 연산은 테이블 시작부터 N개의 행을 반환.
- limit과 끝 행이 지정되면 스캔 연산은 테이블 시작부터 끝 행까지 N개의 행을 반환. N행 전에 끝 행에 도달하면(예: M, M < N) M개의 행이 사용자에게 반환.
- 시작 행, 끝 행, limit(예: N)이 모두 지정되고 N < 시작·끝 행 사이의 행 수이면 시작 행부터 N행이 사용자에게 반환. N > (시작·끝 행 사이의 행 수, 예: M)이면 M행이 사용자에게 반환.
Put 연산 엔드포인트 (Endpoints for Put Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row_key | PUT | 테이블에 행 쓰기. 행, 컬럼 퀄리파이어, 값은 각각 Base-64 인코딩해야 함. 문자열 인코딩은 base64 커맨드라인 유틸리티 사용, 디코딩은 base64 -d. 페이로드는 --data 인자에 있고 /users/fakerow 값은 플레이스홀더. 여러 행은 |
예시:
XML format
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/fakerow"
JSON format
curl -vi -X PUT
-H "Accept: text/json"
-H "Content-Type: text/json"
-d '{"Row":[{"key":"cm93NQo=", "Cell": [{"column":"Y2Y6ZQo=", "$":"dmFsdWU1Cg=="}]}]}''
"example.com:8000/users/fakerow"
Check-And-Put 연산 엔드포인트 (Endpoints for Check-And-Put Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row_key/?check=put | PUT | 조건부 Put — 셀의 현재 버전 값 변경: 셀의 현재 또는 최신 버전 값(current-version-value)을 check-value와 비교하고, current-version-value == check-value이면 새 데이터(new-value)를 현재 또는 최신 버전으로 셀에 씀. 행, 컬럼 퀄리파이어, 값은 각각 Base-64 인코딩해야 함. check 셀 이름(컬럼 패밀리:컬럼 이름)과 값이 항상 끝에, 같은 행 키의 새 Put 셀 이름(컬럼 패밀리:컬럼 이름)과 값 바로 뒤에 위치. 페이로드는 --data 또는 -d 인자에 있음. 삽입할 데이터를 파일에 저장하고 -d @filename.txt 구문으로 전달 가능 |
예시:
XML format
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row1/?check=put"
JSON format
curl -vi -X PUT
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{"Row":[{"key":"cm93MQ==","Cell":[{"column":"Y2ZhOmFsaWFz","$":"T2xkR3V5"},{"column":"Y2ZhOmFsaWFz", "$":"TmV3R3V5"}] }]}'
"http://example.com:8000/users/row1/?check=put"
상세 설명:
- 위 json-format 예제에서:
-d옵션 끝의{"column":"Y2ZhOmFsaWFz", "$":"TmV3R3V5"}는 각각 Base-64의 check 셀 이름과 check 셀 값:"Y2ZhOmFsaWFz"는"cfa:alias","TmV3R3V5"는"NewGuy".{"column":"Y2ZhOmFsaWFz","$":"T2xkR3V5"}는 각각 Base-64의 새 Put 셀 이름과 셀 값:"Y2ZhOmFsaWFz"는"cfa:alias","T2xkR3V5"는"OldGuy"."cm93MQ=="는 checkAndPutrow key용"row1"의 Base-64.- 요청 URL의
row key뒤의"/?check=put"은 checkAndPut WebHBase 연산이 동작하는 데 필요. - 요청 URL의
"row key"는 URL-encoded여야 함. 예:"david%20chen"과"row1"은 각각 행 키"david chen"과"row1"의 URL-encoded 형식. - 메모: "cfa"는 컬럼 패밀리 이름이고 "alias"는 non-Base64 인코딩 셀 이름의 컬럼(퀄리파이어) 이름.
- 기본적으로 xml-format 예제는 json-format 예제와 같으며 여기서 자세히 설명하지 않겠음.
Check-And-Delete 연산 엔드포인트 (Endpoints for Check-And-Delete Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row_key/?check=delete | DELETE | 조건부 행 삭제: 셀의 임의 버전 값(any-version-value)을 check-value와 비교하고, any-version-value == check-value이면 요청 URL 안의 row_key가 지정한 행을 삭제. 페이로드의 행, 컬럼 퀄리파이어, 값은 각각 Base-64 인코딩해야 함. |
| /table/row_key/column_family/?check=delete | DELETE | 조건부 행의 컬럼 패밀리 삭제: any-version-value를 check-value와 비교하고 같으면 요청 URL 안의 row_key/column_family가 지정한 행의 컬럼 패밀리 삭제. 나머지는 조건부 행 삭제와 동일 |
| /table/row_key/column:qualifier/?check=delete | DELETE | 조건부 행의 컬럼 모든 버전 삭제: any-version-value를 check-value와 비교하고 같으면 요청 URL 안의 row_key/column:qualifier가 지정한 행의 컬럼 삭제. 요청 URL의 column:qualifier는 column_family:column_name |
| /table/row_key/column:qualifier/version_id/?check=delete | DELETE | 조건부 행의 컬럼 단일 버전 삭제: any-version-value를 check-value와 비교하고 같으면 요청 URL 안의 row_key/column:qualifier/version_id가 지정한 행의 컬럼 버전 삭제 |
예시:
Conditional delete a row (XML)
curl -vi -X DELETE
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row1/?check=delete"
Conditional delete a row (JSON)
curl -vi -X DELETE
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{"Row":[{"key":"cm93MQ==","Cell":[{"column":"Y2ZhOmFsaWFz","$":"TmV3R3V5"}]}]}'
"http://example.com:8000/users/row1/?check=delete"
Conditional delete a column family (XML)
curl -vi -X DELETE
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row1/cfa/?check=delete"
Conditional delete a column family (JSON)
curl -vi -X DELETE
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{"Row":[{"key":"cm93MQ==","Cell":[{"column":"Y2ZhOmFsaWFz","$":"TmV3R3V5"}]}]}'
"http://example.com:8000/users/row1/cfa/?check=delete"
Conditional delete all versions of a column (XML)
curl -vi -X DELETE
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row1/cfa:alias/?check=delete"
Conditional delete all versions of a column (JSON)
curl -vi -X DELETE
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{"Row":[{"key":"cm93MQ==","Cell":[{"column":"Y2ZhOmFsaWFz","$":"TmV3R3V5"}]}]}'
"http://example.com:8000/users/row1/cfa:alias/?check=delete"
Conditional delete a single version (XML)
curl -vi -X DELETE
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row1/cfa:alias/1519423552160/?check=delete"
Conditional delete a single version (JSON)
curl -vi -X DELETE
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{"Row":[{"key":"cm93MQ==","Cell":[{"column":"Y2ZhOmFsaWFz","$":"TmV3R3V5"}]}]}'
"http://example.com:8000/users/row1/cfa:alias/1519423552160/?check=delete"
상세 설명:
- 위 4개의 json-format 예제에서:
-d옵션 끝의{"column":"Y2ZhOmFsaWFz", "$":"TmV3R3V5"}는 각각 Base-64의 check 셀 이름과 check 셀 값:"Y2ZhOmFsaWFz"는"cfa:alias","TmV3R3V5"는"NewGuy"."cm93MQ=="는 checkAndDeleterow key용"row1"의 Base-64.요청 URL끝의"/?check=delete"는 checkAndDelete WebHBase 연산이 동작하는 데 필요.- 마지막 json-format 예제의
요청 URL의"version_id"는"타임스탬프 번호 + 1"의 값과 같아야 함. - checkAndDelete WebHBase 연산의
요청 URL에 있는"row key","column family","cell name" 또는 "column family:column name","version_id"는 URL-encoded여야 함. 예제의"row1","cfa","cfa:alias","1519423552160"은 각각 URL-encoded된"row key","column family","column family:column name","version_id".
- 기본적으로 4개의 xml-format 예제는 해당하는 4개의 json-format 예제와 같으며 여기서 자세히 설명하지 않겠음.
Append 연산 엔드포인트 (Endpoints for Append Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row_key/?check=append | PUT | 주어진 새 값을 셀의 현재 값 끝에 추가. 행, 컬럼 퀄리파이어, 값은 각각 Base-64 인코딩해야 함 |
예시:
XML format
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://example.com:8000/users/row5?check=append"
JSON format
curl -vi -X PUT
-H "Content-type: application/json"
-H "Accept: application/json"
-d '{"Row":[{"key":"dGVzdHJvdzE=","Cell":[{"column":"YTox","$":"dGVzdHZhbHVlMgo"},{"column":"YToy","$":"dGVzdHZhbHVlMTIK"}]}]}'
"http://localhost:8080/users/testrow1?check=append"
Increment 연산 엔드포인트 (Endpoints for Increment Operations)
| Endpoint | HTTP Verb | Description |
|---|---|---|
| /table/row_key/?check=increment | PUT | 셀의 현재 값 증가. 행, 컬럼 퀄리파이어, 값은 각각 Base-64 인코딩해야 함 |
예시:
XML format
curl -vi -X PUT
-H "Accept: text/xml"
-H "Content-Type: text/xml"
-d '
"http://localhost:8080/users/row5?check=increment"
JSON format
curl -vi -X PUT
-H "Content-type: application/json"
-H "Accept: application/json"
-d '{"Row":[{"key":"dGVzdHJvdzE=","Cell":[{"column":"YTox","$":"MQ=="},{"column":"YToy","$":"MQ=="}]}]}'
"http://localhost:8080/users/testrow1?check=increment"
REST XML 스키마 (REST XML Schema)
REST Protobufs 스키마 (REST Protobufs Schema)
message Version { optional string restVersion = 1; optional string jvmVersion = 2; optional string osVersion = 3; optional string serverVersion = 4; optional string jerseyVersion = 5; optional string version = 6; optional string revision = 7; }
message StorageClusterStatus { message Region { required bytes name = 1; optional int32 stores = 2; optional int32 storefiles = 3; optional int32 storefileSizeMB = 4; optional int32 memStoreSizeMB = 5; optional int64 storefileIndexSizeKB = 6; optional int64 readRequestsCount = 7; optional int64 writeRequestsCount = 8; optional int32 rootIndexSizeKB = 9; optional int32 totalStaticIndexSizeKB = 10; optional int32 totalStaticBloomSizeKB = 11; optional int64 totalCompactingKVs = 12; optional int64 currentCompactedKVs = 13; optional int64 cpRequestsCount = 14; } message Node { required string name = 1; // name:port optional int64 startCode = 2; optional int32 requests = 3; optional int32 heapSizeMB = 4; optional int32 maxHeapSizeMB = 5; repeated Region regions = 6; } // node status repeated Node liveNodes = 1; repeated string deadNodes = 2; // summary statistics optional int32 regions = 3; optional int32 requests = 4; optional double averageLoad = 5; }
message TableList { repeated string name = 1; }
message TableInfo { required string name = 1; message Region { required string name = 1; optional bytes startKey = 2; optional bytes endKey = 3; optional int64 id = 4; optional string location = 5; } repeated Region regions = 2; }
message TableSchema { optional string name = 1; message Attribute { required string name = 1; required string value = 2; } repeated Attribute attrs = 2; repeated ColumnSchema columns = 3; // optional helpful encodings of commonly used attributes optional bool inMemory = 4; optional bool readOnly = 5; }
message ColumnSchema { optional string name = 1; message Attribute { required string name = 1; required string value = 2; } repeated Attribute attrs = 2; // optional helpful encodings of commonly used attributes optional int32 ttl = 3; optional int32 maxVersions = 4; optional string compression = 5; }
message Cell { optional bytes row = 1; // unused if Cell is in a CellSet optional bytes column = 2; optional int64 timestamp = 3; optional bytes data = 4; }
message CellSet { message Row { required bytes key = 1; repeated Cell values = 2; } repeated Row rows = 1; }
message Scanner { optional bytes startRow = 1; optional bytes endRow = 2; repeated bytes columns = 3; optional int32 batch = 4; optional int64 startTime = 5; optional int64 endTime = 6; optional int32 maxVersions = 7; optional string filter = 8; optional int32 caching = 9; // specifies REST scanner caching repeated string labels = 10; optional bool cacheBlocks = 11; // server side block caching hint optional int32 limit = 12; optional bool includeStartRow = 13; optional bool includeStopRow = 14; }
Thrift
Thrift에 대한 문서는 Thrift API and Filter Language로 이동했어요.
C/C++ Apache HBase 클라이언트 (C/C++ Apache HBase Client)
FB의 Chip Turner가 순수 C/C++ 클라이언트를 작성했어요. 확인해 보세요.
C++ 클라이언트 구현. HBASE-14850을 참고하세요.
HBase에서 Java Data Objects (JDO) 사용 (Using Java Data Objects (JDO) with HBase)
Java Data Objects (JDO)는 일반 Java 객체(POJO)로 영구 데이터를 나타내 데이터베이스의 영구 데이터에 접근하는 표준 방식이에요.
의존성 (Dependencies)
이 코드 예제의 의존성:
- HBase 0.90.x 또는 더 새로운 버전
- commons-beanutils.jar (https://commons.apache.org/)
- commons-pool-1.5.5.jar (https://commons.apache.org/)
- HBase 0.90용 transactional-tableindexed (https://github.com/hbase-trx/hbase-transactional-tableindexed)
hbase-jdo 다운로드 (Download hbase-jdo)
코드를 http://code.google.com/p/hbase-jdo/에서 다운로드하세요.
JDO 예제 (JDO Example)
이 예제는 JDO로 테이블과 인덱스를 만들고, 테이블에 행을 삽입하고, 행을 가져오고, 컬럼 값을 가져오고, 쿼리를 수행하며, 몇 가지 추가 HBase 연산을 수행해요.
package com.apache.hadoop.hbase.client.jdo.examples;
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Hashtable;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.client.tableindexed.IndexedTable;
import com.apache.hadoop.hbase.client.jdo.AbstractHBaseDBO; import com.apache.hadoop.hbase.client.jdo.HBaseBigFile; import com.apache.hadoop.hbase.client.jdo.HBaseDBOImpl; import com.apache.hadoop.hbase.client.jdo.query.DeleteQuery; import com.apache.hadoop.hbase.client.jdo.query.HBaseOrder; import com.apache.hadoop.hbase.client.jdo.query.HBaseParam; import com.apache.hadoop.hbase.client.jdo.query.InsertQuery; import com.apache.hadoop.hbase.client.jdo.query.QSearch; import com.apache.hadoop.hbase.client.jdo.query.SelectQuery; import com.apache.hadoop.hbase.client.jdo.query.UpdateQuery;
/**
- Hbase JDO Example.
- dependency library.
-
- commons-beanutils.jar
-
- commons-pool-1.5.5.jar
-
- hbase0.90.0-transactionl.jar
- you can expand Delete,Select,Update,Insert Query classes.
*/ public class HBaseExample { public static void main(String[] args) throws Exception { AbstractHBaseDBO dbo = new HBaseDBOImpl();
//*drop if table is already exist.*
if(dbo.isTableExist("user")){
dbo.deleteTable("user");
}
//*create table*
dbo.createTableIfNotExist("user",HBaseOrder.DESC,"account");
//dbo.createTableIfNotExist("user",HBaseOrder.ASC,"account");
//create index.
String[] cols={"id","name"};
dbo.addIndexExistingTable("user","account",cols);
//insert
InsertQuery insert = dbo.createInsertQuery("user");
UserBean bean = new UserBean();
bean.setFamily("account");
bean.setAge(20);
bean.setEmail("[email protected]");
bean.setId("ncanis");
bean.setName("ncanis");
bean.setPassword("1111");
insert.insert(bean);
//select 1 row
SelectQuery select = dbo.createSelectQuery("user");
UserBean resultBean = (UserBean)select.select(bean.getRow(),UserBean.class);
// select column value.
String value = (String)select.selectColumn(bean.getRow(),"account","id",String.class);
// search with option (QSearch has EQUAL, NOT_EQUAL, LIKE)
// select id,password,name,email from account where id='ncanis' limit startRow,20
HBaseParam param = new HBaseParam();
param.setPage(bean.getRow(),20);
param.addColumn("id","password","name","email");
param.addSearchOption("id","ncanis",QSearch.EQUAL);
select.search("account", param, UserBean.class);
// search column value is existing.
boolean isExist = select.existColumnValue("account","id","ncanis".getBytes());
// update password.
UpdateQuery update = dbo.createUpdateQuery("user");
Hashtable<String, byte[]> colsTable = new Hashtable<String, byte[]>();
colsTable.put("password","2222".getBytes());
update.update(bean.getRow(),"account",colsTable);
//delete
DeleteQuery delete = dbo.createDeleteQuery("user");
delete.deleteRow(resultBean.getRow());
////////////////////////////////////
// etc
// HTable pool with apache commons pool
// borrow and release. HBasePoolManager(maxActive, minIdle etc..)
IndexedTable table = dbo.getPool().borrow("user");
dbo.getPool().release(table);
// upload bigFile by hadoop directly.
HBaseBigFile bigFile = new HBaseBigFile();
File file = new File("doc/movie.avi");
FileInputStream fis = new FileInputStream(file);
Path rootPath = new Path("/files/");
String filename = "movie.avi";
bigFile.uploadFile(rootPath,filename,fis,true);
// receive file stream from hadoop.
Path p = new Path(rootPath,filename);
InputStream is = bigFile.path2Stream(p,4096);
} }
Scala
클래스패스 설정 (Setting the Classpath)
HBase와 함께 Scala를 사용하려면 CLASSPATH에 HBase 클래스패스와 코드에 필요한 Scala JAR이 포함되어야 해요. 먼저 HBase RegionServer 프로세스가 실행 중인 서버에서 다음 명령을 사용해 HBase 클래스패스를 얻으세요.
$ ps aux |grep regionserver| awk -F 'java.library.path=' {'print $2'} | awk {'print $1'} /usr/lib/hadoop/lib/native:/usr/lib/hbase/lib/native/Linux-amd64-64
$CLASSPATH 환경 변수를 이전 단계에서 찾은 경로와 scala-library.jar의 경로 및 프로젝트에 필요한 각 추가 Scala 관련 JAR을 포함하도록 설정하세요.
$ export CLASSPATH=$CLASSPATH:/usr/lib/hadoop/lib/native:/usr/lib/hbase/lib/native/Linux-amd64-64:/path/to/scala-library.jar
Scala SBT 파일 (Scala SBT File)
build.sbt 파일은 HBase와 함께 동작하려면 다음 resolvers와 libraryDependencies가 필요해요.
resolvers += "Apache HBase" at "https://repository.apache.org/content/repositories/releases"
resolvers += "Thrift" at "https://people.apache.org/~rawson/repo/"
libraryDependencies ++= Seq( "org.apache.hadoop" % "hadoop-core" % "0.20.2", "org.apache.hbase" % "hbase" % "0.90.4" )
Scala 코드 예시 (Example Scala Code)
이 예제는 HBase 테이블을 나열하고, 새 테이블을 만들고, 행을 추가하고, 행의 값을 가져와요.
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName} import org.apache.hadoop.hbase.client.{Admin, Connection, ConnectionFactory, Get, Put} import org.apache.hadoop.hbase.util.Bytes
val conf = HBaseConfiguration.create() val connection = ConnectionFactory.createConnection(conf); val admin = connection.getAdmin();
// list the tables val listtables = admin.listTables() listtables.foreach(println)
// let's insert some data in 'mytable' and get the row val table = connection.getTable(TableName.valueOf("mytable"))
val theput = new Put(Bytes.toBytes("rowkey1"))
theput.addColumn(Bytes.toBytes("ids"),Bytes.toBytes("id1"),Bytes.toBytes("one")) table.put(theput)
val theget = new Get(Bytes.toBytes("rowkey1")) val result = table.get(theget) val value = result.value() println(Bytes.toString(value))
Jython
클래스패스 설정 (Setting the Classpath)
HBase와 함께 Jython을 사용하려면 CLASSPATH에 HBase 클래스패스와 코드에 필요한 Jython JAR이 포함되어야 해요.
jython.jar와 프로젝트에 필요한 각 추가 Jython 관련 JAR이 있는 디렉터리 경로를 설정하세요. 그런 다음 $JYTHON_HOME env 변수를 가리키도록 HBASE_CLASSPATH를 export하세요.
$ export HBASE_CLASSPATH=/directory/jython.jar
클래스패스에 HBase와 Hadoop JAR이 있는 Jython 셸을 시작하세요:
$ bin/hbase org.python.util.jython
Jython 코드 예시 (Jython Code Examples)
예제: Jython으로 테이블 생성, 채우기, Get, Delete
다음 Jython 코드 예제는 테이블을 확인하고, 존재하면 삭제한 뒤 생성해요. 그런 다음 데이터로 테이블을 채우고 데이터를 가져와요.
import java.lang from org.apache.hadoop.hbase import HBaseConfiguration, HTableDescriptor, HColumnDescriptor, TableName from org.apache.hadoop.hbase.client import Admin, Connection, ConnectionFactory, Get, Put, Result, Table from org.apache.hadoop.conf import Configuration
First get a conf object. This will read in the configuration
that is out in your hbase-*.xml files such as location of the
hbase master node.
conf = HBaseConfiguration.create() connection = ConnectionFactory.createConnection(conf) admin = connection.getAdmin()
Create a table named 'test' that has a column family
named 'content'.
tableName = TableName.valueOf("test") table = connection.getTable(tableName)
desc = HTableDescriptor(tableName) desc.addFamily(HColumnDescriptor("content"))
Drop and recreate if it exists
if admin.tableExists(tableName): admin.disableTable(tableName) admin.deleteTable(tableName)
admin.createTable(desc)
Add content to 'column:' on a row named 'row_x'
row = 'row_x' put = Put(row) put.addColumn("content", "qual", "some content") table.put(put)
Now fetch the content just added, returns a byte[]
get = Get(row)
result = table.get(get) data = java.lang.String(result.getValue("content", "qual"), "UTF8")
print "The fetched row contains the value '%s'" % data
예제: Jython으로 테이블 스캔
이 예제는 테이블을 스캔하고 주어진 패밀리 퀄리파이어와 일치하는 결과를 반환해요.
import java.lang from org.apache.hadoop.hbase import TableName, HBaseConfiguration from org.apache.hadoop.hbase.client import Connection, ConnectionFactory, Result, ResultScanner, Table, Admin from org.apache.hadoop.conf import Configuration conf = HBaseConfiguration.create() connection = ConnectionFactory.createConnection(conf) admin = connection.getAdmin() tableName = TableName.valueOf('wiki') table = connection.getTable(tableName)
cf = "title" attr = "attr" scanner = table.getScanner(cf) while 1: result = scanner.next() if not result: break print java.lang.String(result.row), java.lang.String(result.getValue(cf, attr))