Phoenix基本使用(HBase)

来源:互联网 发布:淘宝人肉一个人多钱 编辑:程序博客网 时间:2024/05/21 21:40

HBase迁移

最好的学习资料

http://phoenix.apache.org

相关的数据库表

此处记录了对应表格的MySql中的数据库中table的DDL和HBase中使用Phoenix建立表的DDL

HBase Table DDL

商品操作记录表CREATE TABLE IF NOT EXISTS tb_product_log_record (  id varchar(100) primary key, -- 主键Id 需要进行设计这个就是 一个记录对应的row key ( 一般是根据查询条件进行设计 )  product_id varchar(100) , -- 商品Id  product_nm varchar(200)  , -- 商品的属性  seller_id INTEGER, -- 卖家id  cur_state INTEGER, -- 当前商品的状态  subject_id varchar(100)  , -- 类目Id  seller_acount varchar(100)  , -- 卖家账户的名称  handler_txt varchar(100)  , -- 处理内容,上下架 ,删除 这样的操作,修改不会  record_dt timestamp  , -- 操作的时间记录  subject_name varchar(64)  , -- 类目名称  old_snap_id varchar(32) , -- 旧快照ID   new_snap_id varchar(32) , -- 新快照ID  oper_source INTEGER -- 操作来源,1:商城,2:招商,3:ERP);

MySql Table DDL

