最具影响力的数字化技术在线社区

168大数据

 找回密码
 立即注册

QQ登录

只需一步,快速开始

1 2 3 4 5
打印 上一主题 下一主题
开启左侧

[综合] 基于hadoop生态圈的数据仓库实践 — OLAP与数据可视化(一)

[复制链接]
跳转到指定楼层
楼主
发表于 2018-12-27 16:13:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多数据大咖,获取更多知识干货,轻松玩转大数据

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
一、OLAP与Impala简介
1. OLAP简介
        OLAP是Online Analytical Processing的缩写,意为联机分析处理。此概念最早是由关系数据库之父E.F.Codd于1993年提出,至今已有20多年。OLAP允许以一种称为多维数据集的结构,访问业务数据源经过聚合和组织整理的后数据。以此为标准,OLAP作为单独的一类产品同联机事务处理(OLTP)得以明显区分。
        在计算领域,OLAP是一种快速应答多维分析查询的方法,也是商业智能的一个组成部分,与之相关的概念还包括数据仓库、报表系统、数据挖掘等。数据仓库用于数据的存储和组织,OLAP集中于数据的分析,数据挖掘则致力于知识的自动发现,报表系统则侧重于数据的展现。OLAP从数据仓库中的集成数据出发,构建面向分析的多维数据模型,再使用多维分析方法从多个不同的视角对多维数据进行分析比较,分析活动以数据驱动。
        通过使用OLAP工具,用户可以从多个视角交互式地分析多维数据。OLAP由三个基本的分析操作构成:合并(上卷)、下钻和切片。合并是指数据的聚合,即数据可以在一个或多个维度上进行累积和计算。例如,所有的营业部数据被上卷到销售部门以分析销售趋势。下钻是一种由汇总数据向下浏览细节数据的技术,比如用户可以从产品分类的销售数据下钻查看单个产品的销售数据。切片则是这样一种特性,通过它用户可以获取OLAP立方体中的特定数据集合,并从不同的视角观察这些数据。这些观察数据的视角又叫做维度(例如通过经销商、日期、客户、产品或区域等等,查看同一销售数据)。
        OLAP系统的核心是OLAP立方体(或称为多维立方体或超立方体)。它由被称为度量的数值事实组成,这些度量被维度划分归类。一个OLAP立方体的例子如下图所示,数据单元位于立方体的交叉点上,每个数据单元跨越产品、时间、位置等多个维度。通常使用一个矩阵接口操作OLAP立方体,例如电子表格程序的数据透视表,可以按维度分组执行聚合或求平均值等操作。立方体的元数据一般由关系数据库中的星型模式或雪花模式生成,度量来自事实表的记录,维度来自维度表。
        OLAP分析所需的原始数据量是非常庞大的。一个分析模型,往往会涉及数千万或数亿条数据,甚至更多,而分析模型中包含多个维度数据,这些维度又可以由用户作任意的组合。这样的结果就是大量的实时运算导致过长的响应时间。想象一个1000万条记录的分析模型,如果一次提取4个维度进行组合分析,每个维度有10个不同的取值,理论上的运算次数将达到10的12次方。这样的运算量将导致数十分钟乃至更长的等待时间。如果用户对维组合次序进行调整,或增加、或减少某些维度的话,又将是一个重新的计算过程。
        从上面的分析中可以得出结论,如果不能解决OLAP运算效率问题的话,OLAP将只会是一个没有实用价值的概念。在OLAP的发展历史中,常见的解决方案是用多维数据库代替关系数据库设计,将数据根据维度进行最大限度的聚合运算,运算中会考虑到各种维度组合情况,运算结果将生成一个数据立方体,并保存在磁盘上。用这种以空间换时间的预运算方式提高OLAP的速度。那么,在大数据流行的今天,又有什么产品可以解决OLAP的效率问题呢?且看hadoop生态圈中适合做OLAP的组件——Impala。


2. Impala简介
(1)Impala是什么
        Impala是一个运行在Hadoop之上的大规模并行处理(MPP)查询引擎,提供对Hadoop集群数据的高性能、低延迟的SQL查询,使用HDFS作为底层存储。它是基于Google Dremel的开源实现。对查询的快速响应使交互式查询和对分析查询的调优成为可能,而这些在针对处理长时间批处理作业的SQL-on-Hadoop传统技术上是无法完成的。
        Impala与Hive元数据存储数据库相结合,在这两个组件之间共享数据库表,并且Impala与HiveQL的语法兼容。因此既可以使用Impala也可以使用Hive进行建立表、发布查询、装载数据等操作。Impala可以在已经存在的Hive表上执行交互式实时查询。


(2)为什么要使用Impala
Impala可以使用SQL访问存储在Hadoop上的数据,而传统的MapReduce则需要掌握Java技术。Impala还提供SQL直接访问HDFS文件系统、HBase数据库系统或Amazon S3的数据。
Impala在Hadoop生态系统之上提供并行处理数据库技术,允许用户执行低延迟的交互式查询。
Impala大都能在几秒或几分钟内返回查询结果,而相同的Hive查询通常需要几十分钟甚至几小时完成。
Impala的实时查询引擎非常适合对Hadoop文件系统上的数据进行分析式查询。
由于Impala能实时给出查询结果,使它能够很好地与Pentaho、Tableau这类报表或可视化工具一起使用(这些工具已经配备了Impala连接器,可以从GUI直接执行可视化查询)。
Impala与Hadoop生态圈相结合,内置对所有Hadoop文件格式(ORC、Parquet等等)的支持。这意味着可以使用Hadoop上的各种解决方案存储、共享和访问数据,同时避免了数据竖井,并且降低了数据迁移的成本。
Impala缺省使用Parquet文件格式,这种列式存储对于典型数据仓库场景下的大查询是最优的。
        Impala之所以使用Parquet文件格式,最初灵感来自于Google 2010年发表的Dremel论文,文中论述了对大规模查询的优化。Parquet是一种列式存储,它不像普通数据仓库那样水平存储数据,而是垂直存储数据。当查询在数值列上应用聚合函数时,这种存储方式将带来巨大的性能提升。原因是只需要读取文件中该列的数据,而不是像Hive需要读取整个数据集。Parquet文件格式支持高效的压缩编码方式(例如Hadoop和Hive缺省使用的snappy压缩),Parquet文件也可用Hive和Pig处理。


(3)适合Impala的使用场景
需要低延迟得到查询结果。
快速分析型查询。
实时查询。
需要多次处理相同类型的查询。
        总而言之,Impala非常适合OLAP类型的查询需求。


