2018년/DataBase

3장 클라이언트 API : 기본기능 - Delete 메서드

위지원 2018. 8. 17. 19:53
 

야호!! 드디어 삭제다!

2018/08/10 - [2018년 하반기/HBASE] - 3장 클라이언트 API : 기본기능 - Put 메서드

2018/08/17 - [2018년 하반기/HBASE] - 3장 클라이언트 API : 기본기능 - Get 메서드




CRUD(Create,Read,Update,Delete) 기능

출처: http://weejw.tistory.com/category/2018년 하반기/HBASE# [위지원의 블로그]
CRUD(Create,Read,Update,Delete) 기능

출처: http://weejw.tistory.com/category/2018년 하반기/HBASE# [위지원의 블로그]

CRUD(Create,Read,Update,Delete) 기능


2.Get 메서드



출처: http://weejw.tistory.com/category/2018년 하반기/HBASE [위지원의 블로그]




CRUD(Create,Read,Update,Delete) 기능

출처: http://weejw.tistory.com/category/2018년 하반기/HBASE# [위지원의 블로그]
CRUD(Create,Read,Update,Delete) 기능

출처: http://weejw.tistory.com/category/2018년 하반기/HBASE# [위지원의 블로그]

CRUD(Create,Read,Update,Delete) 기능


2.Get 메서드



출처: http://weejw.tistory.com/category/2018년 하반기/HBASE [위지원의 블로그]

CRUD(Create,Read,Update,Delete) 기능

3.Delete 메서드


Delete 라는 클래스를 이용해서 삭제를 수행할 수 있다. Delete 객체를 생성해서 테이블의 delete 메서드로 넘겨줄 수 있다.





delete 객체를 생성하는 방법은 역시 여러가지가 있지만, 그 중에서 몇개만 살펴보자면 가장 기본인 row만 넘겨주는 경우와 timestamp까지 넘겨주는 경우가 있다.



Delete class의 다음 메서드를 사용하면 row에서 삭제하고자 하는 데이터의 범위를 좁힐 수 있다.





Table table = connection.getTable(TableName.valueOf("testtable"));

Delete delete = new Delete(Bytes.toBytes("row1")); //특정 row를 지정한다.

delete.setTimestamp(1); // row 삭제를 위한 TimeStemp를 지정한다.

delete.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1")); //컬럼하나의 모든 version을 삭제한다.
delete.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual2"), 3); // 특정 version과 그 이전버전을 모두 삭제한다.
//변경되었다. version이 아니라 TimeStemp를 넘겨줘야한다(API참조)
delete.addFamily(Bytes.toBytes("colfam1")); //Family를 모두 삭제한다.
delete.addFamily(Bytes.toBytes("colfam1"), 3); //특정 version과 그 이전 버전을 모두 삭제한다.

table.delete(delete);


위에 다양한 방법중에 특정 퀄리파이어를 삭제한 장면이다.


이것은 컬럼 패밀리를 삭제해본 모습이다.


version삭제가 안된다.. 한참을 고민한끝에 그것은 바로!! timestamp 값을 지정해서 값을 PUT! 해줘야한다는 것이였다..^^;; 지난번 배운 Put 메서드에서 보면 long ts로 timestemp를 지정해서 생성할 수 있었다. 해보자. (책을 너무 대충읽오 있나보다)



일반으로 지정된 시간에 대해서 삭제하려고 하면 자바 API로 하면 아래와 같이 오류가 뜬다. 분명 아규먼트 타입상 Long의 자리인데..음..,,

Delete delete = new Delete(Bytes.toBytes("row1"));

delete.addColumns(Bytes.toBytes("colfam1"), Bytes.toBytes("qual2"), 1534501337711);

같은 코드를 shell에서 외쳤을때는 전혀 문제가 없다..ㅠ_ㅠ 왜일까?


Delete 리스트


Delete 인스턴스의 리스트를 생성해서 한번에 삭제한다. 위에서 소개할때 두번째에 있던 친구이다.



이번에는 바~로 코딩에 들어가보겠다.!!


아래 코드를 이용하여서 비어있는 테이블에 데이터를 삽입해주자.

Put put = new Put(Bytes.toBytes("row1"));

