Hadoop————Hbase强化

1、Hbase的特点

可用作hadoop数据库,提供分布式可伸缩大型数据存储。用户能随机、实时读写数据。存储十亿行 x 百万列数量级数据。是版本化、非关系型数据库。面向列存储,table是按row排序。

Feature
----------------
    Linear and modular scalability.                 //线性模块化扩展方式。
    Strictly consistent reads and writes.           //严格一致性读写
    Automatic and configurable sharding of tables   //自动可配置表切割
    Automatic failover support between RegionServers.   //区域服务器之间自动容灾(只需要在用作hbase节点的服务器上开启两个HMaster进程就可实现自动容灾,zk节点下会有:/hbase/backup-master)
    Convenient base classes for backing Hadoop MapReduce jobs with Apache HBase tables.     //
    Easy to use Java API for client access.         //java API
    Block cache and Bloom Filters for real-time queries //块缓存和布隆过滤器用于实时查询 
    Query predicate push down via server side Filters   //通过服务器端过滤器实现查询预测
    Thrift gateway and a REST-ful Web service that supports XML, Protobuf, and binary data encoding options //
    Extensible jruby-based (JIRB) shell                 //
    Support for exporting metrics via the Hadoop metrics subsystem to files or Ganglia; or via JMX          //可视化
    面向列数据库。

2、搭建Hbase集群

0.选择安装的主机

s201 ~ s204

1.jdk

2.hadoop

3.用tar命令解压Hbase压缩包

4.配置环境变量

5.验证安装是否成功

$>hbase version

6.配置hbase模式

6.1)本地模式

[hbase/conf/hbase-env.sh]
EXPORT JAVA_HOME=/soft/jdk

[hbase/conf/hbase-site.xml]
    ...
<property>
        <name>hbase.rootdir</name>
        <value>file:/home/hadoop/HBase/HFiles</value>
</property>

5.2)伪分布式

[hbase/conf/hbase-env.sh]
EXPORT JAVA_HOME=/soft/jdk

[hbase/conf/hbase-site.xml]
    <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
    </property
    <property>
                <name>hbase.rootdir</name>
                <value>hdfs://localhost:8030/hbase</value>
    </property>

5.3)完全分布式

    [hbase/conf/hbase-env.sh]
            export JAVA_HOME=/soft/jdk
            export HBASE_MANAGES_ZK=false

            [hbse-site.xml]
            <!-- 使用完全分布式 -->
            <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
            </property>

            <!-- 指定hbase数据在hdfs上的存放路径 -->
            <property>
                <name>hbase.rootdir</name>
                <value>hdfs://s201:8020/hbase</value>
            </property>
            <!-- 配置zk地址 -->
            <property>
                <name>hbase.zookeeper.quorum</name>
                <value>s201:2181,s202:2181,s203:2181</value>
            </property>
            <!-- zk的本地目录 -->
            <property>
                <name>hbase.zookeeper.property.dataDir</name>
                <value>/home/centos/zookeeper</value>
            </property>

7.配置regionservers

[hbase/conf/regionservers]
        s202
        s203
        s204

8.启动hbase集群(s201)

$>start-hbase.sh

9.登录hbase的webui

http://s201:16010

3、Hbase的命令操作

hbase shell操作
------------------
    $>hbase shell                          //登录shell终端.
    $hbase>help                                //帮助菜单
    $hbase>help    'list_namespace'            //查看特定的命令帮助
    $hbase>list_namespace                  //列出名字空间(名字空间相当于数据库)
    $hbase>list_namespace_tables 'defalut' //列出名字空间(数据库)
    $hbase>create_namespace 'ns1'          //创建名字空间
    $hbase>help 'create'
    $hbase>create 'ns1:t1','f1'                //创建表,指定空间下
    $hbase>put 'ns1:t1','row1','f1:id',100     //插入数据(名字空间:表名,行名,列族名:列名,值)
    $hbase>put 'ns1:t1','row1','f1:name','tom' //

    $hbase>get 'ns1:t1','row1'                 //查询指定row
    $hbase>scan 'ns1:t1'                       //扫描表
    $hbase>flush 'ns1:t1'      //清理内存数据到磁盘。
    $hbase>count 'ns1:t1'      //统计函数
    $hbase>disable 'ns1:t1'        //删除表之前需要禁用表
    $hbase>drop 'ns1:t1'       //删除表

    $hbase>scan 'hbase:meta'   //查看元数据表,所有的表信息都在这里存储
    $hbase>split 'ns1:t1'      //切割表,默认是10G切割 
    $hbase>split ''                //切割区域
    $hbase>merge_region '第一个区域的md5值' '第二个区域的md5值'   //合并区域
    $hbase>move '(64d1269c1776c4207e4346a495cbfcda)需要移动区域的md5值' 's2,16020,1529736825974(主机名,端口号,时间戳)'    //移动区域到s2主机上

    有关区域的md5值以及主机信息都可以在metadata上看到

4、通过编程API访问Hbase

1.创建hbase模块