(4)Impala架构
        Impala架构图如下所示。



        Impala服务器是一个分布式、大规模并行处理(MPP)数据库引擎。它由不同的守护进程组成,每种守护进程运行在Hadoop集群中的特定主机上。其中Impalad、Statestored、Catalogd三个守护进程在其架构中扮演主要角色。


        Impala守护进程
        Impala的核心组件是一个运行在集群中每个数据节点上的守护进程,物理表现为impalad进程。该进程读写数据文件,接收从impala-shell命令行、Hue、JDBC、ODBC提交的查询请求,将查询工作并行分布到集群的数据节点上,并将查询的中间结果返回给中心协调节点。
        可以将查询提交至任意一个数据节点上运行的Impala守护进程,此守护进程实例担任该查询的协调器,其它节点提交部分中间结果返给协调器,协调器构建查询的最终结果集。当在试验环境使用impala-shell命令行运行SQL时,出于方便性,通常总是连接同一个Impala守护进程。而在生产环境负载的集群中,可以采用循环的方式,通过JDBC或ODBC接口,将每个查询轮流提交至不同的Impala守护进程,已达到负载均衡。
        Impala守护进程持续与statestore进行通信,以确认每个节点健康状况以及是否可以接收新的任务。
        当集群中的任何Impala节点建立、修改、删除任何类型的对象,或者通过Impala处理一个insert或load data语句时,catalogd守护进程(Impala 1.2引入)都会发出广播消息。Impala守护进程会接收这种从catalogd守护进程发出的广播消息。这种后台通信减少了对refresh或invalidate metadata语句的需要,而在Impala 1.2版本前,这些语句被用于在节点间协调元数据信息。


        Impala Statestore
        叫做statestore的Impala组件检查集群中所有数据节点上Impala守护进程的健康状况,并将这些信息持续转发给每个Impala守护进程。其物理表现为一个名为statestored的守护进程,该进程只需要在集群中的一台主机上启动。如果Impala守护进程由于硬件、软件、网络或其它原因失效,statestore会通知所有其它的Impala守护进程,这样以后的查询就不会再向不可到达的节点发出请求。
        statestore的目的只是在发生某种错误时提供帮助,因此在正常操作一个Impala集群时,它并不是一个关键组件。即使statestore没有运行或者不可用,Impala守护进程依然会运行,并像通常一样在它们中分法任务。 这时如果一个Impala守护进程失效,仅仅是降低了集群的鲁棒性。当statestore恢复可用后,它会重建与Impala守护进程之间的通信并恢复监控功能。
        在Impala中,所有负载均衡和高可用的考虑都是用于Impala守护进程的。statestored和catalogd进程没有高可用的需求,因为这些进程即使出现问题也不会引起数据丢失。当这些进程由于所在的主机停机而变成不可用时,可以这样处理:先停止Impala服务,然后删除Impala StateStore和Impala Catalog服务器角色,再在另一台主机上添加这两个角色,最后重启Impala服务。


        Impala Catalog服务
        称为Catalog服务的Impala组件将Impala SQL语句产生的元数据改变转发至集群中的所有数据节点。其物理表现为一个名为catalogd的守护进程,该进程只需要在集群中的一台主机上启动,而且应该与statestored进程在同一台主机上。
        由于catalog服务的存在,当通过执行Impala语句而改变元数据时,不需要再发出refresh或invalidate metadata语句。然而,当通过Hive执行建立表、装载数据等操作后,在一个Impala节点上执行查询前,仍然需要先发出refresh或invalidate metadata语句。例如,通过Impala执行的create table、insert或其它改变表或改变数据的操作,无需执行refresh and invalidate metadata语句。而如果这些操作是用过Hive执行的,或者是直接操纵的HDFS数据文件,仍需执行refresh and invalidate metadata语句(只需在一个Impala节点执行,而不是全部节点)。
        缺省情况下,元数据在Impala启动时异步装载并缓存,这样Impala可以立即接收查询请求。如果想让Impala等所有元数据装载后再接收查询请求,需要设置catalogd的配置选项load_catalog_in_background=false。


(4)开发Impala应用
        Impala SQL方言
        Impala的核心开发语言是SQL,也可以使用Java或其它语言,通过JDBC或ODBC接口与Impala进行交互,许多商业智能工具都使用这种方式。对于特殊的分析需求,还可以用C++或Java编写用户定义的函数(UDFs),补充SQL内建的功能。
        Impala的SQL方言与Hive组件(HiveQL)在语法上高度兼容。正因如此,对于熟悉Hadoop架构上SQL查询的用户来说,Impala SQL并不陌生。当前,Impala SQL支持HiveQL语句、数据类型、内建函数的一个子集。Impala还包含一些附加的符合工业标准的内建函数,用于简化从非Hadoop系统移植SQL。
        对于具有传统数据库或数据仓库背景的用户来说,下面关于SQL方言的内容应该是非常熟悉的:


包含where、group by、order by、with等子句的select语句(Impala的with子句并不支持递归查询),连接操作,处理字符串、数字、日期的内建函数、聚合函数、子查询、in和between这样的比较操作符等。这些select语句与SQL标准是兼容的。
分区表在数据仓库中经常使用。把一个或多个列作为分区键,数据按照分区键的值物理分布。当查询的where子句中包含分区键列时,可以直接跳过不符合过滤条件的分区,这也就是所谓的“分区消除”。例如,假设有10年的数据,并且查询语句中有类似where year = 2015、where year > 2010、where year in (2014, 2015)的where子句,则Impala跳过所有不匹配年份的数据,这会大大降低查询的I/O数量。
在Impala 1.2及其以上版本中,UDFs可以在select和insert...select语句中执行定制的比较和转换逻辑。
        如果对Hadoop环境不够熟悉但具有传统数据库或数据仓库背景,需要学习并实践一下Impala SQL与传统SQL的不同之处:


Impala SQL专注于查询而不是DML,所以没有提供update或delete语句。对于没用的陈旧数据,典型的做法是使用drop table或alter table ... drop partition语句直接删除,或者使用 insert overwrite语句将老数据替换掉。
在Impala中,所有的数据创建都是通过insert语句,典型情况是通过查询其它表批量插入数据。insert语句有两种插入数据的方式,insert into在现有数据上追加,而insert overwrite则会替换整个表或分区的内容(效果就像先truncate table再insert一样)。Impala没有insert ... values的插入单行的语法。
比较常见的情况是,在其它环境建立表和数据文件,然后使用Impala对其进行实时查询。相同的数据文件和表的元数据在Hadoop生态圈的不同组件之间共享。例如,Impala可以访问Hive里的表和数据,而Hive也可以访问在Impala中建立的表及其数据。许多其它的Hadoop组件可以生成Parquet和Avro格式的文件,Impala也可以查询这些文件。
Hadoop和Impala的关注点在大数据集上的数据仓库型操作,因此Impala包含一些对于传统数据库应用系统非常重要的SQL方言。例如,可以在create table语句中指定分隔符,通过表读取以逗号和tab做分隔的文本文件。还可以建立外部表,在不迁移和转换现有数据文件的前提下读取它们。
impala读取的大量数据可能不太容易确定其长度,所以不能强制字符串类型数据的长度。例如,可以定义一个表列为string类型,而不是象char(1)或varchar(64)限制字符串长度。(在Impala 1.2及其以后版本中,可以使用char和varchar类型限制字符串长度。)
        Impala编程接口
        可以通过下面的接口连接Impala,并向Impala守护进程提交请求。