put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),2,Bytes.toBytes("val2"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),3,Bytes.toBytes("val3"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"),4,Bytes.toBytes("val4"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),5,Bytes.toBytes("val5"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),6,Bytes.toBytes("val6"));

Put put2 = new Put(Bytes.toBytes("row2"));

put2.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put2.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),2,Bytes.toBytes("val2"));
put2.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),3,Bytes.toBytes("val3"));
put2.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"),4,Bytes.toBytes("val4"));
put2.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),5,Bytes.toBytes("val5"));
put2.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),6,Bytes.toBytes("val6"));

Put put3 = new Put(Bytes.toBytes("row3"));

put3.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put3.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),2,Bytes.toBytes("val2"));
put3.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),3,Bytes.toBytes("val3"));
put3.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"),4,Bytes.toBytes("val4"));
put3.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),5,Bytes.toBytes("val5"));
put3.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),6,Bytes.toBytes("val6"));


Table table = connection.getTable(TableName.valueOf("testtable"));
table.put(put);
table.put(put2);
table.put(put3);

hbase(main):006:0> scan 'testtable',{VERSIONS=>5}
ROW                     COLUMN+CELL                                                       
 row1                   column=colfam1:qual1, timestamp=2, value=val2                     
 row1                   column=colfam1:qual1, timestamp=1, value=val1                     
 row1                   column=colfam1:qual2, timestamp=3, value=val3                     
 row1                   column=colfam2:qual2, timestamp=4, value=val4                     
 row1                   column=colfam2:qual3, timestamp=6, value=val6                     
 row1                   column=colfam2:qual3, timestamp=5, value=val5                     
 row2                   column=colfam1:qual1, timestamp=2, value=val2                     
 row2                   column=colfam1:qual1, timestamp=1, value=val1                     
 row2                   column=colfam1:qual2, timestamp=3, value=val3                     
 row2                   column=colfam2:qual2, timestamp=4, value=val4                     
 row2                   column=colfam2:qual3, timestamp=6, value=val6                     
 row2                   column=colfam2:qual3, timestamp=5, value=val5                     
 row3                   column=colfam1:qual1, timestamp=1, value=val1                     
 row3                   column=colfam1:qual2, timestamp=3, value=val3                     
 row3                   column=colfam1:qual2, timestamp=2, value=val2                     
 row3                   column=colfam2:qual2, timestamp=4, value=val4                     
 row3                   column=colfam2:qual3, timestamp=6, value=val6                     
 row3                   column=colfam2:qual3, timestamp=5, value=val5                     
3 row(s)
Took 0.1618 seconds 


그리고 나서 Delete List를 생성하고 그안에 delete 객체를 생성해서 add()한 뒤 삭제해주자.


List<Delete> deletes = new ArrayList<Delete>();

Delete delete1 = new Delete(Bytes.toBytes("row1"));
delete1.setTimestamp(4); //row1에서 timestemp가 4인것과 그것보다 낮은것들을 삭제한다.
deletes.add(delete1);

Delete delete2 = new Delete(Bytes.toBytes("row2"));
delete2.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1")); //row2에서 qual1의 최신버전 1개 삭제
delete2.addColumns(Bytes.toBytes("colfam2"), Bytes.toBytes("qual3"), 5); //qual3중에 timestemp가 5인것
deletes.add(delete2);

Delete delete3 = new Delete(Bytes.toBytes("row3"));
delete3.addFamily(Bytes.toBytes("colfam1")); //row3의 colfam1을 삭제한다.
delete3.addFamily(Bytes.toBytes("colfam2"), 3); //row3의 colfam2중에서 timestemp가 3인것과 그보다 낮은 것을 삭제한다.
deletes.add(delete3);

table.delete(deletes);

hbase(main):007:0> scan 'testtable',{VERSIONS=>5}
ROW                    COLUMN+CELL                                                       
 row1                   column=colfam2:qual3, timestamp=6, value=val6                     
 row1                   column=colfam2:qual3, timestamp=5, value=val5                     
 row2                   column=colfam1:qual1, timestamp=1, value=val1                     
 row2                   column=colfam1:qual2, timestamp=3, value=val3                     
 row2                   column=colfam2:qual2, timestamp=4, value=val4                     
 row2                   column=colfam2:qual3, timestamp=6, value=val6                     
 row3                   column=colfam2:qual2, timestamp=4, value=val4                     
 row3                   column=colfam2:qual3, timestamp=6, value=val6                     
 row3                   column=colfam2:qual3, timestamp=5, value=val5                     