2.添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.ctgu</groupId>
    <artifactId>HbaseDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>---------开始复制jar包到共享目录下----------</echo>
                                <delete file="J:\Program\java\hadoop\jar\HdfsDemo-1.0-SNAPSHOT.jar"></delete>
                                <copy file="target/HdfsDemo-1.0-SNAPSHOT.jar" toFile="J:\Program\java\hadoop\jar\HdfsDemo.jar">
                                </copy>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

复制hbase集群的hbase-site.xml文件到模块的src/main/resources目录下。

3.编程实现

cn.ctgu.hbasedemo.test;
import org.apache.hadoop.conf.Configuration;
        import org.apache.hadoop.hbase.HBaseConfiguration;
        import org.apache.hadoop.hbase.TableName;
        import org.apache.hadoop.hbase.client.*;
        import org.apache.hadoop.hbase.util.Bytes;
        import org.junit.Test;

        import java.io.IOException;

        /**
         *
         */
        public class TestCRUD {
            @Test
            public void put() throws Exception {
                //创建conf对象
                Configuration conf = HBaseConfiguration.create();
                //通过连接工厂创建连接对象
                Connection conn = ConnectionFactory.createConnection(conf);
                //通过连接查询tableName对象
                TableName tname = TableName.valueOf("ns1:t1");
                //获得table
                Table table = conn.getTable(tname);

                //通过bytes工具类创建字节数组(将字符串)
                byte[] rowid = Bytes.toBytes("row3");

                //创建put对象
                Put put = new Put(rowid);

                byte[] f1 = Bytes.toBytes("f1");
                byte[] id = Bytes.toBytes("id") ;
                byte[] value = Bytes.toBytes(102);
                put.addColumn(f1,id,value);

                //执行插入
                table.put(put);
            }
//查询
            @Test
            public void get() throws Exception {
                //创建conf对象
                Configuration conf = HBaseConfiguration.create();
                //通过连接工厂创建连接对象
                Connection conn = ConnectionFactory.createConnection(conf);
                //通过连接查询tableName对象
                TableName tname = TableName.valueOf("ns1:t1");
                //获得table
                Table table = conn.getTable(tname);

                //通过bytes工具类创建字节数组(将字符串)
                byte[] rowid = Bytes.toBytes("row3");
                Get get = new Get(Bytes.toBytes("row3"));
                Result r = table.get(get);
                byte[] idvalue = r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
                System.out.println(Bytes.toInt(idvalue));
            }
        }

百万数据批量插入

//百万数据写入的优化:关闭写前日志、关闭自动清理缓冲区
    @Test
    public void bigdataput() throws Exception {
        DecimalFormat format=new DecimalFormat();
        format.applyPattern("0000000");


        long start = System.currentTimeMillis();
        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t1");
        HTable table = (HTable) conn.getTable(tname);
        //不要自动清理缓冲区
        table.setAutoFlush(false);

        for (int i = 4; i < 1000000; i++) {
            Put put = new Put(Bytes.toBytes("row" + format.format(i)));
            //关闭写前日志
            put.setWriteToWAL(false);
            put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("id"), Bytes.toBytes(i));
            put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("tom" + i));
            put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("age"), Bytes.toBytes(i % 100));
            table.put(put);

            //没写入2000条数据手动清理缓冲区
            if (i % 2000 == 0) {
                table.flushCommits();
            }
        }
        //
        table.flushCommits();
        System.out.println(System.currentTimeMillis() - start);
    }
    //rowkey格式化,避免出现row=8出现在row=10008的后面,因为在hbase中是按字节数组存储的,比较rowkey的时候是按位进行比较的,所以会
    //出现上面那种情况,将前面填充0
    @Test
    public void formatNum(){
        DecimalFormat format=new DecimalFormat();
        format.applyPattern("0000000");
        System.out.println(format.format(8));//结果为:0000008
    }

创建表时指定列族的版本数,该列族的所有列都具有相同数量版本
shell命令操作

$hbase>create 'ns1:t3',{NAME=>'f1',VERSIONS=>3}            //创建表时,指定列族的版本数。
    $hbase>get 'ns1:t3','row1',{COLUMN=>'f1',VERSIONS=>4}  //检索的时候,查询多少版本。

API实现

@Test
    public void getWithVersions() throws IOException {
        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t3");
        Table table = conn.getTable(tname);
        Get get = new Get(Bytes.toBytes("row1"));
        //检索所有版本
        get.setMaxVersions();
        Result r = table.get(get);
        List<Cell> cells = r.getColumnCells(Bytes.toBytes("f1"), Bytes.toBytes("name"));
        for(Cell c : cells){
            String f = Bytes.toString(c.getFamily());//获取列族
            String col = Bytes.toString(c.getQualifier());//获取列名
            long ts = c.getTimestamp();//获取时间戳
            String val = Bytes.toString(c.getValue());//获取值
            System.out.println(f + "/" + col + "/" + ts + "=" + val);
        }
    }

原生扫描
1.原生扫描

$hbase>scan 'ns1:t3',{COLUMN=>'f1',RAW=>true,VERSIONS=>10}     //包含标记了delete的数据

2.删除数据
        $hbase>delete 'nd1:t3','row1','f1:name',148989875645           //删除数据,标记为删除.小于该删除时间的数据都作废。