impala-shell命令行接口
Hue基于web的用户界面
JDBC
ODBC
        使用这些接口,可以在异构环境下使用Impala,如在非Linux平台上运行的JDBC、ODBC应用,还可以使用JDBC、ODBC接口将Impala和商业智能工具结合使用。
        每个impalad守护进程运行在集群中的不同节点上,监听来自多个端口的请求。来自impala-shell和Hue的请求通过相同的端口被路由至impalad守护进程,而JDBC和ODBC的请求发往不同的impalad监听端口。


(5)Impala与Hadoop生态圈
        Impala可以利用Hadoop生态圈中许多熟悉的组件,并且可以和这些组件交换数据,即可作为生产者也可作为消费者,因此可以灵活地加入到ETL管道中。
        Impala与Hive
        Impala的一个主要目标是让SQL-on-Hadoop操作足够快,以吸引新的Hadoop用户,或开发Hadoop新的使用场景。在实际中,许多Hadoop用户使用Hive来执行长时间运行的、面向批处理的SQL查询,而Impala可以利用这些已有的Hive架构。Impala将它的表定义存储在一个传统的MySQL或PostgreSQL数据库中,这个数据库被称为metastore,而Hive也将其元数据存储在同一个的数据库中。通过这种方式,只要Hive表定义的文件类型和压缩算法为Impala所支持,所有列的数据类型也是Impala所支持的类型,Impala就可以访问它。
        Impala最初被设计成致力于提高查询的性能,这就意味着在Impala里,select语句能够读取的数据的类型比insert语句能够插入的数据的类型要多Impala可以读取使用Hive装载的Avro、RCFile或SequenceFile文件格式的数据。
        Impala查询优化器也可以利用表和列的统计信息。在Impala 1.2.2版本前,使用Hive里的analyze table语句收集这些信息,在Impala 1.2.2及其更高版本中,使用Impala的compute stats语句收集信息。compute stats更灵活也更简单,并且不需要再impala-shell和Hive shell之间来回切换。


        Impala的元数据和元数据存储
        前面讨论Impala如何与Hive一起使用时提到,Impala使用一个叫做metastore的数据库维护它的表定义信息。同时Impala还跟踪其它数据文件底层特性的元数据,如HDFS中数据块的物理位置信息。
        对于一个有很多分区或很多数据的大表,获取它的元数据可能很耗时,有时需要花上几分钟的时间。因此每个Impala节点都会缓存这些元数据,当后面再查询该表时,就可以复用缓存中的元数据。
        如果表定义或表中的数据更新了,集群中所有其它的Impala守护进程在查询该表前,   都必须能收到最新的元数据,并更新自己缓存的元数据。在Impala 1.2或更高版本中,这种元数据的更新是自动的,由catalogd守护进程为所有通过Impala发出的DDL和DML语句进行协调。
        对于通过Hive发出的DDL和DML,或者手工改变了HDFS文件的情况,还是需要在Impala中使用refresh语句(当新的数据文件被加到已有的表上)或invalidate metadata语句(新建表、删除表、执行了HDFS的rebalance操作,或者删除了数据文件)。invalidate metadata语句获取metastore中存储的所有表的元数据。如果能够确定在Impala外部只有特定的表被改变,可以为每一个受影响的表使用refresh 表名,该语句只获取特定表的最新元数据。


        Impala与HDFS
        Impala使用分布式文件系统HDFS作为主要的数据存储介质。Impala依赖HDFS提供的冗余功能,保证在单独节点因硬件、软件或网络问题失效后仍能工作。Impala表数据物理表现为HDFS上的数据文件,这些文件使用常见的HDFS文件格式和压缩算法。


        Impala与Hbase
        除HDFS外,HBase也是Impala数据存储介质的备选方案。HBase是建立在HDFS之上的数据库存储系统,不提供内建的SQL支持。许多Hadoop用户使用HBase存储大量的稀疏数据。在Impala中可以定义表,并映射为HBase中等价的表,通过这种方式就可以使用Impala查询HBase表的内容,甚至可以联合Impala表和HBase表执行关联查询。


二、Hive、Spark SQL、Impala比较
        Hive、Spark SQL和Impala三种分布式SQL查询引擎都是SQL-on-Hadoop解决方案,但又各有特点。前面已经讨论了Hive和Impala,本节先介绍一下SparkSQL,然后从功能、架构、使用场景几个角度比较这三款产品的异同,最后附上分别由cloudera公司和SAS公司出示的关于这三款产品的性能对比报告。
1. Spark SQL简介
        Spark SQL是Spark的一个处理结构化数据的程序模块。与其它基本的Spark RDD API不同,Spark SQL提供的接口包含更多关于数据和计算的结构信息,Spark SQL会利用这些额外信息执行优化。可以通过SQL和数据集API与Spark SQL交互,但无论使用何种语言或API向Spark SQL发出请求,其内部都使用相同的执行引擎,这种统一性方便开发者在不同的API间进行切换。
        Spark SQL具有如下特性:
集成——将SQL查询与Spark程序无缝集成。Spark SQL可以将结构化数据作为Spark的RDD(Resilient Distributed Datasets,弹性分布式数据集)进行查询,并整合了Scala、Java、Python、R等语言的API。这种集成可以使开发者只需运行SQL查询就能完成复杂的分析算法。
统一数据访问——通过Schema-RDDs为高效处理结构化数据而提供的单一接口,Spark SQL可以从Hive表、parquet或JSON文件等多种数据源查询数据,也可以向这些数据源装载数据。
与Hive兼容——已有数据仓库上的Hive查询无需修改即可运行。Spark SQL复用Hive前端和元数据存储,与已存的Hive数据、查询和UDFs完全兼容。
标准的连接层——使用JDBC或ODBC连接。Spark SQL提供标准的JDBC、ODBC连接方式。
可扩展性——交互式查询与批处理查询使用相同的执行引擎。Spark SQL利用RDD模型提供容错和扩展性。
        Spark SQL架构如下图所示。



        此架构包括Language API、Schema RDD、Data Sources三层。
Language API——Spark SQL与多种语言兼容,并提供这些语言的API。
Schema RDD——Schema RDD是存放列Row对象的RDD,每个Row对象代表一行记录。Schema RDD还包含记录的结构信息(即数据字段),它可以利用结构信息高效地存储数据。Schema RDD支持SQL查询操作。
Data Sources——一般Spark的数据源是文本文件或Avro文件,而Spark SQL的数据源却有所不同。其数据源可能是Parquet文件、JSON文档、Hive表或Cassandra数据库。
2. Hive、Spark SQL、Impala比较
(1)功能
        Hive:
是简化数据抽取、转换、装载的工具
提供一种机制,给不同格式的数据加上结构
可以直接访问HDFS上存储的文件,也可以访问HBase的数据
通过MapReduce执行查询
Hive定义了一种叫做HiveQL的简单的类SQL查询语言,用户只要熟悉SQL,就可以使用它查询数据。同时,HiveQL语言也允许熟悉MapReduce计算框架的程序员添加定制的mapper和reducer插件,执行该语言内建功能不支持的复杂分析。
用户可以定义自己的标量函数(UDF)、聚合函数(UDAF)和表函数(UDTF)
支持索引压缩和位图索引
支持文本、RCFile、HBase、ORC等多种文件格式或存储类型
使用RDBMS存储元数据,大大减少了查询执行时语义检查所需的时间
支持DEFLATE、BWT或snappy等算法操作Hadoop生态系统内存储的数据
大量内建的日期、数字、字符串、聚合、分析函数,并且支持UDF扩展内建函数。
HiveQL隐式转换成MapReduce或Spark作业
        Spark SQL:
支持Parquet、Avro、Text、JSON、ORC等多种文件格式
支持存储在HDFS、HBase、Amazon S3上的数据操作
支持snappy、lzo、gzip等典型的Hadoop压缩编码方式
通过使用“shared secret”提供安全认证
支持Akka和HTTP协议的SSL加密
保存事件日志
支持UDF
支持并发查询和作业的内存分配管理(可以指定RDD只存内存中、或只存磁盘上、或内存和磁盘都存)
支持把数据缓存在内存中
支持嵌套结构
        Impala:
支持Parquet、Avro、Text、RCFile、SequenceFile等多种文件格式
支持存储在HDFS、HBase、Amazon S3上的数据操作
支持多种压缩编码方式:Snappy(有效平衡压缩率和解压缩速度)、Gzip(最高压缩率的归档数据压缩)、Deflate(不支持文本文件)、Bzip2、LZO(只支持文本文件)
支持UDF和UDAF
自动以最有效的顺序进行表连接
允许定义查询的优先级排队策略
支持多用户并发查询
支持数据缓存
提供计算统计信息(COMPUTE STATS)
提供窗口函数(聚合 OVER PARTITION, RANK, LEAD, LAG, NTILE等等)以支持高级分析功能
支持使用磁盘进行连接和聚合,当操作使用的内存溢出时转为磁盘操作
允许在where子句中使用子查询
允许增量统计——只在新数据或改变的数据上执行统计计算
支持maps、structs、arrays上的复杂嵌套查询
可以使用impala插入或更新HBase
(2)架构
        Hive:
        构建在Hadoop之上,查询管理分布式存储上的大数据集的数据仓库组件。底层使用MapReduce计算框架,Hive查询被转化为MapReduce代码并执行。生产环境建议使用RDBMS存储元数据。支持JDBC、ODBC、CLI等连接方式。


        Spark SQL:
        底层使用Spark计算框架,提供有向无环图,比MapReduce更灵活。Spark SQL以Schema RDD为核心,模糊了RDD与关系表之间的界线。Schema RDD是一个由Row对象组成的RDD,附带包含每列数据类型的结构信息。Spark SQL复用Hive的元数据存储。支持JDBC、ODBC、CLI等连接方式,并提供多种语言的API。


        Impala:
        底层采用MPP技术,支持快速交互式SQL查询。与Hive共享元数据存储。Impalad是核心进程,负责接收查询请求并向多个数据节点分发任务。statestored进程负责监控所有Impalad进程,并向集群中的节点报告各个Impalad进程的状态。catalogd进程负责广播通知元数据的最新信息。


(3)场景
        Hive:
        适用场景:
周期性转换大量数据,例如:每天晚上导入OLTP数据并转换为星型模式;每小时批量转换数据等。
整合遗留的数据格式,例如:将CSV数据转换为Avro;将一个用户自定义的内部格式转换为Parquet等。
        不适用场景:
商业智能,例如:与Tableau结合进行数据探查;与Micro Strategy一个出报表等。
交互式查询,例如:OLAP查询。
        Spark SQL:
        适用场景:
从Hive数据仓库中抽取部分数据,使用Spark进行分析。
        不适用场景:
商业智能和交互式查询。
        Impala:
        适用场景:
秒级的响应时间
OLAP
交互式查询
        不适用场景:
ETL
UDAF
3. Hive、SparkSQL、Impala性能对比
(1)cloudera公司2014年做的性能基准对比测试,原文链接:http://blog.cloudera.com/blog/20 ... he-performance-gap/
        先看一下测试结果:
对于单用户查询,Impala比其它方案最多快13倍,平均快6.7倍。
对于多用户查询,差距进一步拉大:Impala比其它方案最多快27.4倍,平均快18倍。
        下面看看这个测试是怎么做的。
        配置:
        所有测试都运行在一个完全相同的21节点集群上,每个节点只配有64G内存。之所以内存不配大,就是为了消除人们对于Impala只有在非常大的内存上才有好性能的错误认识:
双物理CPU,每个12核,Intel Xeon CPU E5-2630L 0 at 2.00GHz
12个磁盘驱动器,每个磁盘932G,1个用作OS,其它用作HDFS
每节点64G内存
        对比产品:
Impala 1.4.0
Hive-on-Tez 0.13
Spark SQL 1.1
Presto 0.74
        查询:
21个节点上的数据量为15T
测试场景取自TPC-DS,一个开放的决策支持基准(包括交互式、报表、分析式查询)
由于除Impala外,其它引擎都没有基于成本的优化器,本测试使用的查询都使用SQL-92标准的连接
采用统一的Snappy压缩编码方式,各个引擎使用各自最优的文件格式,Impala和Spark SQL使用Parquet,Hive-on-Tez使用ORC,Presto使用RCFile。
对每种引擎多次运行和调优
        结果:
        单用户如下图所示。



        多用户如下图所示。



        查询吞吐率如下图所示。



        Impala本身就是cloudera公司的主打产品,因此只听其一面之词未免有失偏颇,下面就再看一个SAS公司的测试。


(2)SAS2013年做的Impala和Hive的对比测试
        硬件:
Dell M1000e server rack
10 Dell M610 blades
Juniper EX4500 10 GbE switch
        刀片服务器配置
Intel Xeon X5667 3.07GHz processor
Dell PERC H700 Integrated RAID controller
Disk size: 543 GB
FreeBSD iSCSI Initiator driver
HP P2000 G3 iSCSI dual controller
Memory: 94.4 GB
        软件:
Linux 2.6.32
Apache Hadoop 2.0.0
Apache Hive 0.10.0
Impala 1.0
Apache MapReduce 0.20.2
        数据:
        数据模型如下图所示。



        各表的数据量如下图所示。



        PAGE_CLICK_FLAT表使用Compressed Sequence文件格式,大小124.59 GB。
        查询:
        使用了以下5条查询语句
