Spark-Hbase操作以及过滤器

spark读写hbase

package com.huawei.bigdata.spark.examples

import java.io.{File, IOException}
import java.util

import com.esotericsoftware.kryo.Kryo
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{CellUtil, HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapreduce.TableInputFormat
import org.apache.hadoop.hbase.protobuf.ProtobufUtil
import org.apache.hadoop.hbase.util.{Base64, Bytes}
import org.apache.spark.serializer.KryoRegistrator
import org.apache.spark.{SparkConf, SparkContext}
import com.huawei.hadoop.security.LoginUtil

/**
  * calculate data from hbase1/hbase2,then update to hbase2
  */
object SparkHbasetoHbase {

  case class FemaleInfo(name: String, gender: String, stayTime: Int)

  def main(args: Array[String]) {

    val hadoopConf: Configuration  = new Configuration()
    if("kerberos".equalsIgnoreCase(hadoopConf.get("hadoop.security.authentication"))) {
      //security mode

      val userPrincipal = "sparkuser"
      val USER_KEYTAB_FILE = "user.keytab"
      val filePath = System.getProperty("user.dir") + File.separator + "conf" + File.separator
      val krbFile = filePath + "krb5.conf"
      val userKeyTableFile = filePath + USER_KEYTAB_FILE

      val ZKServerPrincipal = "zookeeper/hadoop.hadoop.com"
      val ZOOKEEPER_DEFAULT_LOGIN_CONTEXT_NAME: String = "Client"
      val ZOOKEEPER_SERVER_PRINCIPAL_KEY: String = "zookeeper.server.principal"

      LoginUtil.setJaasConf(ZOOKEEPER_DEFAULT_LOGIN_CONTEXT_NAME, userPrincipal, userKeyTableFile)
      LoginUtil.setZookeeperServerPrincipal(ZOOKEEPER_SERVER_PRINCIPAL_KEY, ZKServerPrincipal)
      LoginUtil.login(userPrincipal, userKeyTableFile, krbFile, hadoopConf)
    }

    val conf = new SparkConf().setAppName("SparkHbasetoHbase")
    conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    conf.set("spark.kryo.registrator", "com.huawei.bigdata.spark.examples.MyRegistrator")
    conf.setMaster("local[2]")
    val sc = new SparkContext(conf)
    // Create the configuration parameter to connect the HBase. The hbase-site.xml must be included in the classpath.
    val hbConf = HBaseConfiguration.create(sc.hadoopConfiguration)
    hbConf.set("hbase.zookeeper.quorum", "192.168.0.11,192.168.0.144,192.168.0.124")
    hbConf.set("hbase.zookeeper.property.clientPort", "2181")
    hbConf.set("hbase.rpc.timeout", "1800000")
    hbConf.set(TableInputFormat.INPUT_TABLE, "FAWVehicleStatusData") //table name
    // Declare the information of the table to be queried.
    val scan = new Scan()
    val proto = ProtobufUtil.toScan(scan)
    val scanToString = Base64.encodeBytes(proto.toByteArray)
    hbConf.set(TableInputFormat.SCAN, scanToString)

    //  Obtain the data in the table through the Spark interface.
    val rdd = sc.newAPIHadoopRDD(hbConf, classOf[TableInputFormat], classOf[ImmutableBytesWritable], classOf[Result])

    // Traverse every Partition in the HBase table1 and update the HBase table2
    // If less data, you can use rdd.foreach()
    rdd.map(r=>(
      Bytes.toString(r._2.getValue(Bytes.toBytes("info"),Bytes.toBytes("customer_id"))),
      Bytes.toString(r._2.getValue(Bytes.toBytes("info"),Bytes.toBytes("create_id")))
      )).toDF("customer_id","create_id").registerTempTable("shop")

    // 测试
val df2 = sqlContext.sql("SELECT customer_id FROM shop")
df2.rdd.foreachPartition(x => hBaseWriter(x))

    sc.stop()
  }

  /**
    * write to table2 in exetutor
    *
    * @param iterator partition data from table1
    */
  def hBaseWriter(iterator: Iterator[(ImmutableBytesWritable, Result)]): Unit = {
    //read hbase
    val tableName = "table2"
    val columnFamily = "cf"
    val qualifier = "cid"
    val conf = HBaseConfiguration.create()
    var table: Table = null
    var connection: Connection = null

    try {
      connection = ConnectionFactory.createConnection(conf)
      table = connection.getTable(TableName.valueOf(tableName))

      val iteratorArray = iterator.toArray
      val rowList = new util.ArrayList[Get]()
      for (row <- iteratorArray) {
        val get = new Get(row._2.getRow)
        rowList.add(get)
      }

      //get data from hbase table2
      val resultDataBuffer = table.get(rowList)

      //set data for hbase
      val putList = new util.ArrayList[Put]()
      for (i <- 0 until iteratorArray.size) {
        val resultData = resultDataBuffer(i) //hbase2 row
        if (!resultData.isEmpty) {
          //query hbase1Value
          var hbase1Value = ""
          val it = iteratorArray(i)._2.listCells().iterator()
          while (it.hasNext) {
            val c = it.next()
            // query table1 value by colomn family and colomn qualifier
            if (columnFamily.equals(Bytes.toString(CellUtil.cloneFamily(c)))
              && qualifier.equals(Bytes.toString(CellUtil.cloneQualifier(c)))) {
              hbase1Value = Bytes.toString(CellUtil.cloneValue(c))
            }
          }

          val hbase2Value = Bytes.toString(resultData.getValue(columnFamily.getBytes, qualifier.getBytes))
          val put = new Put(iteratorArray(i)._2.getRow)

          //calculate result value
          val resultValue = hbase1Value.toInt + hbase2Value.toInt
          //set data to put
          put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(qualifier), Bytes.toBytes(resultValue.toString))
          putList.add(put)
        }
      }

      if (putList.size() > 0) {
        table.put(putList)
      }
    } catch {
      case e: IOException =>
        e.printStackTrace();
    } finally {
      if (table != null) {
        try {
          table.close()
        } catch {
          case e: IOException =>
            e.printStackTrace();
        }
      }
      if (connection != null) {
        try {
          // Close the HBase connection.
          connection.close()
        } catch {
          case e: IOException =>
            e.printStackTrace()
        }
      }
    }
  }
}