3.TTL
    time to live ,存活时间。
    影响所有的数据,包括没有删除的数据。
    超过该时间,原生扫描也扫不到数据。
    $hbase>create 'ns1:tx' , {NAME=>'f1',TTL=>10,VERSIONS}

4.KEEP_DELETED_CELLS
    删除key之后,数据是否还保留。
    $hbase>create 'ns1:tx' , {NAME=>'f1',TTL=>10,VERSIONS,KEEP_DELETED_CELLS=>true}

这里写图片描述
API操作

//创建名字空间(即数据库)
    @Test
    public void createNameSpace() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection();
        Admin admin=conn.getAdmin();
        //创建名字空间描述符
        NamespaceDescriptor nsd=NamespaceDescriptor.create("ns2").build();
        admin.createNamespace(nsd);
    }
    @Test
    public void listNameSpace() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection();
        Admin admin=conn.getAdmin();
        //获取名字空间描述符
        NamespaceDescriptor[]ns=admin.listNamespaceDescriptors();
        for(NamespaceDescriptor n:ns){
            System.out.println(n.getName());
        }
    }
    //创建表
    @Test
    public void createTable() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        //获取管理员对象
        Admin admin=conn.getAdmin();
        //创建表名对象
        TableName tableName=TableName.valueOf("ns2:t2");
        //创建表描述符对象
        HTableDescriptor tb1=new HTableDescriptor(tableName);
        //创建列族描述符
        HColumnDescriptor col=new HColumnDescriptor("f1");
        tb1.addFamily(col);

        admin.createTable(tb1);
        System.out.println("over");
    }
    //禁用表和删除表,表只有先禁用才能删除
    @Test
    public void disableTable() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        Admin admin=conn.getAdmin();
        //禁用表
        admin.disableTable(TableName.valueOf("ns2:t2"));
        //启用表
        //admin.enableTable(TableName.valueOf("ns2:t2"));
        //删除表
        admin.deleteTable(TableName.valueOf("ns2:t2"));
    }

    //删除数据
    @Test
    public void deleteData() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tname=TableName.valueOf("ns1:t1");

        Table table=conn.getTable(tname);
        Delete del=new Delete(Bytes.toBytes("row0001"));
        del.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("id"));
        del.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("name"));

        table.delete(del);
        System.out.println("over");
    }
    //扫描数据,避免扫描全部数据,因为数据量很大,耗时长,设置起始结束row或者表
    @Test
    public void scan() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tnam=TableName.valueOf("ns1:t1");
        Table table=conn.getTable(tnam);
        Scan scan=new Scan();
        scan.setStartRow(Bytes.toBytes("row5000"));//设置起始行
        scan.setStopRow(Bytes.toBytes("row8000"));//设置结束行

        ResultScanner rs=table.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();//r是行
            byte[]name=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("name"));
            System.out.println(Bytes.toString(name));
        }
    }
    //动态遍历
    @Test
    public void scan2() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tnam=TableName.valueOf("ns1:t1");
        Table table=conn.getTable(tnam);
        Scan scan=new Scan();
        scan.setStartRow(Bytes.toBytes("row5000"));//设置起始行
        scan.setStopRow(Bytes.toBytes("row8000"));//设置结束行

        ResultScanner rs=table.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();//r是行
            Map<byte[],byte[]>map=r.getFamilyMap(Bytes.toBytes("f1"));//获取每一列族
            for(Map.Entry<byte[],byte[]>entrySet:map.entrySet()){
                String col=Bytes.toString(entrySet.getKey());
                String val=Bytes.toString(entrySet.getValue());
                System.out.println(col+":"+val+",");
            }
          System.out.println();
        }
    }

    @Test
    public void scan3() throws Exception {
        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t1");
        Table table = conn.getTable(tname);
        Scan scan = new Scan();
        scan.setStartRow(Bytes.toBytes("row5000"));
        scan.setStopRow(Bytes.toBytes("row8000"));
        ResultScanner rs = table.getScanner(scan);
        Iterator<Result> it = rs.iterator();
        while (it.hasNext()) {
            Result r = it.next();
            //得到一行的所有map,key=f1,value=Map<Col,Map<Timestamp,value>>
            NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = r.getMap();
            //
            for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> entry : map.entrySet()){
                //得到列族
                String f = Bytes.toString(entry.getKey());
                Map<byte[], NavigableMap<Long, byte[]>> colDataMap = entry.getValue();//列数据
                for(Map.Entry<byte[], NavigableMap<Long, byte[]>> ets : colDataMap.entrySet() ){
                    String c = Bytes.toString(ets.getKey());//列

                    Map<Long, byte[]> tsValueMap = ets.getValue();
                    for(Map.Entry<Long,byte[]> e : tsValueMap.entrySet()){
                        Long ts = e.getKey() ;//时间戳
                        String value = Bytes.toString(e.getValue());//值
                        System.out.print(f+":"+c+":"+ts+"=" +value + ",");
                    }
                }
            }
            System.out.println();
        }
    }

缓存和批处理

开启服务器端扫描器缓存
a)表层面(全局)

<property>
            <name>hbase.client.scanner.caching</name>
            <!-- 缓存整数最大值 -->
            <value>2147483647</value>
            <source>hbase-default.xml</source>
</property>

b)操作层面

