package cn.itcast.bigdata.hbase;

import java.io.IOException;

import java.io.InterruptedIOException;

import java.util.ArrayList;

import java.util.Iterator;

import org.apache.commons.collections.comparators.NullComparator;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.HColumnDescriptor;

import org.apache.hadoop.hbase.HTableDescriptor;

import org.apache.hadoop.hbase.MasterNotRunningException;

import org.apache.hadoop.hbase.NamespaceDescriptor;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.ZooKeeperConnectionException;

import org.apache.hadoop.hbase.client.Delete;

import org.apache.hadoop.hbase.client.Get;

import org.apache.hadoop.hbase.client.HBaseAdmin;

import org.apache.hadoop.hbase.client.HTable;

import org.apache.hadoop.hbase.client.Put;

import org.apache.hadoop.hbase.client.Result;

import org.apache.hadoop.hbase.client.ResultScanner;

import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;

import org.apache.hadoop.hbase.client.Scan;

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

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

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

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

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

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

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

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

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

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

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

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

import org.apache.hadoop.hbase.util.Bytes;

import org.apache.hadoop.io.BinaryComparable;

import org.junit.Before;

import org.junit.Test;

/**

* Hbase客户端操作示例

*

* @author songjq

*

*/

/**

* Hbase客户端操作示例

*

* @author songjq

*

*/

public class HbaseAPIDemo {

// 数据库连接对象

private HBaseAdmin hBaseAdmin = null;

// 表连接对象

private HTable hTable = null;

/**

* 获取Hbase对象连接

*

* @throws MasterNotRunningException

* @throws ZooKeeperConnectionException

* @throws IOException

*/

@Before

public void getHbaseConn() throws MasterNotRunningException, ZooKeeperConnectionException, IOException {

/**

* 通过这种通用的配置对象构造的方法来创建一个配置对象 这种方法会自动加载classpath下的

* core-site.xml,hdfs-site.xml,core-default.xml...等这些hadoop的配置文件

*/

// Configuration hdfsconf = new Configuration();

/**

* HBaseConfiguration.create()则会自动加载classpath下的hadoop下的配置文件 及hbase-site.xml

*/

Configuration conf = HBaseConfiguration.create();

/**

* 这里通过zk集群地址连接hbase集群,只需要把hbase-site.xml中zk连接地址拷贝过来即可

* /usr/local/apps/hbase-0.96.2-hadoop2/conf/hbase-site.xml

*/

conf.set("hbase.zookeeper.quorum", "hadoop-server01:2181,hadoop-server02:2181,hadoop-server03:2181");

// 构造一个DDL操作的客户端对象hBaseAdmin

hBaseAdmin = new HBaseAdmin(conf);

// 实例化表连接对象

hTable = new HTable(conf, "oadb:t_user_info");

}

/**

* 查询方式多样,可以根据行键起止范围查询

*

* @throws IOException

*/

@Test

public void scanTest() throws IOException {

/*

* 封装scan查询对象,指定查询起止参数 不封装列族和列字段,默认就查询起止位置所有列族数据 细节:

* 1、scan封装的对象中,如果扫描到的行在读取列字段时,该字段不存在,那么程序执行到该行后将直接退出,不再继续读取后面的行

* 2、scan封装的数据含头不含尾

*/

Scan scan = new Scan(Bytes.toBytes("user000007"), Bytes.toBytes("user000009"));

/**

* //指定查询的列族,不指定就查询该列族中字段 scan.addFamily(Bytes.toBytes("base_info"));

* //指定查询列族中的字段 scan.addColumn(Bytes.toBytes("base_info"),

* Bytes.toBytes("userid"));

*/

/*

* 执行查询

*/

ResultScanner scanner = hTable.getScanner(scan);

/*

* 获取查询结果的迭代器

*/

Iterator<Result> iterator = scanner.iterator();

/*

* 迭代结果输出

*/

System.out.println("userid\t\tusername\tage\torgid\torgname");

while (iterator.hasNext()) {

/*

* 打印每个行键rowkey结果

*/

Result result = iterator.next();

byte[] userid = result.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("userid"));

byte[] username = result.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("username"));

byte[] age = result.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("age"));

byte[] orgid = result.getValue(Bytes.toBytes("extra_info"), Bytes.toBytes("orgid"));

byte[] orgname = result.getValue(Bytes.toBytes("extra_info"), Bytes.toBytes("orgname"));

System.out.println(Bytes.toString(userid) + "\t" + Bytes.toString(username) + "\t" + Bytes.toString(age)

+ "\t" + Bytes.toString(orgid) + "\t" + Bytes.toString(orgname));

}

hTable.close();

}

/**

* scan高级查询【过滤器】 这里只举例部分过滤器的使用,其它过滤器使用方法类似

* @throws IOException

*/

@Test