/**
  * Define serializer class.
  */
class MyRegistrator extends KryoRegistrator {
  override def registerClasses(kryo: Kryo) {
    kryo.register(classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable])
    kryo.register(classOf[org.apache.hadoop.hbase.client.Result])
    kryo.register(classOf[Array[(Any, Any)]])
    kryo.register(classOf[Array[org.apache.hadoop.hbase.Cell]])
    kryo.register(classOf[org.apache.hadoop.hbase.NoTagsKeyValue])
    kryo.register(classOf[org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats])
  }

}

 

有两个参数类在各类Filter中经常出现,统一介绍下:
(1)比较运算符 CompareFilter.CompareOp
比较运算符用于定义比较关系,可以有以下几类值供选择:
EQUAL                                  相等
GREATER                              大于
GREATER_OR_EQUAL           大于等于
LESS                                      小于
LESS_OR_EQUAL                  小于等于
NOT_EQUAL                        不等于

(2)比较器  ByteArrayComparable
通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用:
BinaryComparator               匹配完整字节数组 
BinaryPrefixComparator     匹配字节数组前缀 
BitComparator
NullComparator
RegexStringComparator    正则表达式匹配
SubstringComparator        子串匹配

1. 结构(Structural)过滤器--FilterList

FilterList 代表一个过滤器链,它可以包含一组即将应用于目标数据集的过滤器,过滤器间具有“与” FilterList.Operator.MUST_PASS_ALL 和“或” FilterList.Operator.MUST_PASS_ONE 关系。