原数据库表CREATE TABLE `tb_product_log_record` (  `id` bigint(20) NOT NULL COMMENT '主键',  `product_id` varchar(100) DEFAULT NULL COMMENT '商品ID',  `product_nm` varchar(200) DEFAULT NULL COMMENT '商品名称',  `seller_id` int(11) DEFAULT NULL COMMENT '商家ID',  `cur_state` int(2) DEFAULT NULL COMMENT '修改是当前的状态',  `subject_id` varchar(100) DEFAULT NULL COMMENT '科目ID',  `seller_acount` varchar(100) DEFAULT NULL COMMENT '商家登录账号',  `handler_txt` varchar(100) DEFAULT NULL COMMENT '处理内容,上下架 ,删除 这样的操作,修改不会',  `record_dt` timestamp NULL DEFAULT NULL COMMENT '操作的时间记录',  `subject_name` varchar(64) DEFAULT NULL COMMENT '类目名称',  `old_snap_id` varchar(32) DEFAULT NULL COMMENT '旧快照ID',  `new_snap_id` varchar(32) DEFAULT NULL COMMENT '新快照ID',  `oper_source` int(2) DEFAULT NULL COMMENT '操作来源,1:商城,2:招商,3:ERP',  PRIMARY KEY (`id`),  KEY `idx_pid` (`product_id`,`id`),  KEY `idx_record_dt` (`record_dt`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

关于数据类型的对应

这里想好好说一下数据类型的对应关系,MySql迁移到HBase中的时候数据类型会有一定的改变(MYSQL有对应的数据类型,HBase存储的都是字节数组类型),这个地方就涉及到了类型的转换。还好Phoenix为我们提供了,各种数据类型。

Mysql Phoenix bigint bigint varchar(100) varchar(100) timestamp timestamp int(11) INTEGER

以上内容的转换只是使用到了这几种数据类型的转换,日后如果还有对应的类型,会继续进行添加。

执行主键的两种方式

  1. id varchar(100) primary key
  2. constraint my_pk primary key (state, city)

这里的主键就是HBase中的rowKey。需要好好设计这个里面的row Key,合理的设计row key 可以带来更好的查询性能方面的优化。

讲讲Phoenix

Overview

Apache Phoenix enables OLTP and operational analytics in Hadoop for low latency applications by combining the best of both worlds:

  1. the power of standard SQL and JDBC APIs with full ACID transaction capabilities and
    the flexibility of late-bound, schema-on-read capabilities from the NoSQL world by leveraging HBase as its backing store
  2. Apache Phoenix is fully integrated with other Hadoop products such as Spark, Hive, Pig, Flume, and Map Reduce.

主要就是说这个提供了一种实时对Hadoop的OLTP的功能。

为什么选取Phoenix

主要是因为我们的项目都是从MySql上面进行迁移过来的,我们的Dao层使用的是Mybatis,并且查询语句都是比较简单的SQL,如果对其进行Hbase的改造,会导致Dao层需要多的重构,涉及到业务等,迁移尽量不对业务进行影响。而Phoenix正提供了在ORM和数据源中间的一种转换层。

SQL Support

Apache Phoenix takes your SQL query, compiles it into a series of HBase scans, and orchestrates the running of those scans to produce regular JDBC result sets. Direct use of the HBase API, along with coprocessors and custom filters, results in performance on the order of milliseconds for small queries, or seconds for tens of millions of rows.

To see a complete list of what is supported, go to our language reference. All standard SQL query constructs are supported, including SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, etc. It also supports a full set of DML commands as well as table creation and versioned incremental alterations through our DDL commands.

Here’s a list of what is currently not supported:

Relational operators. Intersect, Minus.
Miscellaneous built-in functions. These are easy to add - read this blog for step by step instructions.

如何使用

因为使用的是java,所以就贴一下Spring的配置:

<bean id="phoenixDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">        <property name="driverClass" value="org.apache.phoenix.jdbc.PhoenixDriver"/>        <!-- 需要注意Phoenix的id地址 和 user passwd-->        <property name="jdbcUrl" value="jdbc:phoenix:127.0.0.1:2181"/>        <property name="user" value=""/>        <property name="password" value=""/>        <property name="initialPoolSize" value="20"/>        <property name="maxStatements" value="0"/>        <!--因为Phoenix进行数据更改时不会自动的commit,必须要添加defaultAutoCommit属性,否则会导致数据无法提交的情况-->        <property name="autoCommitOnClose" value="true"/>    </bean>    <!-- 只读interface -->    <bean id="hbaseSessionFactoryReadInterface" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="phoenixDataSource"/>        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>        <property name="mapperLocations">            <array>                <value>classpath:mybatis/sqlmap/HbaseSQL/*.xml</value>            </array>        </property>    </bean>    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="basePackage" value="com.gy.test.model.hbasemapper"/>        <property name="sqlSessionFactory" ref="hbaseSessionFactoryReadInterface"/>    </bean>

主需要改变mysql的数据源就可以了。可以继续使用Mybatis之前生成的Mapper,但是对应的类型如果需要转换,需要转换一下。例如在MySql中我的主键是Bigint类型的,但是Hbase中我存储的是Varchar。

分页查询

Phoenix提供的SQL转换都很优秀,实验了一下基本的查询语句,添加,更新(upsert)和delete语句都很完美的支持了。甚至连连表等操作也支持。但是分页查询却是没有很好的支持,至少在我查到之前觉得~

查了很多网上的帖子,都是要先找到startRowkey然后让主键进行大于的方式进行分页查询,因为在Phoenix中没有提供给我们像MySql中的 limit 10,20这种方式去查询数据。最后终于在我们磊神的帮助下找到了!

OFFSET with LIMIT

使用 OFFSET 关键字去指定从第几个RowKey去查询,使用Limit来指定查询页面的大小, OFFSET相当于 MySql limit start,size 中的start.

Example:

SELECT title, author, isbn, descriptionFROM libraryWHERE published_date > 2010ORDER BY title, author, isbnLIMIT 10 OFFSET 10

符合条件的情况下,我们从第二页查询(每页10条),查询10条。

Phoenix其实也需要去定位StartRowKey,其实也是去查询这个startRowKey,至于查询这个条件的效率主要取决于我们的查询条件,建议是使用rowKey的查询或建立二级索引。

数据导入

一开始是想使用程序去导入数据,但是涉及到很多的问题,包括程序中间操作失败啊等情况,所以打算使用Phoenix自带的工具进行csv格式的数据进行导入操作。

https://phoenix.apache.org/bulk_dataload.htmlbin/psql.py -t EXAMPLE localhost data.csv命令可以进行导入数据s

创建索引

CREATE INDEX my_index ON my_table (v1,v2) INCLUDE(v3)

这个是对my_table这个表的 v1,v2 字段建立一个索引,然后建立的索引可以查询出v3 这个字段。

第一步执行:CREATE INDEX my_index ON TB_PRODUCT_LOG_RECORD_CONTENT (log_id);执行计划:explain select * from tb_product_log_record_content where log_id =  1016010515188290002结果:CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER TB_PRODUCT_LOG_RECORD_CONTENT SERVER FILTER BY LOG_ID = 1016010515188290002

以上的情况,使用了全表的FULL SCAN,这个主要是因为我们设置索引的时候没有把对应的*的所有字段包含到这个索引的Include里面。

在Phoenix中进行查询

我们能查询到一个名字为 my_index的表,这个表里面包含一个字段,log_id。
ok以上的情况就可以说明了,Phoenix创建的二级索引,其实就是针对对应的索引字段创建了一个以这个索引字段为rowKey,然后以 include 的field,作为列的一个表。

我们想查询*,这个包含了很多字段,在这个表里面没有找到当然要去到Full Scan里面进行查询啦。

关注插入

上节既然说到了这个是两张表,那么插入的时候是否会两边都插入呢?

第一步执行 :upsert into tb_product_log_record_content (id,handle_tp,handle_centent,org_content,cur_content,log_id) values ('11000000000000002',1,1,'aa','bb',1);第二步在Phoenix中执行:select count(*) from tb_product_log_record_content;Phoenix中的结果:+-----------+| COUNT(1)  |+-----------+| 44047     |+-----------+第三步在HBase中执行:count ‘my_index′ 也会得到同样的结果

验证了之前说的创建索引后两边表都会进行插入的情况。
这样的话如果创建索引那么相当于把对应的内容又重新存储了一遍,Phoenix帮我们设置了rowkey。

0 0