//设置量,即扫描一次获取到多少数据
scan.setCaching(10);

扫描器缓存
面向行级别的,每次推送多少行,而不是单独提取一行,降低交互的次数,提高效率。

API操作

 //扫描器缓存
    @Test
    public void getScanCache() throws IOException {

        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t1");
        Scan scan = new Scan();
        scan.setCaching(5000);//设置缓存大小
        Table t = conn.getTable(tname);
        ResultScanner rs = t.getScanner(scan);
        long start = System.currentTimeMillis() ;
        Iterator<Result> it = rs.iterator();
        while(it.hasNext()){
            Result r = it.next();//一次获取5000行数据
            System.out.println(r.getColumnLatestCell(Bytes.toBytes("f1"), Bytes.toBytes("name")));
        }
        System.out.println(System.currentTimeMillis() - start);
    }

批量扫描是面向列级别
控制每次next()服务器端返回的列的个数。
scan.setBatch(5); //每次next返回5列。
这里写图片描述

 /**
     * 测试缓存和批处理
     */
    @Test
    public void testBatchAndCaching() throws IOException {

        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t7");
        Scan scan = new Scan();
        scan.setCaching(2);//设置缓存为2行
        scan.setBatch(4);//设置批为4,即列为4

        Table t = conn.getTable(tname);
        ResultScanner rs = t.getScanner(scan);
        Iterator<Result> it = rs.iterator();
        while (it.hasNext()) {
            Result r = it.next();
            System.out.println("========================================");
            //得到一行的所有map,key=f1,value=Map<Col,Map<Timestamp,value>>
            NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = r.getMap();
            //
            for (Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> entry : map.entrySet()) {
                //得到列族
                String f = Bytes.toString(entry.getKey());
                Map<byte[], NavigableMap<Long, byte[]>> colDataMap = entry.getValue();
                for (Map.Entry<byte[], NavigableMap<Long, byte[]>> ets : colDataMap.entrySet()) {
                    String c = Bytes.toString(ets.getKey());
                    Map<Long, byte[]> tsValueMap = ets.getValue();
                    for (Map.Entry<Long, byte[]> e : tsValueMap.entrySet()) {
                        Long ts = e.getKey();
                        String value = Bytes.toString(e.getValue());
                        System.out.print(f + "/" + c + "/" + ts + "=" + value + ",");
                    }
                }
            }
            System.out.println();
        }
    }

这里写图片描述

过滤器

