Impala的分析函数(基于impala2.12)

分析函数又称为开窗函数,是一种特殊的内置函数。分析函数不会仅限于对每个group by的分组产生一个结果,它操作的是一个窗口(window),输入的行是排序和分组的,可以通过over()语句使用灵活的条件。impala的分析函数是从impala2.0.0开始添加的。分析函数经常被用于金融和科学领域,用来分析趋势、离群点以及大数据集的分桶分析。

1.over从句

当调用分析函数时,比如LEAD(),RANK()以及FIRST_VALUE,需要使用OVER从句。当调用聚合函数时使用了OVER从句,比如MAX(),COUNT()或者SUM(),将被视为分析函数。

语法

function(args) OVER([partition_by_clause] [order_by_clause [window_clause]])
partition_by_clause ::= PARTITION BY expr [, expr ...]
order_by_clause ::= ORDER BY expr [ASC | DESC] [NULLS FIRST
window_clause: See Window Clause

PARTITION BY从句
          PARTITION BY 从句与GROUP BY从句类似,按照一列或者多列相同的值,将数据分成不同的组,这个逻辑上的组,称之为分区。但是,请注意以下限制,这些限制特别适用于涉及分区表的分析函数调用。当查询涉及到分析函数和分区表时,仅对分析函数调用的partition by子句中命名的列执行分区裁剪。比如,当一个分析函数查询带有WHERE year=2016的分区裁剪条件,只有在PARTITION BY 从句中指定year才可以裁剪掉其他的分区数据,比如 OVER (PARTITION BY year,other_columns
other_analytic_clauses)

分析函数作用的范围是一个分组内(分区)的数据,任意MAX(),SUM()或者ROW_NUMBER()等独立应用于每个分区。当省略PARTITION BY子句时,则会将分析操作应用于表中的所有行。

ORDER BY 从句
           ORDER BY从句与一个查询中最外面的ORDER BY从句类似。它会对整个数据集或者PARTITION BY指定的分组数据进行排序。可以按一个或多个列进行排序,可以选择升序或降序以及空值是按排序顺序排在第一还是最后。因为ORDER BY从句仅仅对分析函数作用的数据进行排序,所以,如果使输出的结果是全排序的,可以在查询语句的最外层使用ORDER BY从句。当ORDER BY从句省略时,分析函数作用于PARTITION BY指定的分组的所有数据。当指定ORDER BY从句时,分析函数可以作用于分组的所有数据或者部分数据,这取决于WINDOW从句。在OVER从句内部使用的ORDER BY,与查询最外层的ORDER BY是有区别的,比如ORDER BY 1被解释为常量排序值(实际上是无操作),而不是按照第1列进行排序。
           Window 从句
           window从句只能ORDER BY 从句一起使用.。如果指定了 ORDER BY 从句,而省略了window从句,则默认的窗口(window)是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,表示从开始到当前行。

HBase 表注意事项
           由于 HBase 表在单行查找做了优化,而不是全表扫描。所以不推荐在HBase表上使用分析函数,尽管查询是有效的,但是与查询HDFS上的数据相比,性能较差。
           Parquet 表注意事项
           在Parquet表上使用分析函数效率较高。
          文本表注意事项
          分析函数可以方便地与文本存储格式的表一起使用,但当数据量非常大时,优先使用 Parquet格式存储。在impala2.0.0添加的功能。

2Window从句

分析函数可以使用一个可选的window从句, 主要作用是让分析函数作用于某些行,而不是分组中的所有行。例如,可以通过指定前面和后面几行的数目,得到移动平均值。对于同一分组中的行,此子句可以产生不同的分析结果。 AVG(), COUNT(), FIRST_VALUE(), LAST_VALUE(), 和SUM()函数支持window子句。对于MAX()和 MIN(),window 从句只允许其实行为  UNBOUNDED PRECEDING,即第一行。

          语法

ROWS BETWEEN [ { m | UNBOUNDED } PRECEDING | CURRENT ROW] [ AND [CURRENT ROW
| { UNBOUNDED | n } FOLLOWING] ]
RANGE BETWEEN [ {m | UNBOUNDED } PRECEDING | CURRENT ROW] [ AND [CURRENT ROW
| { UNBOUNDED | n } FOLLOWING] ]

目前, 对于RANGE从句,Impala仅支持以下几种组合:
           • RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,为默认值,即当指定了ORDER BY从句,而省略了window从句 ,表示从开始到当前行。
          • RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING,表示从当前行到最后一行
          • RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,表示所有行

•n  PRECEDING  m FOLLOWING: 表示窗口的范围是:[(当前行的行数)- n, (当前行的行数)+m]
row.
    关于window从句示意图,如下图所示:

Impala的分析函数(基于impala2.12)_第1张图片

           例子:

--创建表
create table stock_ticker 
          (stock_symbol string,
          closing_price decimal(8,2),
          closing_date timestamp);

--插入数据
insert into stock_ticker values ("JDR",12.86,"2014-10-02 00:00:00"),
                                ("JDR",12.89,"2014-10-03 00:00:00"),
                                ("JDR",12.94,"2014-10-04 00:00:00"),
                                ("JDR",12.55,"2014-10-05 00:00:00"),
                                ("JDR",14.03,"2014-10-06 00:00:00"),
                                ("JDR",14.75,"2014-10-07 00:00:00"),
                                ("JDR",13.98,"2014-10-08 00:00:00");

如果只对分组的所有数据做统计,则可以不指定ORDER BY从句。比如:

 --SQL1,统计分组数据的行数
select
     stock_symbol,
     closing_date,
     closing_price,
     count(*) over (partition by stock_symbol) cnt                     
from stock_ticker;

--SQL1结果输出
+--------------+---------------------+---------------+-----+
| stock_symbol | closing_date        | closing_price | cnt |
+--------------+---------------------+---------------+-----+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 7   |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 7   |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 7   |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 7   |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 7   |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 7   |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 7   |
+--------------+---------------------+---------------+-----+

--SQL2,对分组的数据按某个字段求和
select
     stock_symbol,
     closing_date,
     closing_price,
     sum(closing_price ) over (partition by stock_symbol) sums                      
from stock_ticker;
--SQL2结果输出
+--------------+---------------------+---------------+-------+
| stock_symbol | closing_date        | closing_price | sums  |
+--------------+---------------------+---------------+-------+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 94.00 |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 94.00 |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 94.00 |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 94.00 |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 94.00 |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 94.00 |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 94.00 |
+--------------+---------------------+---------------+-------+

--SQL3,查找分组内的第一个值
select
     stock_symbol,
     closing_date,
     closing_price,
     first_value(closing_price) over (partition by stock_symbol) firstvalue                     
from stock_ticker;
--SQL3结果输出
+--------------+---------------------+---------------+------------+
| stock_symbol | closing_date        | closing_price | firstvalue |
+--------------+---------------------+---------------+------------+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 12.86      |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 12.86      |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 12.86      |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 12.86      |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 12.86      |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 12.86      |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 12.86      |
+--------------+---------------------+---------------+------------+

--SQL4,查找分组内的最后一个值
select
     stock_symbol,
     closing_date,
     closing_price,
     last_value(closing_price) over (partition by stock_symbol)  as lastvalue                    
from stock_ticker;
SQL4结果输出
+--------------+---------------------+---------------+-----------+
| stock_symbol | closing_date        | closing_price | lastvalue |
+--------------+---------------------+---------------+-----------+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 13.98     |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 13.98     |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 13.98     |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 13.98     |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 13.98     |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 13.98     |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 13.98     |
+--------------+---------------------+---------------+-----------+

--SQL5,查找分组内的某个字段的最大值
select
     stock_symbol,
     closing_date,
     closing_price,
     max(closing_price) over (partition by stock_symbol)  as maxvalue                    
from stock_ticker;

SQL5结果输出
+--------------+---------------------+---------------+----------+
| stock_symbol | closing_date        | closing_price | maxvalue |
+--------------+---------------------+---------------+----------+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 14.75    |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 14.75    |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 14.75    |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 14.75    |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 14.75    |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 14.75    |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 14.75    |
+--------------+---------------------+---------------+----------+

        下面的例子是求移动平均值


select 
    stock_symbol, 
    closing_date,
    closing_price,
    avg(closing_price) over (partition by stock_symbol order by closing_date
       rows between 1 preceding and 1 following) as moving_average
from stock_ticker;

-- rows between 1 preceding and 1 following的含义是:
窗口的范围为三行数据,即[当前行 -1 ,当前行 + 1]。
对于第一行而言,不存在前一行数据,所以只统计[第一行,第一行 + 1]的平均值。
对于最后一行而言,不存在后一行数据,所以只统计[最后一行 -1 ,最后一行]的平均值

--结果输出
+--------------+---------------------+---------------+----------------+
| stock_symbol | closing_date        | closing_price | moving_average |
+--------------+---------------------+---------------+----------------+
| JDR          | 2014-10-02 00:00:00 | 12.86         | 12.87          |
| JDR          | 2014-10-03 00:00:00 | 12.89         | 12.89          |
| JDR          | 2014-10-04 00:00:00 | 12.94         | 12.79          |
| JDR          | 2014-10-05 00:00:00 | 12.55         | 13.17          |
| JDR          | 2014-10-06 00:00:00 | 14.03         | 13.77          |
| JDR          | 2014-10-07 00:00:00 | 14.75         | 14.25          |
| JDR          | 2014-10-08 00:00:00 | 13.98         | 14.36          |
+--------------+---------------------+---------------+----------------+

 

具体分析函数参见我的另一篇博客:https://blog.csdn.net/jmx_bigdata/article/details/8805963

你可能感兴趣的:(impala)