public void testFilter() throws IOException {

/***************************

* 行键前缀过滤器PrefixFilter** 根据行键rowkey前缀值查询*****

**************************/

/*

* 默认查询所有行

*/

Scan scan = new Scan();

/*

* 构造一个前缀过滤器,针对行键rowkey前缀进行过滤 这里过滤前缀为user000001开头的行

*/

Filter rowkeyFilter = new PrefixFilter(Bytes.toBytes("user000001"));

/*

* 向scan添加过滤器

*/

scan.setFilter(rowkeyFilter);

/*

* 执行查询

*/

ResultScanner scanner = hTable.getScanner(scan);

/*

* 获取查询迭代器

*/

Iterator<Result> iterator = scanner.iterator();

/*

* 遍历迭代器,输入结果

*/

System.out.println("---------------前缀过滤器---------------");

while (iterator.hasNext()) {

Result res = iterator.next();

System.out.println("rowkey->" + Bytes.toString(res.getRow()) + " userid->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("userid"))) + " username->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("username"))));

/**

* 输出结果:符合过滤条件要求

* rowkey->user0000011 userid->Usercode0000011 username->张三11

* rowkey->user0000011 userid->Usercode0000011 username->张三11

*/

}

/***************************

* 比较过滤器 等值比较过滤器

**************************/

/*

* 重新实例化scan对象

*/

scan = new Scan();

/*

* RowFilter是CompareFilter抽象类的实现类 CompareFilter是继承自FilterBase抽象类

* FilterBase又继承自Filter抽象类 这里使用RowFilter构造一个过滤器对象

* rowCompareOp是查询条件,CompareOp.EQUAL表示进行等值查询

* rowComparator是条件值,是一个ByteArrayComparable类型的对象

* ByteArrayComparable是个抽象类,有BinaryComparable,BinaryPrefixComparator,

* NullComparator, RegexStringComparator,SubstringComparator等实现类

*/

/*

* 构造一Comparator比较器,这里使用BinaryComparator类来实现等值查询

*/

ByteArrayComparable rowComparator = new BinaryComparator(Bytes.toBytes("user0000011"));

/*

* 构造一个行过滤器,返回行键为user0000011的行

*/

RowFilter rowFilter = new RowFilter(CompareOp.EQUAL, rowComparator);

/*

* 想scan参数添加过滤器

*/

scan.setFilter(rowFilter);

/*

* 执行查询

*/

ResultScanner scanner2 = hTable.getScanner(scan);

/*

* 获取查询结果的迭代

*/

Iterator<Result> iterator2 = scanner2.iterator();

/*

* 遍历迭代器,输入结果

*/

System.out.println("---------------等值比较过滤器---------------");

while (iterator2.hasNext()) {

Result res = iterator2.next();

System.out.println("rowkey->" + Bytes.toString(res.getRow()) + " userid->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("userid"))) + " username->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("username"))));

/**

* 输出结果:符合过滤条件要求

*  rowkey->user0000011 userid->Usercode0000011 username->张三11

*/

}

/***************************

* 比较过滤器 根据列族中字段进行比较查询,类型关系型数据库中模糊匹配查询

**************************/

scan = new Scan();

/*

* 构造一个SubstringComparator比较器,类似like模糊查询,这里是将base_info:userid列中匹配0001等行查询并返回

*/

SubstringComparator substringComparator = new SubstringComparator("0001");

/*

* new SingleColumnValueFilter(family, qualifier, compareOp, comparator);

* family->列族, qualifier->列族中字段, compareOp->比较条件, comparator->比较器

* 这里讲base_info:userid中匹配0001的行查询出来并返回

*/

SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("base_info"),

Bytes.toBytes("userid"), CompareOp.EQUAL, substringComparator);

//需要显示指定一个参数,才能过滤掉那些不包含的列的行,这里可以不加这个参数做一个测试,前提构造的hbase中数据具备这个条件

singleColumnValueFilter.setFilterIfMissing(true);

/*

* 向scan添加singleColumnValueFilter过滤器

*/

scan.setFilter(singleColumnValueFilter);

/*

* 执行查询

*/

ResultScanner scanner3 = hTable.getScanner(scan);

Iterator<Result> iterator3 = scanner3.iterator();

/*

* 遍历迭代器,输入结果

*/

System.out.println("---------------特定列族列过滤器---------------");

while (iterator3.hasNext()) {

Result res = iterator3.next();

System.out.println("rowkey->" + Bytes.toString(res.getRow()) + " userid->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("userid"))) + " username->"

+ Bytes.toString(res.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("username"))));

/**

* 输出结果:

*  rowkey->user0000010 userid->Usercode0000010 username->张三10

rowkey->user0000011 userid->Usercode0000011 username->张三11

rowkey->user000002 userid->null username->null

rowkey->user000003 userid->null username->null

从输出结果看出不符合我们的要求,多了  rowkey->user000002 userid->null username->null

  rowkey->user000003 userid->null username->null

原因是这两行并没有base_info列族及对应的列

该过滤器的原理是如果过滤器中不包含指定的列,则会默认返回不包含列过滤器指定列的行数据, 因此需要加

singleColumnValueFilter.setFilterIfMissing(true);

再次查询结果:

rowkey->user0000010 userid->Usercode0000010 username->张三10

rowkey->user0000011 userid->Usercode0000011 username->张三11

*/

}

/*

* 关闭连接

*/

hTable.close();

}

}