[AppleScript] 纯文本查看 复制代码
-- What are the most visited top-level directories on the customer support website for a given week and year?
select top_directory, count(*) as unique_visits   
  from (select distinct visitor_id, split(requested_file, '[\\/]')[1] as top_directory
          from page_click_flat
         where domain_nm = 'support.sas.com' 
		   and flash_enabled='1' 
           and weekofyear(detail_tm) = 48 
           and year(detail_tm) = 2012
       ) directory_summary
 group by top_directory
 order by unique_visits;
 
-- What are the most visited pages that are referred from a Google search for a given month?
select domain_nm, requested_file, count(*) as unique_visitors, month
  from (select distinct domain_nm, requested_file, visitor_id, month(detail_tm) as month
          from page_click_flat
         where domain_nm = 'support.sas.com' 
           and referrer_domain_nm = 'www.google.com'
       ) visits_pp_ph_summary
 group by domain_nm, requested_file, month
 order by domain_nm, requested_file, unique_visitors desc, month asc;
 
-- What are the most common search terms used on the customer support website for a given year?
select query_string_txt, count(*) as count
  from page_click_flat
 where query_string_txt <> '' 
   and domain_nm='support.sas.com' 
   and year(detail_tm) = '2012'
 group by query_string_txt
 order by count desc;
 
-- What is the total number of visitors per page using the Safari browser?
select domain_nm, requested_file, count(*) as unique_visitors
  from (select distinct domain_nm, requested_file, visitor_id
          from page_click_flat
         where domain_nm='support.sas.com' 
           and browser_nm like '%Safari%' 
           and weekofyear(detail_tm) = 48 
           and year(detail_tm) = 2012
       ) uv_summary
 group by domain_nm, requested_file
 order by unique_visitors desc;
 
-- How many visitors spend more than 10 seconds viewing each page for a given week and year?
select domain_nm, requested_file, count(*) as unique_visits
  from (select distinct domain_nm, requested_file, visitor_id
          from page_click_flat
         where domain_nm='support.sas.com' 
           and weekofyear(detail_tm) = 48 
           and year(detail_tm) = 2012 
           and seconds_spent_on_page_cnt > 10;
       ) visits_summary
 group by domain_nm, requested_file
 order by unique_visits desc;

        结果:
        Hive与Impala查询时间对比如下图所示。



        可以看到,查询1、2、4Impala比Hive快的多,而查询3、5Impala却比Hive慢很多。这个测试可能更客观一些,而且也从侧面说明了一个问题,不要轻信厂商宣传的数据,还是要根据自己的实际测试情况得出结论。


三、Impala OLAP实例
        本节使用前面销售订单的例子说明如何使用Impala做OLAP类型的查询,以及实际遇到的问题及解决方案。为了处理SCD和行级更新,我们前面的ETL使用了Hive ORCFile格式的表,可惜到目前为止,Impala还不支持ORCFile。用Impala查询ORCFile表时,错误信息如下图所示。



        这是一个棘手的问题。如果我们再建一套和dw库中表结构一样的表,但使用Impala能够识别的文件类型,如Parquet,又会引入两个新的问题:一是CDH 5.7.0的Hive版本是1.1.0,有些数据类型不支持,如date。另一个更大的问题是增量装载数据问题。dw库的维度表和事实表都有update操作,可Impala只支持数据装载,不支持update和delete等DML操作。如果每天都做insert overwrite覆盖装载全部数据,对于大数据量来说很不现实。


        尽管Impala不支持update语句,但通过使用HBase作为底层存储可是达到同样的效果。相同键值的数据被插入时,会自动覆盖原有的数据行。这样只要在每天定期ETL时,记录当天产生变化(包括修改和新增)的记录,只将这些记录插入到Impala表中,就可以实现增量数据装载。这个方案并不完美,毕竟冗余了一套数据,既浪费空间,又增加了ETL的额外工作。其实前面ETL的Hive表也可以使用HBase做底层存储而不用ORCFile文件类型,利用HBase的特性,既可以用Hive做ETL,又可以用Impala做OLAP,真正做到一套数据,多个引擎。这个方案也需要一些额外的工作,如安装HBase,配置Hive、Impala与HBase协同工作等,它最主要的问题是Impala在HBase上的查询性能并不适合OLAP场景。
        如果没有累积快照事实表,可以对相对较小的维度表全量覆盖插入,而对大的事实表增量插入,这也是本实例中采用的方案。也就是说,为了保证查询性能和数据装载可行性,牺牲了对累积快照事实表的支持。希望Impala尽快支持ORCFile并能达到和Parquet同样的性能,这样就可以省却很多麻烦。


1. 建立olap库、表、视图
        用下面的查询语句从MySQL的hive库生成建表文件:
