hbase的CoprocessorProtocol及一个简单的通用扩展实现

原文:http://zhang-xzhi-xjtu.iteye.com/blog/1926732

hbase中的CoprocessorProtocol机制. 


CoprocessorProtocol的原理比较简单,近似于一个mapreduce框架。由client将scan分解为面向多个region的请求,并行发送请求到多个region,然后client做一个reduce的操作,得到最后的结果。 


先看一个例子,使用hbase的AggregationClient可以做到简单的面向单个column的统计。 
Java代码   收藏代码
  1. @Test  
  2. public void testAggregationClient() throws Throwable {  
  3.   
  4.     LongColumnInterpreter columnInterpreter = new LongColumnInterpreter();  
  5.   
  6.     AggregationClient aggregationClient = new AggregationClient(  
  7.             CommonConfig.getConfiguration());  
  8.     Scan scan = new Scan();  
  9.   
  10.     scan.addColumn(ColumnFamilyName, QName1);  
  11.   
  12.     Long max = aggregationClient.max(TableNameBytes, columnInterpreter,  
  13.             scan);  
  14.     Assert.assertTrue(max.longValue() == 100);  
  15.   
  16.     Long min = aggregationClient.min(TableNameBytes, columnInterpreter,  
  17.             scan);  
  18.     Assert.assertTrue(min.longValue() == 20);  
  19.   
  20.     Long sum = aggregationClient.sum(TableNameBytes, columnInterpreter,  
  21.             scan);  
  22.     Assert.assertTrue(sum.longValue() == 120);  
  23.   
  24.     Long count = aggregationClient.rowCount(TableNameBytes,  
  25.             columnInterpreter, scan);  
  26.     Assert.assertTrue(count.longValue() == 4);  
  27.   
  28. }  


看下hbase的源码。AggregateImplementation 
Java代码   收藏代码
  1. @Override  
  2.   public  T getMax(ColumnInterpreter ci, Scan scan)  
  3.       throws IOException {  
  4.     T temp;  
  5.     T max = null;  
  6.     InternalScanner scanner = ((RegionCoprocessorEnvironment) getEnvironment())  
  7.         .getRegion().getScanner(scan);  
  8.     List results = new ArrayList();  
  9.     byte[] colFamily = scan.getFamilies()[0];  
  10.     byte[] qualifier = scan.getFamilyMap().get(colFamily).pollFirst();  
  11.     // qualifier can be null.  
  12.     try {  
  13.       boolean hasMoreRows = false;  
  14.       do {  
  15.         hasMoreRows = scanner.next(results);  
  16.         for (KeyValue kv : results) {  
  17.           temp = ci.getValue(colFamily, qualifier, kv);  
  18.           max = (max == null || (temp != null && ci.compare(temp, max) > 0)) ? temp : max;  
  19.         }  
  20.         results.clear();  
  21.       } while (hasMoreRows);  
  22.     } finally {  
  23.       scanner.close();  
  24.     }  
  25.     log.info("Maximum from this region is "  
  26.         + ((RegionCoprocessorEnvironment) getEnvironment()).getRegion()  
  27.             .getRegionNameAsString() + ": " + max);  
  28.     return max;  
  29.   }  

这里由于 
Java代码   收藏代码
  1. byte[] colFamily = scan.getFamilies()[0];  
  2. byte[] qualifier = scan.getFamilyMap().get(colFamily).pollFirst();  

所以,hbase自带的Aggregate函数,只能面向单列进行统计。 

当我们想对多列进行Aggregate,并同时进行countRow时,有以下选择。 
1 scan出所有的row,程序自己进行Aggregate和count。 
2 使用AggregationClient,调用多次,得到所有的结果。由于多次调用,有一致性问题。 
3 自己扩展CoprocessorProtocol。 

首先我们可以写一个protocol的通用框架。 
定义protocol接口。 
Java代码   收藏代码
  1. public interface MyCoprocessorProtocol extends CoprocessorProtocol {  
  2.   
  3.     public static final long VERSION = 1L;  
  4.   
  5.     public  T handle(RowHandler rowHandler, Scan scan) throws IOException;  
  6. }  