//测试行过滤器
    @Test
    public void testFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //过滤出行小于等于100的行
        RowFilter rowFilter=new RowFilter(CompareFilter.CompareOp.LESS_OR_EQUAL,new BinaryComparator(Bytes.toBytes("row0100")));
        scan.setFilter(rowFilter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            System.out.println(Bytes.toString(r.getRow()));
        }
    }
    //测试行过滤器
    @Test
    public void testFamilyFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //过滤出列族小于等于f2的列族
        FamilyFilter filter=new FamilyFilter(CompareFilter.CompareOp.LESS_OR_EQUAL,new BinaryComparator(Bytes.toBytes("f2")));
        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            System.out.println(f1id+":"+f2id);
        }
    }
    //测试列过滤器
    @Test
    public void testColFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //过滤出列为id的列
        QualifierFilter filter=new QualifierFilter(CompareFilter.CompareOp.EQUAL,new BinaryComparator(Bytes.toBytes("id")));
        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }
    /*
    *
    * 测试ValueFilter(值过滤器)
    * 过滤value的值,含有指定的子字符串
    *
    *
    * */
    @Test
    public void testValueFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //过滤出含有"1.1"字串的值
        ValueFilter filter=new ValueFilter(CompareFilter.CompareOp.EQUAL,new SubstringComparator("1.1"));
        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }
    //测试依赖列过滤器
    @Test
    public void testDepFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //该过滤器尝试找到该f2列族所在的addr列,并返回该addr不等于beijing的全部键值对。
        DependentColumnFilter filter=new DependentColumnFilter(Bytes.toBytes("f2"),
                Bytes.toBytes("addr"),
                true,//为true删除,false不删除
                CompareFilter.CompareOp.NOT_EQUAL,
                new BinaryComparator(Bytes.toBytes("beijing"))
               );
        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
    *
    * 单列值value过滤
    * 如果value不满足,整行过滤掉
    *
    * */
    @Test
    public void testSingleFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //该过滤器尝试找到该f2列族所在列name不为tom2.2的行,如果为tom2.2则整行过滤掉
        SingleColumnValueFilter filter=new SingleColumnValueFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.NOT_EQUAL,
                new BinaryComparator(Bytes.toBytes("tom2.2"))
        );

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
    *
    * 单列值排除过滤器
    * 去掉过滤器使用的列,对列值进行过滤
    *
    * */
    @Test
    public void testSingleColumnValueFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //该过滤器过滤掉(即删除)当列name为tom2.2的整列
        SingleColumnValueExcludeFilter filter=new SingleColumnValueExcludeFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                new BinaryComparator(Bytes.toBytes("tom2.2"))
        );

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
    *
    *前缀过滤,是rowkey过滤
    * */
    @Test
    public void testPrefixFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //该过滤器过滤出rowkey包含row22的所有列
        PrefixFilter filter=new PrefixFilter(Bytes.toBytes("row22"));

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
    *
    *分页过滤器,在region上扫描时,对每次page设置的大小
    * 返回给客户端涉及到每个结果的合并
    * 假如该表分为3个区,每个分页设置为10,则返回30行数据
    * */
    @Test
    public void testPageFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //该过滤器使得表的每个区返回10行
        PageFilter filter=new PageFilter(10);

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
   *
   *KeyOnly过滤器,只提取key,丢弃value
   * */
    @Test
    public void testKeyOnlyFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //丢弃value,只要key,如果参数为空,则打印出value为null
        KeyOnlyFilter filter=new KeyOnlyFilter();

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }

    /*
  *
  *列分页过滤器,过滤指定范围列
  * */
    @Test
    public void testColumnPageFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Scan scan=new Scan();
        //过滤掉前两列,然后取后两列
        ColumnPaginationFilter filter=new ColumnPaginationFilter(2,2);

        scan.setFilter(filter);

        Table t=conn.getTable(tableName);
        ResultScanner rs=t.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            Result r=it.next();
            byte[]f1id=r.getValue(Bytes.toBytes("f1"),Bytes.toBytes("id"));
            byte[]f2id=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("id"));
            byte[]f2name=r.getValue(Bytes.toBytes("f2"),Bytes.toBytes("name"));
            System.out.println(f1id+":"+f2id+":"+f2name);
        }
    }
    //组合过滤器
  /* 相当于下面的sql语句
  select * from t7 where ((age <= 13) and (name like '%t')

                         or

            (age > 13) and (name like 't%'))*/
    @Test
    public void testComboFilter() throws IOException {

        Configuration conf = HBaseConfiguration.create();
        Connection conn = ConnectionFactory.createConnection(conf);
        TableName tname = TableName.valueOf("ns1:t7");
        Scan scan = new Scan();

        //where ... f2:age <= 13
        SingleColumnValueFilter ftl = new SingleColumnValueFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("age"),
                CompareFilter.CompareOp.LESS_OR_EQUAL,
                new BinaryComparator(Bytes.toBytes("13"))
        );

        //where ... f2:name like %t
        SingleColumnValueFilter ftr = new SingleColumnValueFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                new RegexStringComparator("^t")//匹配正则表达式
        );
        //ft
        FilterList ft = new FilterList(FilterList.Operator.MUST_PASS_ALL);
        ft.addFilter(ftl);
        ft.addFilter(ftr);

        //where ... f2:age > 13
        SingleColumnValueFilter fbl = new SingleColumnValueFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("age"),
                CompareFilter.CompareOp.GREATER,
                new BinaryComparator(Bytes.toBytes("13"))
        );

        //where ... f2:name like %t
        SingleColumnValueFilter fbr = new SingleColumnValueFilter(
                Bytes.toBytes("f2"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                new RegexStringComparator("t$")
        );
        //ft
        FilterList fb = new FilterList(FilterList.Operator.MUST_PASS_ALL);
        fb.addFilter(fbl);
        fb.addFilter(fbr);


        FilterList fall = new FilterList(FilterList.Operator.MUST_PASS_ONE);
        fall.addFilter(ft);
        fall.addFilter(fb);

        scan.setFilter(fall);
        Table t = conn.getTable(tname);
        ResultScanner rs = t.getScanner(scan);
        Iterator<Result> it = rs.iterator();
        while (it.hasNext()) {
            Result r = it.next();
            byte[] f1id = r.getValue(Bytes.toBytes("f1"), Bytes.toBytes("id"));
            byte[] f2id = r.getValue(Bytes.toBytes("f2"), Bytes.toBytes("id"));
            byte[] f1name = r.getValue(Bytes.toBytes("f1"), Bytes.toBytes("name"));
            byte[] f2name = r.getValue(Bytes.toBytes("f2"), Bytes.toBytes("name"));
            System.out.println(f1id + " : " + f2id + " : " + Bytes.toString(f1name) + " : " + Bytes.toString(f2name));
        }
    }

计数器

$hbase>incr 'ns1:t8','row1','f1:click',1//incr 设置计数器,每次加1
$hbase>get_counter 'ns1:t8','row1','f1:click'

API编程实现

 /*
 *
 *测试计数器
 * */
    @Test
    public void testIncr() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tableName=TableName.valueOf("ns1:t5");
        Table t=conn.getTable(tableName);
        Increment incr=new Increment(Bytes.toBytes("row1"));
        incr.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("daily"),1);
        incr.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("weekly"),10);
        incr.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("monthly"),100);
        t.increment(incr);

    }

5、Hbase架构原理

5.1 Hbase写入过程

hbase是基于hdfs的,相同列族的数据存放在一个文件中。分为表数据存储目录和WAL目录,WAL(write ahead log,写前日志),写入数据的时候会先进行写前日志的记录,以便宕机的时候能恢复相关数据。

[表数据的存储目录结构构成]
hdfs://s201:8020/hbase/data/${名字空间}/${表名}/${区域名称}/${列族名称}/${文件名}

[WAL目录结构构成]
hdfs://s201:8020/hbase/WALs/${区域服务器名称,主机名,端口号,时间戳}/