3 row(s)
Took 0.0964 seconds


위에 메소드에다가 버그를 하나 심어주고 확인을 해보자.


Delete delete4 = new Delete(Bytes.toBytes("row2"));
delete4.addColumn(Bytes.toBytes("BOGUS"),Bytes.toBytes("qual1"));
deletes.add(delete4);

try {
table.delete(deletes);
} catch (Exception e) {
System.err.println("Error: " + e);
}
table.close();

System.out.println("Deletes length: " + deletes.size()); //리스트에 남아있는 친구가 있는지 확인을 해보자
for (Delete delete : deletes) {
System.out.println(delete);
}

그럼 아래와 같이 굉장히 길게 에러가 출력되는데 중요한건 가장 마지막에 있는 단 하나! 리스트에는 delete 객체가 단하나! 남아있다.


Error: org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 1 action:

org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException: Column family BOGUS does not exist in region testtable,,1534504182114.f9ed523be3cbf3a9902c1b7718d08937. in table 'testtable', {NAME => 'colfam1', VERSIONS => '10', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}, {NAME => 'colfam2', VERSIONS => '10', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
        at org.apache.hadoop.hbase.regionserver.RSRpcServices.doBatchOp(RSRpcServices.java:1038)
        at org.apache.hadoop.hbase.regionserver.RSRpcServices.doNonAtomicBatchOp(RSRpcServices.java:961)
        at org.apache.hadoop.hbase.regionserver.RSRpcServices.doNonAtomicRegionMutation(RSRpcServices.java:924)
        at org.apache.hadoop.hbase.regionserver.RSRpcServices.multi(RSRpcServices.java:2673)
        at org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:42014)
        at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:409)
        at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:130)
        at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:324)
        at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:304)
: 1 time, servers with issues: netdb.slave2.com,16020,1534483987538
Deletes length: 1
{"totalColumns":1,"row":"row2","families":{"BOGUS":[{"qualifier":"qual1","vlen":0,"tag":[],"timestamp":9223372036854775807}]},"ts":9223372036854775807}



원자적 '확인 후 삭제' 연산


힘들어죽겠다.자 다음은 원자적 확인후 삭제이다. Put에서 한것처럼 확인을 먼저한다음에 라는 전제 조건이 붙은 것 뿐이다.

table class의 API를 확인하니 오호호호호 Deprecated... checkAndMutate를 대신 애용해달라는 말이 보인다. 일단 checkAndDelete예제부터 해보자.





Put put = new Put(Bytes.toBytes("row1"));

put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),2,Bytes.toBytes("val2"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual3"),3,Bytes.toBytes("val3"));

put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"),2,Bytes.toBytes("val2"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),3,Bytes.toBytes("val3"));


table.put(put); //새로운 값들을 삽입하고

Delete delete1 = new Delete(Bytes.toBytes("row1"));
delete1.addColumns(Bytes.toBytes("colfam1"), Bytes.toBytes("qual3"));

boolean res1 = table.checkAndDelete(Bytes.toBytes("row1"),
Bytes.toBytes("colfam2"), Bytes.toBytes("qual3"), null, delete1); //앞에 조건이 맞으면(null이라는) 마지막 delete1 연산을 수행한다.
System.out.println("Delete 1 successful: " + res1);

Delete delete2 = new Delete(Bytes.toBytes("row1"));
delete2.addColumns(Bytes.toBytes("colfam2"), Bytes.toBytes("qual3")); //삭제한다.
table.delete(delete2);

boolean res2 = table.checkAndDelete(Bytes.toBytes("row1"),
Bytes.toBytes("colfam2"), Bytes.toBytes("qual3"), null, delete1); //바로 위에서 삭제했기때문에 value부분에 전달한 파라미터 null과 조건이 맞기때문에 이번에는 true가 출력된다.

* delete연산은 맞는게 없으면 아무것도 수행하지 않는다.
System.out.println("Delete 2 successful: " + res2);

Delete delete3 = new Delete(Bytes.toBytes("row2"));
delete3.addFamily(Bytes.toBytes("colfam1"));

try{
boolean res4 = table.checkAndDelete(Bytes.toBytes("row1"),
Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"),
Bytes.toBytes("val1"), delete3);
System.out.println("Delete 3 successful: " + res4);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage()); //아래와 같이 에러가 발생한다. 앞에 조건은 부합하지만 delete3에서는 존재하지 않는 row2에 대해 언급했기때문이다.
}