定义该protocol的实现。 
Java代码   收藏代码
  1. public class MyEndpointImpl extends BaseEndpointCoprocessor implements  
  2.         MyCoprocessorProtocol {  
  3.   
  4.     protected static Log log = LogFactory.getLog(MyEndpointImpl.class);  
  5.   
  6.     @Override  
  7.     public ProtocolSignature getProtocolSignature(String protocol,  
  8.             long version, int clientMethodsHashCode) throws IOException {  
  9.         if (MyCoprocessorProtocol.class.getName().equals(protocol)) {  
  10.             return new ProtocolSignature(MyCoprocessorProtocol.VERSION, null);  
  11.         }  
  12.         throw new IOException("Unknown protocol: " + protocol);  
  13.     }  
  14.   
  15.     @Override  
  16.     public  T handle(RowHandler rowHandler, Scan scan) throws IOException {  
  17.   
  18.         InternalScanner scanner = ((RegionCoprocessorEnvironment) getEnvironment())  
  19.                 .getRegion().getScanner(scan);  
  20.         List results = new ArrayList();  
  21.         T t = rowHandler.getInitValue();  
  22.         try {  
  23.             boolean hasMoreRows = false;  
  24.   
  25.             do {  
  26.                 hasMoreRows = scanner.next(results);  
  27.                 log.debug("scanner result : " + results + " hasMoreRows = "  
  28.                         + hasMoreRows);  
  29.                 t = rowHandler.handle(results, t);  
  30.   
  31.                 results.clear();  
  32.             } while (hasMoreRows);  
  33.         } finally {  
  34.             scanner.close();  
  35.         }  
  36.         return t;  
  37.     }  
  38. }  


定义一个rowHandler。 
Java代码   收藏代码
  1. public interface RowHandler extends Writable {  
  2.   
  3.     public T getInitValue();  
  4.   
  5.     public T handle(List keyValues, T t);  
  6. }  


定义一个reduce。 
Java代码   收藏代码
  1. public interface MyReducer {  
  2.   
  3.     public R getInitValue();  
  4.   
  5.     public R reduce(R r, T t);  
  6. }  


定义一个client。 
Java代码   收藏代码
  1. public class MyClient {  
  2.   
  3.     HTableInterface table;  
  4.   
  5.     public MyClient(HTableInterface table) {  
  6.         this.table = table;  
  7.     }  
  8.   
  9.     public  R call(final byte[] tableName,  
  10.             final RowHandler howHandler, final MyReducer myReducer,  
  11.             final Scan scan) throws Throwable {  
  12.   
  13.         class MyCallBack implements Batch.Callback {  
  14.             R r = myReducer.getInitValue();  
  15.   
  16.             R getResult() {  
  17.                 return r;  
  18.             }  
  19.   
  20.             @Override  
  21.             public synchronized void update(byte[] region, byte[] row, T result) {  
  22.                 r = myReducer.reduce(r, result);  
  23.             }  
  24.         }  
  25.   
  26.         MyCallBack myCallBack = new MyCallBack();  
  27.   
  28.         try {  
  29.             table.coprocessorExec(MyCoprocessorProtocol.class,  
  30.                     scan.getStartRow(), scan.getStopRow(),  
  31.                     new Batch.Call() {  
  32.                         @Override  
  33.                         public T call(MyCoprocessorProtocol instance)  
  34.                                 throws IOException {  
  35.                             return instance.handle(howHandler, scan);  
  36.                         }  
  37.                     }, myCallBack);  
  38.         } finally {  
  39.             table.close();  
  40.         }  
  41.   
  42.         return myCallBack.getResult();  
  43.     }  
  44. }  


这样,我们就有了一个protocol的通用框架。 
假设我们要一个count的功能。 
则只需要实现对应的handler和reducer。 

Java代码   收藏代码
  1. public class CountHandler implements RowHandler {  
  2.   
  3.     @Override  
  4.     public void readFields(DataInput arg0) throws IOException {  
  5.     }  
  6.   
  7.     @Override  
  8.     public void write(DataOutput arg0) throws IOException {  
  9.     }  
  10.   
  11.     @Override  
  12.     public Long getInitValue() {  
  13.         return 0L;  
  14.     }  
  15.   
  16.     @Override  
  17.     public Long handle(List keyValues, Long t) {  
  18.         if (!keyValues.isEmpty()) {  
  19.             return t + 1;  
  20.         } else {  
  21.             return t;  
  22.         }  
  23.     }  
  24.   
  25. }  
  26.   
  27. public class CountReducer implements MyReducer {  
  28.   
  29.     @Override  
  30.     public Long getInitValue() {  
  31.         return 0L;  
  32.     }  
  33.   
  34.     @Override  
  35.     public Long reduce(Long r, Long t) {  
  36.         return r + t;  
  37.     }  
  38. }  