[AppleScript] 纯文本查看 复制代码
use hive;[/color][/size]
[size=2][color=#000000]select concat('create table ', t1.tbl_name, ' (',group_concat(concat(t2.column_name,' ',t2.type_name) order by t2.integer_idx),') stored as parquet;') into outfile '/data/hive/create_table.sql'
  from (select t1.tbl_id,
               t1.tbl_name 
          from TBLS t1, DBS t2
         where t1.db_id = t2. db_id 
           and t2.name = 'dw' 
           and tbl_type <> 'VIRTUAL_VIEW' 
           and (tbl_name like '%dim' or tbl_name like '%fact')) t1,
       (select case when v.column_name = 'date' then 'date1' else v.column_name end column_name,
               replace(v.type_name,'date','timestamp') type_name,
               v.integer_idx,
               t.tbl_id
          from COLUMNS_V2 v, 
               CDS c, 
               SDS s, 
               TBLS t
         where v.cd_id = c.cd_id
           and c.cd_id = s.cd_id
           and s.sd_id = t.sd_id) t2
 where t1.tbl_id = t2.tbl_id
 group by t1.tbl_name;
        生成的create_table.sql文件包含所有维度表和事实表的建表语句,例如:
[AppleScript] 纯文本查看 复制代码
create table product_dim (product_sk int,product_code int,product_name varchar(30),product_category varchar(30),version int,effective_date timestamp,expiry_date timestamp) stored as parquet;[/color][/size]
[size=2][color=#000000]
        用下面的查询语句从MySQL的hive库生成建视图文件:
[AppleScript] 纯文本查看 复制代码
use hive;[/color][/size]
[size=2][color=#000000]select concat('create view ', t1.tbl_name, ' as ', replace(replace(t1.view_original_text,'\n',' '),' date,',' date1,'), ';')  
  into outfile '/data/hive/create_view.sql'
  from TBLS t1, DBS t2
 where t1.db_id = t2.db_id 
   and t2.name = 'dw' 
   and t1.tbl_type = 'VIRTUAL_VIEW';
        生成的create_view.sql文件包含所有建立视图的语句,例如:
[AppleScript] 纯文本查看 复制代码
create view allocate_date_dim as SELECT date_sk, date, month, month_name, quarter, year, promo_ind FROM date_dim;[/color][/size]
[size=2][color=#000000]
        从Hive命令行执行建立库、表、视图的脚本:
[AppleScript] 纯文本查看 复制代码
hive -e 'create database olap;use olap;source /data/hive/create_table.sql;source /data/hive/create_view.sql;'



2. 初始装载数据
        用下面的查询语句从MySQL的hive库生成装载数据脚本文件:
[AppleScript] 纯文本查看 复制代码
use hive;[/color][/size]
[size=2][color=#000000]select concat('insert overwrite table olap.', t1.tbl_name, ' select ', group_concat(t2.column_name order by t2.integer_idx),' from dw.', t1.tbl_name ,';') into outfile '/data/hive/insert_table.sql'
  from (select t1.tbl_id,
               t1.tbl_name 
          from TBLS t1, DBS t2
         where t1.db_id = t2. db_id 
           and t2.name = 'dw' 
           and tbl_type <> 'VIRTUAL_VIEW' 
           and (tbl_name like '%dim' or tbl_name like '%fact')) t1,
       (select v.column_name,
               replace(v.type_name,'date','timestamp') type_name,
               v.integer_idx,
               t.tbl_id
          from COLUMNS_V2 v, 
               CDS c, 
               SDS s, 
               TBLS t
         where v.cd_id = c.cd_id
           and c.cd_id = s.cd_id
           and s.sd_id = t.sd_id) t2
 where t1.tbl_id = t2.tbl_id
 group by t1.tbl_name;
        生成的insert_table.sql文件包含所有insert olap表的语句,例如:
[AppleScript] 纯文本查看 复制代码
insert overwrite table olap.product_dim select product_sk,product_code,product_name,product_category,version,effective_date,expiry_date from dw.product_dim;[/color][/size]
[size=2][color=#000000]
        从Hive命令行执行初始装载数据的脚本:
hive -e 'source /data/hive/insert_table.sql;'


3. 修改销售订单定期装载脚本
        首先将dw和olap库中的事实表变更为动态分区表,这样在向olap库中装载数据时,或是在olap库上进行查询时,都可以有效地利用分区消除来提高性能。这里只修改了每日定时装载所涉及的两个表product_count_fact和sales_order_fact,其它事实表的修改类似。因为分区字段只能在表定义的最后,可能会改变字段的顺序,所以还要修改相关的ETL脚本。
        执行下面的语句修改dw库的事实表。
[AppleScript] 纯文本查看 复制代码
use dw;[/color][/size]
 [size=2][color=#000000]
set hive.exec.dynamic.partition=true;  
set hive.exec.dynamic.partition.mode=nonstrict;  
set hive.exec.max.dynamic.partitions.pernode=1000; 
 
-- product_count_fact表
create table product_count_fact_part
(product_sk int)
partitioned by (product_launch_date_sk int);
 
insert overwrite table product_count_fact_part partition (product_launch_date_sk)
select product_sk,product_launch_date_sk from product_count_fact;
 
drop table product_count_fact;
alter table product_count_fact_part rename to product_count_fact;
 
-- sales_order_fact表
create table sales_order_fact_part
(order_number int,
 customer_sk int,
 customer_zip_code_sk int,
 shipping_zip_code_sk int,
 product_sk int,
 sales_order_attribute_sk int,
 order_date_sk int,
 allocate_date_sk int,
 allocate_quantity int,
 packing_date_sk int,
 packing_quantity int,
 ship_date_sk int,
 ship_quantity int,
 receive_date_sk int,
 receive_quantity int,
 request_delivery_date_sk int,
 order_amount decimal(10,2),
 order_quantity int
 )
partitioned by (entry_date_sk int)
clustered by (order_number) into 8 buckets      
stored as orc tblproperties ('transactional'='true');
 
insert overwrite table sales_order_fact_part partition (entry_date_sk)
select order_number,
       customer_sk,
       customer_zip_code_sk,
       shipping_zip_code_sk,
       product_sk,
       sales_order_attribute_sk,
       order_date_sk,
       allocate_date_sk,
       allocate_quantity,
       packing_date_sk,
       packing_quantity,
       ship_date_sk,
       ship_quantity,
       receive_date_sk,
       receive_quantity,
       request_delivery_date_sk,
       order_amount,
       order_quantity,
       entry_date_sk
  from sales_order_fact;
 
drop table sales_order_fact;
alter table sales_order_fact_part rename to sales_order_fact;
        执行下面的语句修改olap库的事实表,和上面的语句类似,只是表的存储类型为parquet。
[AppleScript] 纯文本查看 复制代码
use olap;[/color][/size]
 [size=2][color=#000000]
set hive.exec.dynamic.partition=true;  
set hive.exec.dynamic.partition.mode=nonstrict;  
set hive.exec.max.dynamic.partitions.pernode=1000; 
 
-- product_count_fact表
create table product_count_fact_part
(product_sk int)
partitioned by (product_launch_date_sk int)
stored as parquet;
 
insert overwrite table product_count_fact_part partition (product_launch_date_sk)
select product_sk,product_launch_date_sk from product_count_fact;
 
drop table product_count_fact;
alter table product_count_fact_part rename to product_count_fact;
 
-- sales_order_fact表
create table sales_order_fact_part
(order_number int,
 customer_sk int,
 customer_zip_code_sk int,
 shipping_zip_code_sk int,
 product_sk int,
 sales_order_attribute_sk int,
 order_date_sk int,
 allocate_date_sk int,
 allocate_quantity int,
 packing_date_sk int,
 packing_quantity int,
 ship_date_sk int,
 ship_quantity int,
 receive_date_sk int,
 receive_quantity int,
 request_delivery_date_sk int,
 order_amount decimal(10,2),
 order_quantity int
 )
partitioned by (entry_date_sk int)
stored as parquet;
 
insert overwrite table sales_order_fact_part partition (entry_date_sk)
select order_number,
       customer_sk,
       customer_zip_code_sk,
       shipping_zip_code_sk,
       product_sk,
       sales_order_attribute_sk,
       order_date_sk,
       allocate_date_sk,
       allocate_quantity,
       packing_date_sk,
       packing_quantity,
       ship_date_sk,
       ship_quantity,
       receive_date_sk,
       receive_quantity,
       request_delivery_date_sk,
       order_amount,
       order_quantity,
       entry_date_sk
  from sales_order_fact;
 
drop table sales_order_fact;
alter table sales_order_fact_part rename to sales_order_fact;
        下面修改数据仓库每天定期装载脚本,需要做以下三项修改。
添加olap库中维度表的覆盖装载语句。
根据分区定义修改dw事实表的装载语句。
添加olap库中事实表的增量装载语句。
        下面显示了修改后的regular_etl.sql定期装载脚本(只部分显示)。
[AppleScript] 纯文本查看 复制代码
-- 设置环境与时间窗口  
!run /root/set_time.sql   
 
set hive.exec.dynamic.partition=true;  
set hive.exec.dynamic.partition.mode=nonstrict;  
set hive.exec.max.dynamic.partitions.pernode=1000;
    
-- 装载customer维度    
...
 
-- 装载olap.customer_dim表
insert overwrite table olap.customer_dim select * from customer_dim;
    
-- 装载product维度    
...
 
-- 装载olap.product_dim表
insert overwrite table olap.product_dim select * from product_dim;
 
-- 装载product_count_fact表
truncate table product_count_fact;
insert into product_count_fact partition (product_launch_date_sk)
select product_sk,date_sk
  from (select a.product_sk product_sk,
               a.product_code product_code,
               b.date_sk date_sk,
               row_number() over (partition by a.product_code order by b.date_sk) rn
          from product_dim a,date_dim b
         where a.effective_date = b.date) t
 where rn = 1;
 
-- 全量装载olap.product_count_fact表
truncate table olap.product_count_fact;
insert into olap.product_count_fact partition (product_launch_date_sk)
select * from product_count_fact;
 
-- 装载销售订单事实表 
-- 前一天新增的销售订单,因为分区键字段在最后,所以这里把entry_date_sk字段的位置做了调整。
-- 后面处理分配库房、打包、配送和收货四个状态时,同样也要做相应的调整。 
INSERT INTO sales_order_fact partition (entry_date_sk)
SELECT    
    a.order_number,    
    customer_sk,
    i.customer_zip_code_sk,  
    j.shipping_zip_code_sk,    
    product_sk, 
    g.sales_order_attribute_sk,
    e.order_date_sk,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    f.request_delivery_date_sk,
    order_amount,    
    quantity,
    h.entry_date_sk    
  FROM    
    rds.sales_order a,     
    customer_dim c,    
    product_dim d,    
    order_date_dim e,  
    request_delivery_date_dim f, 
    sales_order_attribute_dim g,
    entry_date_dim h,
    customer_zip_code_dim i,  
    shipping_zip_code_dim j,  
    rds.customer k, 
    rds.cdc_time l
 WHERE 
    a.order_status = 'N'
AND a.customer_number = c.customer_number    
AND a.status_date >= c.effective_date    
AND a.status_date < c.expiry_date 
AND a.customer_number = k.customer_number  
AND k.customer_zip_code = i.customer_zip_code  
AND a.status_date >= i.effective_date  
AND a.status_date <= i.expiry_date  
AND k.shipping_zip_code = j.shipping_zip_code  
AND a.status_date >= j.effective_date  
AND a.status_date <= j.expiry_date    
AND a.product_code = d.product_code    
AND a.status_date >= d.effective_date    
AND a.status_date < d.expiry_date    
AND to_date(a.status_date) = e.order_date
AND to_date(a.entry_date) = h.entry_date   
AND to_date(a.request_delivery_date) = f.request_delivery_date
AND a.verification_ind = g.verification_ind  
AND a.credit_check_flag = g.credit_check_flag  
AND a.new_customer_ind = g.new_customer_ind  
AND a.web_order_flag = g.web_order_flag 
AND a.entry_date >= l.last_load AND a.entry_date < l.current_load ;    
 
-- 重载PA客户维度    
...
 
-- 装载olap.pa_customer_dim表
insert overwrite table olap.pa_customer_dim select * from pa_customer_dim;
 
-- 处理分配库房、打包、配送和收货四个状态
...
 
-- 增量装载olap.sales_order_fact表
insert into olap.sales_order_fact partition (entry_date_sk)
select t1.* 
  from sales_order_fact t1,entry_date_dim t2,rds.cdc_time t3
 where t1.entry_date_sk = t2.entry_date_sk
   and t2.entry_date >= t3.last_load and t2.entry_date < t3.current_load ;
 
-- 更新时间戳表的last_load字段    
INSERT OVERWRITE TABLE rds.cdc_time SELECT current_load, current_load FROM rds.cdc_time;

4. 定义OLAP需求
        要做好OLAP类的应用,需要对业务数据有深入的理解。只有了解了业务,才能知道需要分析哪些指标,从而有的放矢地剖析相关数据,得出可信的结论来辅助决策。下面就用前面销售订单数据仓库的例子,提出若干问题,然后用Impala查询数据以回答这些问题:
每种产品类型以及单个产品的累积销售量和销售额是多少?
每种产品类型以及单个产品在每个州以及每个城市的月销售量和销售额趋势是什么?
每种产品类型销售量和销售额和同比如何?
每个州以及每个城市的客户数量及其消费金额汇总是多少?
迟到的订单比例是多少?
客户年消费金额为“高”、“中”、“低”档的人数及消费金额所占比例是多少?
每个城市按销售金额排在前三位的商品是什么?
5. 执行OLAP查询
        使用impala-shell命令行工具执行olap库上的查询,回答上一步提出的问题。进入impala-shell,连接impalad所在主机,同步元数据,切换到olap库,这些操作使用的命令如下图所示。



(1)每种产品类型以及单个产品的累积销售量和销售额是多少?
        impala目前只支持最基本的group by,尚不支持rollup、cube、grouping set等操作,所幸支持union。
   
[AppleScript] 纯文本查看 复制代码
select * from[/color][/size]
[size=2][color=#000000](
select t2.product_category pro_category,
       '' pro_name,
       sum(order_quantity) sum_quantity,
       sum(order_amount) sum_amount 
  from sales_order_fact t1, product_dim t2
 where t1.product_sk = t2.product_sk
 group by pro_category
 union all 
select t2.product_category pro_category,
       t2.product_name pro_name,     
       sum(order_quantity) sum_quantity,
       sum(order_amount) sum_amount 
  from sales_order_fact t1, product_dim t2
 where t1.product_sk = t2.product_sk
 group by pro_category, pro_name) t
 order by pro_category, pro_name;
        查询结果如下图所示。



(2)每种产品类型以及单个产品在每个州以及每个城市的月销售量和销售额趋势是什么?
[AppleScript] 纯文本查看 复制代码
select * from[/color][/size]
[size=2][color=#000000](
-- 明细
select t2.product_category pro_category,
       t2.product_name pro_name,
       t3.state state,
	   t3.city city,
       t4.year*100 + t4.month ym,
       sum(order_quantity) sum_quantity,
       sum(order_amount) sum_amount 
  from sales_order_fact t1 
 inner join product_dim t2 on t1.product_sk = t2.product_sk
 inner join customer_zip_code_dim t3 on t1.customer_zip_code_sk = t3.zip_code_sk
 inner join order_date_dim t4 on t1.order_date_sk = t4.date_sk
 group by pro_category, pro_name, state, city, ym
 union all
-- 按产品分类汇总 
select t2.product_category pro_category,
       '' pro_name,
       t3.state state,
	   t3.city city,
       t4.year*100 + t4.month ym,
       sum(order_quantity) sum_quantity,
       sum(order_amount) sum_amount 
  from sales_order_fact t1 
 inner join product_dim t2 on t1.product_sk = t2.product_sk
 inner join customer_zip_code_dim t3 on t1.customer_zip_code_sk = t3.zip_code_sk
 inner join order_date_dim t4 on t1.order_date_sk = t4.date_sk
 group by pro_category, pro_name, state, city, ym
 union all
-- 按产品分类、州汇总
select t2.product_category pro_category,
       '' pro_name,
       t3.state state,
	   '' city,
       t4.year*100 + t4.month ym,
       sum(order_quantity) sum_quantity,
       sum(order_amount) sum_amount 
  from sales_order_fact t1 
 inner join product_dim t2 on t1.product_sk = t2.product_sk
 inner join customer_zip_code_dim t3 on t1.customer_zip_code_sk = t3.zip_code_sk
 inner join order_date_dim t4 on t1.order_date_sk = t4.date_sk
 group by pro_category, pro_name, state, city, ym) t
 order by pro_category, pro_name, state, city, ym;
        查询部分结果如下图所示。



(3)每种产品类型销售量和销售额和同比如何?
        这个查询使用了前面进阶技术——周期快照中定义的month_end_sales_order_fact表。Impala支持视图和left、right、full外连接。
[AppleScript] 纯文本查看 复制代码
create view v_product_category_month as[/color][/size]
[size=2][color=#000000]select t2.product_category,
       t3.year,
       t3.month,
       t1.month_order_amount,
       t1.month_order_quantity
  from month_end_sales_order_fact t1
 inner join product_dim t2 on t1.product_sk = t2.product_sk
 inner join month_dim t3 on t1.order_month_sk = t3.month_sk;
 
select t1.product_category,
       t1.year,
       t1.month,
       (t1.month_order_quantity - nvl(t2.month_order_quantity,0)) / nvl(t2.month_order_quantity,0) pct_quantity,	   
       cast((t1.month_order_amount - nvl(t2.month_order_amount,0)) as double) / cast(nvl(t2.month_order_amount,0) as double) pct_amount
  from v_product_category_month t1 
  left join v_product_category_month t2
    on t1.product_category = t2.product_category
   and t1.year = t2.year + 1
   and t1.month = t2.month;
        查询结果如下图所示。由于没有2015年的数据,分母是0,除0结果是Infinity而不报错。



(4)每个州以及每个城市的客户数量及其消费金额汇总是多少?
[AppleScript] 纯文本查看 复制代码
select * from [/color][/size]
[size=2][color=#000000](
select t3.state state,
       t3.city city,
       count(distinct t2.customer_sk) sum_customer_num,
       sum(order_amount) sum_order_amount 
  from sales_order_fact t1
 inner join customer_dim t2 on t1.customer_sk = t2.customer_sk
 inner join customer_zip_code_dim t3 on t1.customer_zip_code_sk = t3.zip_code_sk
 group by state, city
 union all
select t3.state state,
       '' city,
       count(distinct t2.customer_sk) sum_customer_num,
       sum(order_amount) sum_order_amount 
  from sales_order_fact t1
 inner join customer_dim t2 on t1.customer_sk = t2.customer_sk
 inner join customer_zip_code_dim t3 on t1.customer_zip_code_sk = t3.zip_code_sk
 group by state, city) t
 order by state, city;
        查询结果如下图所示。



(5)迟到的订单比例是多少?
[AppleScript] 纯文本查看 复制代码
select sum_total, sum_late, round(sum_late/sum_total,4) late_pct
  from
(
select sum(case when order_date_sk < entry_date_sk then 1 else 0 end) sum_late,
       count(*)	sum_total
from sales_order_fact) t;

        查询结果如下图所示。



(6)客户年消费金额为“高”、“中”、“低”档的人数及消费金额所占比例是多少?
        这个查询使用了前面进阶技术——分段维度中定义的表。
[AppleScript] 纯文本查看 复制代码
select year, bn, c_count, sum_band, sum_total, round(sum_band/sum_total,4) band_pct [/color][/size]
[size=2][color=#000000]  from 
(
select count(a.customer_sk) c_count, 
       sum(annual_order_amount) sum_band,
       c.year year,  
       band_name bn  
  from annual_customer_segment_fact a,  
       annual_order_segment_dim b,  
       year_dim c,  
       annual_sales_order_fact d 
 where a.segment_sk = b.segment_sk  
   and a.year_sk = c.year_sk  
   and a.customer_sk = d.customer_sk  
   and a.year_sk = d.year_sk
   and b.segment_name = 'grid'
 group by year, bn) t1,
(select sum(annual_order_amount) sum_total from annual_sales_order_fact) t2
 order by year, bn;
        查询结果如下图所示。



(7)每个城市按销售金额排在前三位的商品是什么?
        此查询使用了Impala支持的窗口分析函数row_number()取得排名。
[AppleScript] 纯文本查看 复制代码
select t2.city, t3.product_name, t1.sum_order_amount, t1.rn[/color][/size]
[size=2][color=#000000]  from 
(
select customer_zip_code_sk,
       product_sk,
       sum_order_amount,
       row_number() over (partition by customer_zip_code_sk order by sum_order_amount desc) rn
  from 
(
select customer_zip_code_sk, 
       product_sk, 
       sum(order_amount) sum_order_amount
  from sales_order_fact t1
 group by customer_zip_code_sk, product_sk) t) t1
 inner join customer_zip_code_dim t2 on t1.customer_zip_code_sk = t2.zip_code_sk
 inner join product_dim t3 on t1.product_sk = t3.product_sk
 
 where t1.rn <= 3
 order by t1.customer_zip_code_sk, t1.rn;
        查询结果如下图所示。



        以上几个查询都在1秒左右得到结果。虽然测试数据很少,但即便这样的数据量在Hive上执行相同的查询也要几分钟时间。Impala的优势在于查询速度快,然而相对于Hive或SparkSQL,当前的Impala仍有诸多不足:不支持update、delete操作;不支持Date类型;不支持XML和JSON相关函数;不支持covar_pop、covar_samp、corr、percentile、 percentile_approx、histogram_numeric、collect_set等聚合函数;不支持rollup、cube、grouping set等操作;不支持数据抽样(Sampling)等等。看来要想日臻完美,Impala还有很多工作要做。

楼主热帖
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖 赞 踩

168大数据 - 论坛版权1.本主题所有言论和图片纯属网友个人见解,与本站立场无关
2.本站所有主题由网友自行投稿发布。若为首发或独家,该帖子作者与168大数据享有帖子相关版权。
3.其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和168大数据的同意,并添加本文出处。
4.本站所收集的部分公开资料来源于网络,转载目的在于传递价值及用于交流学习,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
5.任何通过此网页连接而得到的资讯、产品及服务,本站概不负责,亦不负任何法律责任。
6.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源,若标注有误或遗漏而侵犯到任何版权问题,请尽快告知,本站将及时删除。
7.168大数据管理员和版主有权不事先通知发贴者而删除本文。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

关于我们|小黑屋|Archiver|168大数据 ( 京ICP备14035423号|申请友情链接

GMT+8, 2024-6-6 01:11

Powered by BI168大数据社区

© 2012-2014 168大数据

快速回复 返回顶部 返回列表