官网实例代码,两个“或”关系的过滤器的写法:
 

FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);   //数据只要满足一组过滤器中的一个就可以
SingleColumnValueFilter filter1 = new SingleColumnValueFilter(cf,column,CompareOp.EQUAL,Bytes.toBytes("my value"));
list.add(filter1);
SingleColumnValueFilter filter2 = new SingleColumnValueFilter(cf,column,CompareOp.EQUAL,Bytes.toBytes("my other value"));
list.add(filter2);
Scan scan = new Scan();
scan.setFilter(list);

2. 列值过滤器--SingleColumnValueFilter

SingleColumnValueFilter 用于测试列值相等 (CompareOp.EQUAL ), 不等 (CompareOp.NOT_EQUAL),或单侧范围 (CompareOp.GREATER)。
构造函数:
(1)比较的关键字是一个字符数组
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)

检查列值和字符串'2013-06-08' 相等:

 HTable table = HBaseDAO.getHTable("147patents");
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);  
        SingleColumnValueFilter filter = new SingleColumnValueFilter(
                Bytes.toBytes("patentinfo"),
                Bytes.toBytes("CREATE_TIME"),
                CompareOp.EQUAL,
                Bytes.toBytes("2013-06-08")
                );
        filterList.addFilter(filter);
        Scan scan = new Scan();
        scan.setFilter(filterList);
        ResultScanner rs = table.getScanner(scan);
        for (Result r : rs) {
            System.out.println("Scan: " + r);
        }
        table.close();  


(2)比较的关键字是一个比较器(比较器下一小节做介绍)
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)

支持值比较的正则表达式 -- RegexStringComparator
RegexStringComparator comp = new RegexStringComparator("2013-06-1.");//任意以2013-06-1打头的值
        
        SingleColumnValueFilter filter = new SingleColumnValueFilter(
                Bytes.toBytes("patentinfo"),
                Bytes.toBytes("CREATE_TIME"),
                CompareOp.EQUAL,
                comp
                );
检测一个子串是否存在于值中(大小写不敏感) -- SubstringComparator
SubstringComparator comp = new SubstringComparator("2013-06-1"); // looking for '2013-06-1e'
        
        SingleColumnValueFilter filter = new SingleColumnValueFilter(
                Bytes.toBytes("patentinfo"),
                Bytes.toBytes("CREATE_TIME"),
                CompareOp.EQUAL,
                comp
                );
、
BinaryPrefixComparator 前缀二进制比较器。与二进制比较器不同的是,只比较前缀是否相同。

Scan scan = new Scan();
BinaryPrefixComparator comp = new BinaryPrefixComparator(Bytes.toBytes("yting")); //
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("family"), Bytes.toBytes("qualifier"),  CompareOp.EQUAL, comp);
scan.setFilter(filter);

BinaryComparator 二进制比较器,用于按字典顺序比较 Byte 数据值。
Scan scan = new Scan();
BinaryComparator comp = new BinaryComparator(Bytes.toBytes("xmei")); //
ValueFilter filter = new ValueFilter(CompareOp.EQUAL, comp);
scan.setFilter(filter);

3. 键值元数据

由于HBase 采用键值对保存内部数据,键值元数据过滤器评估一行的键(ColumnFamily:Qualifiers)是否存在 , 对应前节所述值的情况。

基于列族过滤数据的FamilyFilter
构造函数:
FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)

        /**
         * FamilyFilter构造函数中第二个参数是ByteArrayComparable类型
         * ByteArrayComparable类参见“引言-参数基础”章节
         * 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:
         */
        FamilyFilter ff = new FamilyFilter(
                CompareFilter.CompareOp.EQUAL , 
                new BinaryComparator(Bytes.toBytes("pat"))   //表中不存在pat列族,过滤结果为空
                );
        FamilyFilter ff1 = new FamilyFilter(
                CompareFilter.CompareOp.EQUAL , 
                new BinaryPrefixComparator(Bytes.toBytes("pat"))   //表中存在以pat打头的列族patentinfo,过滤结果为该列族所有行
                );
        Scan scan = new Scan();
        scan.setFilter(ff1);
        ResultScanner rs = table.getScanner(scan); 