这里写图片描述

5.2 client端交互过程

0.hbase集群启动时,master负责分配区域到指定区域服务器。

1.联系zk,找出meta表所在rs(regionserver)

/hbase/meta-region-server

2.定位row key,找到对应region server(Hbase的查询过程是三级定位,所以速度会很快,能实现实时)
这里写图片描述

3.将超过MemStore的数据通过HFile缓存在本地磁盘。

4.联系RegionServer

5.HRegionServer负责open HRegion对象,为每个列族创建Store对象,Store包含多个StoreFile实例,他们是对HFile的轻量级封装。每个Store还对应了一个MemStore,用于内存存储数据。

HMaster在功能上主要负责Table表和HRegion的管理工作,具体包括:

1、管理用户对Table表的增、删、改、查操作;

2、管理HRegion服务器的负载均衡,调整HRegion分布;

3、在HRegion分裂后,负责新HRegion的分配;

4、在HRegion服务器停机后,负责失效HRegion服务器上的HRegion迁移。

hbase会切割文件,默认大小是10G进行切割。

<property>
        <name>hbase.hregion.max.filesize</name>
        <value>10737418240</value>
        <source>hbase-default.xml</source>
</property>

这里写图片描述
6、hbase和hadoop的ha集成

1.在hbase-env.sh文件添加hadoop配置文件目录到HBASE_CLASSPATH环境变量并分发到其他几台Hbase节点上.

[/soft/hbase/conf/hbase-env.sh]
export HBASE_CLASSPATH=$HBASE_CLASSPATH:/soft/hadoop/etc/hadoop

2.在hbase/conf/目录下创建到hadoop的hdfs-site.xml符号连接。

$>ln -s /soft/hadoop/etc/hadoop/hdfs-site.xml /soft/hbase/conf/hdfs-site.xml

3.修改hbase-site.xml文件中hbase.rootdir的目录值。

[/soft/hbase/conf/hbase-site.xml]
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://mycluster/hbase</value>
        </property>

4.将以上步骤的配置文件分发处理。

7、拆分风暴

7.1 什么叫拆分风暴
当一个region里的存储文件增长到大于配置的hbase.hregion.max.filesize大小(默认为10G)或者在列族
层面配置的大小时,region会被一分为二,region服务器通过在父region中创建splits目录来完成
这个过程,接下来关闭该region,此后这个region不再接受任何请求。

当往hbase中写数据的时候有可能多个region同时达到10G,则它们会同时切割,这就可能导致服务器工作瞬间增大,这就是所谓的切割风暴。

7.2 预防手段——预先切割

创建表时,预先对表进行切割。切割线是rowkey。

$hbase>create 'ns1:t2','f1',SPLITS=>['row3000','row6000']

8、协处理器(coprocessor),相当于一个拦截器

批处理的,等价于存储过程或者触发器
这里写图片描述

[Observer]
        观察者,类似于触发器,基于事件。发生动作时,回调相应方法。
        RegionObserver      //RegionServer区域观察者
        MasterObserver      //Master节点。
        WAlObserver         //
[Endpoint]
        终端,类似于存储过程。

1、关闭hbase集群并配置

[hbase-site.xml]
        <property>
            <name>hbase.coprocessor.region.classes</name>
            <value>coprocessor.RegionObserverExample, coprocessor.AnotherCoprocessor</value>
        </property>
        <property>
            <name>hbase.coprocessor.master.classes</name>
            <value>coprocessor.MasterObserverExample</value>
        </property>
        <property>
            <name>hbase.coprocessor.wal.classes</name>
            <value>coprocessor.WALObserverExample, bar.foo.MyWALObserver</value>
        </property>

2、自定义观察者

package cn.ctgu.hbasedemo.coprocessor;

import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

/*
*
* 自定义区域观察者
*
* */
public class MyRegionObserver extends BaseRegionObserver{

    private void outInfo(String str){
        try {
            FileWriter fw = new FileWriter("/home/hadoop/coprocessor.txt",true);
            fw.write(str + "\r\n");
            fw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public void start(CoprocessorEnvironment e) throws IOException {
        super.start(e);
        outInfo("MyRegionObserver.start()");
    }

    public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException {
        super.preOpen(e);
        outInfo("MyRegionObserver.preOpen()");
    }

    public void postOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
        super.postOpen(e);
        outInfo("MyRegionObserver.postOpen()");
    }


    public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results) throws IOException {
        super.preGetOp(e, get, results);
        String rowkey = Bytes.toString(get.getRow());
        outInfo("MyRegionObserver.preGetOp() : rowkey = " + rowkey);
    }

    public void postGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results) throws IOException {
        super.postGetOp(e, get, results);
        String rowkey = Bytes.toString(get.getRow());
        outInfo("MyRegionObserver.postGetOp() : rowkey = " + rowkey);
    }

    public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
        super.prePut(e, put, edit, durability);
        String rowkey = Bytes.toString(put.getRow());
        outInfo("MyRegionObserver.prePut() : rowkey = " + rowkey);
    }


    public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
        super.postPut(e, put, edit, durability);
        String rowkey = Bytes.toString(put.getRow());
        outInfo("MyRegionObserver.postPut() : rowkey = " + rowkey);
    }


    public void preDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
        super.preDelete(e, delete, edit, durability);
        String rowkey = Bytes.toString(delete.getRow());
        outInfo("MyRegionObserver.preDelete() : rowkey = " + rowkey);
    }


    public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
        super.postDelete(e, delete, edit, durability);
        String rowkey = Bytes.toString(delete.getRow());
        outInfo("MyRegionObserver.postDelete() : rowkey = " + rowkey);
    }
}