假设我们要实现多个列的sum和全部结果的row,我们也只是通过添加hander,reducer和result来实现。 
Java代码   收藏代码
  1. public class CountAndSumResult implements Writable {  
  2.   
  3.     private List resultList = new ArrayList();  
  4.   
  5.     private Long count = 0L;  
  6.   
  7.     public CountAndSumResult() {  
  8.     }  
  9.   
  10.     public CountAndSumResult(int resultSize) {  
  11.         for (int i = 0; i < resultSize; i++) {  
  12.             resultList.add(0L);  
  13.         }  
  14.     }  
  15.   
  16.     public Long getCount() {  
  17.         return count;  
  18.     }  
  19.   
  20.     public void setCount(Long count) {  
  21.         this.count = count;  
  22.     }  
  23.   
  24.     public Long getSum(int i) {  
  25.         return resultList.get(i);  
  26.     }  
  27.   
  28.     public void setSum(int i, Long sum) {  
  29.         resultList.set(i, sum);  
  30.     }  
  31.   
  32.     public int getResultSize() {  
  33.         return resultList.size();  
  34.     }  
  35.   
  36.     @Override  
  37.     public void write(DataOutput out) throws IOException {  
  38.         out.writeLong(count);  
  39.         out.writeInt(resultList.size());  
  40.         for (Long v : resultList) {  
  41.             out.writeLong(v);  
  42.         }  
  43.     }  
  44.   
  45.     @Override  
  46.     public void readFields(DataInput in) throws IOException {  
  47.         count = in.readLong();  
  48.         int size = in.readInt();  
  49.         for (int i = 0; i < size; i++) {  
  50.             resultList.add(in.readLong());  
  51.         }  
  52.     }  
  53.   
  54. }  
  55.   
  56.   
  57. public class CountAndSumHandler implements RowHandler {  
  58.   
  59.     private List columns = new ArrayList();  
  60.   
  61.     public CountAndSumHandler() {  
  62.     }  
  63.   
  64.     public CountAndSumHandler(List columns) {  
  65.         super();  
  66.         this.columns = columns;  
  67.     }  
  68.   
  69.     @Override  
  70.     public void write(DataOutput out) throws IOException {  
  71.         out.writeInt(columns.size());  
  72.         for (String s : columns) {  
  73.             out.writeUTF(s);  
  74.         }  
  75.   
  76.     }  
  77.   
  78.     @Override  
  79.     public void readFields(DataInput in) throws IOException {  
  80.         int size = in.readInt();  
  81.         for (int i = 0; i < size; i++) {  
  82.             columns.add(in.readUTF());  
  83.         }  
  84.     }  
  85.   
  86.     @Override  
  87.     public CountAndSumResult handle(List keyValues,  
  88.             CountAndSumResult t) {  
  89.   
  90.         if (!keyValues.isEmpty()) {  
  91.             t.setCount(t.getCount() + 1);  
  92.         }  
  93.   
  94.         for (int i = 0; i < columns.size(); i++) {  
  95.             String column = columns.get(i);  
  96.             for (KeyValue kv : keyValues) {  
  97.                 if (column.equals(Bytes.toString(kv.getQualifier()))) {  
  98.                     byte[] value = kv.getValue();  
  99.                     if (value == null || value.length == 0) {  
  100.                     } else {  
  101.                         Long tValue = Bytes.toLong(value);  
  102.                         t.setSum(i, t.getSum(i) + tValue);  
  103.                     }  
  104.                     break;  
  105.                 }  
  106.             }  
  107.         }  
  108.   
  109.         return t;  
  110.     }  
  111.   
  112.     @Override  
  113.     public CountAndSumResult getInitValue() {  
  114.         return new CountAndSumResult(columns.size());  
  115.     }  
  116.   
  117. }  
  118.   
  119.   
  120. public class CountAndSumReducer implements  
  121.         MyReducer {  
  122.   
  123.     @Override  
  124.     public CountAndSumResult getInitValue() {  
  125.         return null;  
  126.     }  
  127.   
  128.     @Override  
  129.     public CountAndSumResult reduce(CountAndSumResult r, CountAndSumResult t) {  
  130.         if (r == null) {  
  131.             return t;  
  132.         }  
  133.         if (t == null) {  
  134.             return r;  
  135.         }  
  136.         r.setCount(r.getCount() + t.getCount());  
  137.   
  138.         int size = r.getResultSize();  
  139.         for (int i = 0; i < size; i++) {  
  140.             r.setSum(i, r.getSum(i) + t.getSum(i));  
  141.         }  
  142.         return r;  
  143.     }  
  144.   
  145. }  


有了CoprocessorProtocol,可以扩展出来很多的功能,这个机制还是很强大的。

你可能感兴趣的:(hbase)