注意:
如果希望查找的是一个已知的列族,则使用 scan.addFamily(family)  比使用过滤器效率更高;
由于目前HBase对多列族支持不完善,所以该过滤器目前用途不大。
基于限定符Qualifier(列)过滤数据的QualifierFilter
构造函数:
QualifierFilter(CompareFilter.CompareOp op, ByteArrayComparable qualifierComparator)
/**
         * QualifierFilter构造函数中第二个参数是ByteArrayComparable类型
         * ByteArrayComparable类有以下子类可以使用:
         * *******************************************
         * BinaryComparator  匹配完整字节数组, 
         * BinaryPrefixComparator  匹配开始的部分字节数组, 
         * BitComparator, 
         * NullComparator, 
         * RegexStringComparator,   正则表达式匹配
         * SubstringComparator
         * *******************************************
         * 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:
         */
        QualifierFilter ff = new QualifierFilter(
                CompareFilter.CompareOp.EQUAL , 
                new BinaryComparator(Bytes.toBytes("belong"))   //表中不存在belong列,过滤结果为空
                );
        QualifierFilter ff1 = new QualifierFilter(
                CompareFilter.CompareOp.EQUAL , 
                new BinaryPrefixComparator(Bytes.toBytes("BELONG"))   //表中存在以BELONG打头的列BELONG_SITE,过滤结果为所有行的该列数据
                );
        Scan scan = new Scan();
        scan.setFilter(ff1);
        ResultScanner rs = table.getScanner(scan);  
说明:
一旦涉及到列(Qualifier),HBase就只认大写字母了!
该过滤器应该比FamilyFilter更常用!

 

基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter  ( 该功能用QualifierFilter也能实现 )
构造函数:
ColumnPrefixFilter(byte[] prefix) 

注意:
一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列。

官网示例代码,查找所有"abc"打头的列:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] prefix = Bytes.toBytes("abc");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnPrefixFilter(prefix);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

个人实测代码:
        HTable table = HBaseDAO.getHTable("147patents");
        //返回所有行中以BELONG打头的列的数据  
        ColumnPrefixFilter ff1 = new ColumnPrefixFilter(Bytes.toBytes("BELONG"));
        Scan scan = new Scan();
        scan.setFilter(ff1);
        ResultScanner rs = table.getScanner(scan);  
基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter
说明:
MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行为差不多,但可以指定多个前缀。

官方示例代码,查找所有"abc"或"xyz"打头的列:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")};
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new MultipleColumnPrefixFilter(prefixes);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

个人实测代码:
        HTable table = HBaseDAO.getHTable("147patents");
        
        byte[][] prefixes = new byte[][] {Bytes.toBytes("BELONG"), Bytes.toBytes("CREATE")};
        //返回所有行中以BELONG或者CREATE打头的列的数据
        MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);

        Scan scan = new Scan();
        scan.setFilter(ff);
        ResultScanner rs = table.getScanner(scan);  

 

 基于列范围(不是行范围)过滤数据ColumnRangeFilter
说明:
可用于获得一个范围的列,例如,如果你的一行中有百万个列,但是你只希望查看列名为bbbb到dddd的范围
该方法从 HBase 0.92 版本开始引入
一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列

构造函数:
ColumnRangeFilter(byte[] minColumn, boolean minColumnInclusive, byte[] maxColumn, boolean maxColumnInclusive)
参数解释:
minColumn - 列范围的最小值,如果为空,则没有下限;
minColumnInclusive - 列范围是否包含minColumn ;
maxColumn - 列范围最大值,如果为空,则没有上限;
maxColumnInclusive - 列范围是否包含maxColumn 。