3、注册协处理器并分发

<property>
            <name>hbase.coprocessor.region.classes</name>
            <value>cn.ctgu.hbasedemo.coprocessor.MyRegionObserver</value>
        </property>

4、导出jar包

5、复制jar到共享目录,分发到jar到hbase集群的hbase lib目录下.
开启hbase集群会执行

outInfo("MyRegionObserver.start()");
outInfo("MyRegionObserver.preOpen()");

集群开启之后会执行

outInfo("MyRegionObserver.postOpen()");

获取操作之前会执行

outInfo("MyRegionObserver.preGetOp() : rowkey = " + rowkey);

获取操作之后执行

outInfo("MyRegionObserver.postGetOp() : rowkey = " + rowkey);

执行查询动作之前执行

outInfo("MyRegionObserver.prePut() : rowkey = " + rowkey);

执行查询动作之后执行

outInfo("MyRegionObserver.postPut() : rowkey = " + rowkey);

删除动作之前执行

outInfo("MyRegionObserver.preDelete() : rowkey = " + rowkey);

删除动作之后执行

outInfo("MyRegionObserver.postDelete() : rowkey = " + rowkey);

9、热点问题
所谓的热点问题就是数据分布不均匀,有些RegionServer上存储着大量数据,有些RegionServer上则存储着较少数据,导致负载不均衡。

为了解决热点问题,需要将数据均匀分散,对rowkey进行分区编号就是解决热点问题的手段之一,它是通过对md5值就行改造,将数据均匀分散在多个RegionServer上。

案例——通话记录优化

1.创建表

create 'ns1:calllogs','f1'

2.创建单元测试
这里写图片描述
这里写图片描述

package cn.ctgu.hbasedemo.test;

import hbasedemo.coprocessor.Util;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;

/*
*
* 通话日志
* */
public class TestCallLog {
    /*
    *
    * rowkey结构设计:
    *
    * 区号,主叫或被叫,时间,方向0-主 1-被,对方号码,时长
    * xx   callerid  time  direction   calleid duration
    *
    * */
    @Test
    public void put() throws Exception {
        Configuration conf= HBaseConfiguration.create();
        Connection conn= ConnectionFactory.createConnection(conf);
        TableName tname=TableName.valueOf("ns1:calllogs");
        Table table=conn.getTable(tname);

        String callerId="13845450000";
        String calleeId="13989891111";
        SimpleDateFormat sdf=new SimpleDateFormat();
        sdf.applyPattern("yyyyMMddHHmmss");
        String callTimes=sdf.format(new Date());
        int duration=100;
        DecimalFormat dff=new DecimalFormat();
        dff.applyPattern("00000");
        String durstr=dff.format(duration);

        //区域00-99,substring(0,6)这是将同一个号码的相同年月份的数据作为一个rowkey
        int hash=(callerId+callTimes.substring(0,6)).hashCode();
        hash=(hash&Integer.MAX_VALUE)%100;//防止出现负数

        //hash区域号
        DecimalFormat df=new DecimalFormat();
        df.applyPattern("00");
        String regNo=df.format(hash);

        //拼接rowkey
        //xx   callerid  time  direction   calleid duration
        String rowkey=regNo+","+callerId+","+callTimes+","+"0,"+calleeId+","+durstr;
        byte[]rowid= Bytes.toBytes(rowkey);
        Put put=new Put(rowid);
        put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("callerPos"),Bytes.toBytes("河北"));
        put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("callerPos"),Bytes.toBytes("河南"));
        //执行插入
        table.put(put);
        System.out.println("over");
    }
    //插入多条通话记录
    @Test
    public void puts() throws Exception {
        for(int i=0;i<10;i++){
            put();
            Thread.sleep(1000);
        }
    }
    //打印通话记录,查询的时候只需要查询rowkey即可
    @Test
    public void printCallLogs() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        TableName tname=TableName.valueOf("ns1:calllogs");
        Table table=conn.getTable(tname);
        Scan scan=new Scan();

        String callerId="13845450000";
        String month="201806";

        String regNo= Util.getRegNo(callerId,month);
        String startKey=regNo+","+callerId+","+month;
        scan.setStartRow(Bytes.toBytes(startKey));

        String stopKey=regNo+","+callerId+","+"201807";
        scan.setStopRow(Bytes.toBytes(stopKey));
        ResultScanner rs=table.getScanner(scan);
        Iterator<Result>it=rs.iterator();
        while(it.hasNext()){
            String row=Bytes.toString(it.next().getRow());
            System.out.println(row);
        }

        System.out.println("over");

    }
    //测试布隆过滤器,
    @Test
    public void createBloomFilter() throws Exception {
        Configuration conf=HBaseConfiguration.create();
        Connection conn=ConnectionFactory.createConnection(conf);
        Admin admin=conn.getAdmin();
        TableName tableName=TableName.valueOf("ns1:t10");
        HTableDescriptor tbl=new HTableDescriptor(tableName);
        HColumnDescriptor col=new HColumnDescriptor("f1");
        col.setBloomFilterType(BloomType.ROW);
        tbl.addFamily(col);
        admin.createTable(tbl);
        System.out.println("over");
    }

}