hbase(main):028:0> scan 'testtable'
ROW                   COLUMN+CELL                                              
 row1                 column=colfam1:qual1, timestamp=1, value=val1            
 row1                 column=colfam1:qual2, timestamp=2, value=val2            
 row1                 column=colfam2:qual1, timestamp=1, value=val1            
 row1                 column=colfam2:qual2, timestamp=2, value=val2            
1 row(s)
Took 0.0417 seconds


Delete 1 successful: false
Delete 2 successful: true
Error: Failed 1 action: org.apache.hadoop.hbase.DoNotRetryIOException: Action's getRow must match
        at org.apache.hadoop.hbase.regionserver.HRegion.checkMutationType(HRegion.java:4149)
        at org.apache.hadoop.hbase.regionserver.HRegion.checkAndMutate(HRegion.java:4029)
        at org.apache.hadoop.hbase.regionserver.RSRpcServices.mutate(RSRpcServices.java:2837)
        at org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:42000)
        at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:409)
        at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:130)
        at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:324)
        at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:304)
: 1 time, servers with issues: netdb.slave1.com,16020,1534483984776


이번에는  checkandMutate를 실험해보자. 아래 코드를 보면 RowMutations라는 객체를 생성해서 확인을 하고 있다.


import org.apache.hadoop.hbase.filter.CompareFilter;


Table table = connection.getTable(TableName.valueOf("testtable"));

Put put = new Put(Bytes.toBytes("row1"));

put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual2"),2,Bytes.toBytes("val2"));
put.addColumn(Bytes.toBytes("colfam1"),Bytes.toBytes("qual3"),3,Bytes.toBytes("val3"));

put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual1"),1,Bytes.toBytes("val1"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"),2,Bytes.toBytes("val2"));
put.addColumn(Bytes.toBytes("colfam2"),Bytes.toBytes("qual3"),3,Bytes.toBytes("val3"));

table.put(put);

Put put2 = new Put(Bytes.toBytes("row1"));
put2.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"),
4, Bytes.toBytes("val99"));
put2.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual4"),
4, Bytes.toBytes("val100"));

Delete delete = new Delete(Bytes.toBytes("row1"));
delete.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual2"));

RowMutations mutations = new RowMutations(Bytes.toBytes("row1"));
mutations.add(put2);
mutations.add(delete);

boolean res1 = table.checkAndMutate(Bytes.toBytes("row1"),
Bytes.toBytes("colfam2"), Bytes.toBytes("qual1"),
CompareFilter.CompareOp.LESS, Bytes.toBytes("val1"), mutations);
System.out.println("Mutate 1 successful: " + res1); row1 colfam2:qual1 value의 값(1)과 val1과 비교한다. 더 작지 않기때문에 false

Put put3 = new Put(Bytes.toBytes("row1"));
put3.addColumn(Bytes.toBytes("colfam2"), Bytes.toBytes("qual1"), //row1 colfam2:qual1 value 값을 2로 변경한다.
4, Bytes.toBytes("val2"));
table.put(put3);

boolean res2 = table.checkAndMutate(Bytes.toBytes("row1"),
Bytes.toBytes("colfam2"), Bytes.toBytes("qual1"), 비교하면 row1 colfam2:qual1의 값(2)보다 val1이 더작다 true
CompareFilter.CompareOp.LESS, Bytes.toBytes("val1"), mutations); //true이기때문에 mutations의 OP가 수행된다.
System.out.println("Mutate 2 successful: " + res2);

Mutate 1 successful: false
Mutate 2 successful: true


hbase(main):007:0> scan 'testtable'
ROW                   COLUMN+CELL                                              
 row1                 column=colfam1:qual1, timestamp=4, value=val99           
 row1                 column=colfam1:qual3, timestamp=3, value=val3            
 row1                 column=colfam1:qual4, timestamp=4, value=val100          
 row1                 column=colfam2:qual1, timestamp=4, value=val2            
 row1                 column=colfam2:qual2, timestamp=2, value=val2            
 row1                 column=colfam2:qual3, timestamp=3, value=val3            
1 row(s)
Took 0.0747 seconds