官网示例代码,查找列名在"bbbb"到"dddd"范围的数据:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] startColumn = Bytes.toBytes("bbbb");
byte[] endColumn = Bytes.toBytes("bbdd");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

个人实测代码:
        HTable table = HBaseDAO.getHTable("147patents");
        
        byte[] startColumn = Bytes.toBytes("C");
        byte[] endColumn = Bytes.toBytes("D");
        //返回所有列中从C到D打头的范围的数据,实际返回类似CREATOR、CREATE_TIME、CHANNEL_CODE等列的数据
        ColumnRangeFilter ff = new ColumnRangeFilter(startColumn, true, endColumn, true);
        
        Scan scan = new Scan();
        scan.setFilter(ff);
        ResultScanner rs = table.getScanner(scan);  

4. RowKey

当需要根据行键特征查找一个范围的行数据时,使用Scan的startRow和stopRow会更高效,但是,startRow和stopRow只能匹配行键的开始字符,而不能匹配中间包含的字符:
        byte[] startColumn = Bytes.toBytes("aaa");
        byte[] endColumn = Bytes.toBytes("bbb");
        Scan scan = new Scan(startColumn,endColumn);
  
当需要针对行键进行更复杂的过滤时,可以使用RowFilter:

 

构造函数:
RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)
参数解释参见“引言-参数基础”章节。

个人实测代码:
        HTable table = HBaseDAO.getHTable("147patents");
        /**
         * rowkey格式为:创建日期_发布日期_ID_TITLE
         * 目标:查找  发布日期  为  2013-07-16  的数据
         */
        RowFilter rf = new RowFilter(
                CompareFilter.CompareOp.EQUAL , 
                new SubstringComparator("_2013-07-16_")   
                );
提取rowkey以01结尾数据
Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new RegexStringComparator(".*01$"));

提取rowkey以包含201407的数据
Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new SubstringComparator("201407"));


提取rowkey以123开头的数据
Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new BinaryPrefixComparator("123".getBytes()));


        Scan scan = new Scan();
        scan.setFilter(rf);
        ResultScanner rs = table.getScanner(scan);  
注意:
测试过程中尝试通过组合使用两个RowFilter(CompareFilter.CompareOp参数分别为GREATER_OR_EQUAL和LESS_OR_EQUAL),和SubstringComparator,过滤找出指定发布时间范围内的数据,但结果比较意外,不是预想的数据,估计比较运算符GREATER_OR_EQUAL和LESS_OR_EQUAL和比较器SubstringComparator组合使用效果不太好,慎用。

5.PageFilter

指定页面行数,返回对应行数的结果集。
需要注意的是,该过滤器并不能保证返回的结果行数小于等于指定的页面行数,因为过滤器是分别作用到各个region server的,它只能保证当前region返回的结果行数不超过指定页面行数。

构造函数:
PageFilter(long pageSize)

实测代码(从“2013-07-26”行开始,取5行):
            Scan scan = new Scan();
            scan.setStartRow(Bytes.toBytes("2013-07-26"));
            PageFilter pf = new PageFilter(5L);
            scan.setFilter(pf);
            ResultScanner rs = table.getScanner(scan);
            for (Result r : rs) {
                for (Cell cell : r.rawCells()) {
                    System.out.println("Rowkey : " + Bytes.toString(r.getRow())
                            + "   Familiy:Quilifier : "
                            + Bytes.toString(CellUtil.cloneQualifier(cell))
                            + "   Value : "
                            + Bytes.toString(CellUtil.cloneValue(cell))
                            + "   Time : " + cell.getTimestamp());
                }
            }  
注意:
由于该过滤器并不能保证返回的结果行数小于等于指定的页面行数,所以更好的返回指定行数的办法是ResultScanner.next(int nbRows) ,即:
            ResultScanner rs = table.getScanner(scan);
            for (Result r : rs.next(5)) {
                for (Cell cell : r.rawCells()) {
                    System.out.println("Rowkey : " + Bytes.toString(r.getRow())
                            + "   Familiy:Quilifier : "
                            + Bytes.toString(CellUtil.cloneQualifier(cell))
                            + "   Value : "
                            + Bytes.toString(CellUtil.cloneValue(cell))
                            + "   Time : " + cell.getTimestamp());
                }
            }  