这里写图片描述
这里写图片描述
这里写图片描述
3.创建协处理器
Util.java

package hbasedemo.coprocessor;

import java.text.DecimalFormat;

public class Util {
    public static String getRegNo(String callerId,String callTime){
        //区域00-99
        int hash=(callerId+callTime.substring(0,6)).hashCode();
        hash=(hash & Integer.MAX_VALUE)%100;

        //hash区域号
        DecimalFormat df=new DecimalFormat();
        df.applyPattern("00");
        String regNo=df.format(hash);

        return regNo;
    }
}

CalleeLogRegionObserver.java

package hbasedemo.coprocessor;


import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;


import java.io.FileWriter;
import java.io.IOException;


/*
*
* 自定义区域观察者
*
* */
public class CalleeLogRegionObserver extends BaseRegionObserver{

    //postPut是在put执行完后执行的
    public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
        FileWriter fw=new FileWriter("/home/hadoop/regionLog.txt",true);
        super.postPut(e,put,edit,durability);
        //
       String tableName0=TableName.valueOf("ns1:calllogs").getNameAsString();
        //得到当前的tableName对象
        String tableName1=e.getEnvironment().getRegion().getRegionInfo().getTable().getNameAsString();
        fw.write(tableName1+"\r\n");
        if(!tableName0.equals(tableName1)){
            return;
        }
        //得到主叫的rowkey
        //xx   callerid  time  direction   calleid duration
        //被叫:calleid,time
        //通话记录不仅需要在主叫的区域上写入,在被叫的区域上也得写入(这个工作交由协处理器完成)
        String rowkey=Bytes.toString(put.getRow());
        String[]arr=rowkey.split(",");
        if(arr[3].equals("1")){
            return;
        }

        String hash=Util.getRegNo(arr[4],arr[2]);

        String newRowKey=hash+","+arr[4]+","+arr[2]+",1,"+arr[1]+","+arr[5];
        Put newPut=new Put(Bytes.toBytes(newRowKey));
        newPut.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("dummy"),Bytes.toBytes("no"));

        TableName tn=TableName.valueOf("ns1:calllogs");
        Table t=e.getEnvironment().getTable(tn);

        fw.write(t.getName().getNameAsString()+"\r\n");
        t.put(newPut);
        fw.close();
    }

}

4.配置hbase-site.xml并分发

<property>
            <name>hbase.coprocessor.region.classes</name>
            <value>hbasedemo.coprocessor.CalleeLogRegionObserver</value>
</property>

5.启动hbase集群.

10、phonix

phonix是建立在Hbase基础之上的,将hbase复杂的操作转化为熟悉的mysql操作的一种工具。
这里写图片描述

1.安装phonix

a)下载apache-phoenix-4.10.0-HBase-1.2-bin.tar.gz
b)tar
c)复制xxx-server.jar到hbase的lib目录,并且分发,删除以前的phonixjar包。
d)重启hbase

2.使用phonix的命令行程序

phonix/bin/$>  ./sqlline.py s202   //连接的是zk服务器
$phonix>!tables
$phonix>!help                  //查看帮助

3、SQL Client安装

a)下载squirrel-sql-3.7.1-standard.jar
    该文件是安装文件,执行的安装程序。
    $>jar -jar squirrel-sql-3.7.1-standard.jar
    $>下一步...

b)复制phoenix-4.10.0-HBase-1.2-client.jar到SQuerrel安装目录的lib下(c:\myprograms\squirrel)。

c)启动SQuirrel(GUI)
    定位安装目录->执行squirrel-sql.bat

d)打开GUI界面

d)在左侧的边栏选中"Drivers"选项卡,
    点击 "+" ->
    URL:jdbc:phoenix:192.168.231.202
    Driverclass:org.apache.phoenix.jdbc.PhoenixDriver   
    jdbc:phoenix: s202

d)测试。

4.SQLLine客户端操作

//建表
$jdbc:phoenix>create table IF NOT EXISTS test.Person (IDCardNum INTEGER not null primary key, Name varchar(20),Age INTEGER);

//插入数据
$jdbc:phoenix>UPSERT INTO test.PERSON(IDCardNum , Name,Age) VALUES (1,'tom',12);

//删除数据
$jdbc:phoenix>delete from test.persion where idcardnum = 1 ;

//更新数据
//upsert into test.PERSON(IDCardNum , Name,Age) VALUES (1,'tom',12);

将hbase的表影射到hive上,使用hive的查询语句

CREATE TABLE t11(key string, name string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' 
    WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf:name")
    TBLPROPERTIES("hbase.table.name" = "ns1:t11");  

select count(*) from mydb.t11 ;

猜你喜欢

转载自blog.csdn.net/jorocco/article/details/80805106
今日推荐