6.SkipFilter

根据整行中的每个列来做过滤,只要存在一列不满足条件,整行都被过滤掉。
例如,如果一行中的所有列代表的是不同物品的重量,则真实场景下这些数值都必须大于零,我们希望将那些包含任意列值为0的行都过滤掉。
在这个情况下,我们结合ValueFilter和SkipFilter共同实现该目的:
scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0))));

构造函数:
SkipFilter(Filter filter) 

个人实测代码:
目前的数据:
hbase(main):009:0> scan 'rd_ns:itable'
ROW                         COLUMN+CELL
 100001                     column=info:address, timestamp=1405417403438, value=anywhere
 100001                     column=info:age, timestamp=1405417403438, value=24
 100001                     column=info:name, timestamp=1405417403438, value=zhangtao
 100002                     column=info:address, timestamp=1405417426693, value=shangdi
 100002                     column=info:age, timestamp=1405417426693, value=28
 100002                     column=info:name, timestamp=1405417426693, value=shichao
 100003                     column=info:address, timestamp=1405494141522, value=huilongguan
 100003                     column=info:age, timestamp=1405494999631, value=29
 100003                     column=info:name, timestamp=1405494141522, value=liyang
3 row(s) in 0.0190 seconds

执行以下代码:
        Configuration conf = HBaseConfiguration.create();
        HTable table = new HTable(conf, "rd_ns:itable");
        Scan scan = new Scan();
        scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,
                new BinaryComparator(Bytes.toBytes("28")))));
        ResultScanner rs = table.getScanner(scan);
        for (Result r : rs) {
            for (Cell cell : r.rawCells()) {
                System.out.println("Rowkey : " + Bytes.toString(r.getRow())
                        + "   Familiy:Quilifier : "
                        + Bytes.toString(CellUtil.cloneQualifier(cell))
                        + "   Value : "
                        + Bytes.toString(CellUtil.cloneValue(cell))
                        + "   Time : " + cell.getTimestamp());
            }
        }
        table.close();  
输出结果(整个100002行被过滤掉了):
Rowkey : 100001   Familiy:Quilifier : address   Value : anywhere   Time : 1405417403438
Rowkey : 100001   Familiy:Quilifier : age   Value : 24   Time : 1405417403438
Rowkey : 100001   Familiy:Quilifier : name   Value : zhangtao   Time : 1405417403438
Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522
Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405494999631
Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522  

7. Utility--FirstKeyOnlyFilter

该过滤器仅仅返回每一行中的第一个cell的值,可以用于高效的执行行数统计操作。
估计实战意义不大。

构造函数:
public FirstKeyOnlyFilter()

个人实测代码:
        HTable table = HBaseDAO.getHTable("147patents");
        FirstKeyOnlyFilter fkof = new FirstKeyOnlyFilter();
        Scan scan = new Scan();
        scan.setFilter(fkof);
        ResultScanner rs = table.getScanner(scan);  

8. 取得查询结果

无论是官网的Ref Guide还是网上流传的大部分博客中,输出查询结果的代码都是:
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}

但查看最新的API可知Result实例的raw()方法已经不建议使用了:
raw() Deprecated. as of 0.96, use rawCells()

0.96以后版本正确的获取结果代码如下:
        for (Result r : rs) {
            for (Cell cell : r.rawCells()) {
                System.out.println(
                        "Rowkey : "+Bytes.toString(r.getRow())+
                        "Familiy:Quilifier : "+Bytes.toString(CellUtil.cloneQualifier(cell))+
                        "Value : "+Bytes.toString(CellUtil.cloneValue(cell))
                        );
            }
        }  

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值