使用Spark core和SparkSQL的窗口函数分别实现分组取topN的操作

原创 2016年08月29日 18:07:43

在spark 1.4及以上版本中,针对sparkSQL,添加了很多新的函数,进一步扩展了SparkSQL对数据的处理能力。

本篇介绍一个强大的窗口函数 row_number()函数,常用于对数据进行分组并取每个分组中的TopN数据。

示例数据如下:

class1 90

class2 56

class1 87

class1 76

class2 88

class1 95

class1 74

class2 87

class2 67

class2 77

1、直接使用Spark core中的api来实现分组取topN功能: 
首先将数据源读入代JavaRDD中,然后解析每一行数据,将每一行的第一个元素作为key,第二元素作为value构成tuple的RDD

SparkConf conf = new SparkConf().setAppName("groupTopN").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf);
JavaRDD<String> lines = sc.textFile("C:\\Temp\\groupTopN.txt");
JavaPairRDD<String,Integer> pairs = lines.mapToPair(new PairFunction<String, String, Integer>() {
@Overridepublic Tuple2<String, Integer> call(String line) throws Exception { 
   String[] lineSplited = line.split(" ");   
   return new Tuple2<String,Integer>(lineSplited[0],Integer.valueOf(lineSplited[1]));
   }
   } );

得到pairs是一个二元组的RDD,直接调用groupByKey()函数,就可以按照key来进行分组了

JavaPairRDD<String, Iterable<Integer>> grouped = pairs.groupByKey();

分组后每个key对应的这一个value的集合,这里,需要对每个key对应的value集合首先进行排序,然后取其前N个元素即可

JavaPairRDD<String,Iterable> groupedTopN = grouped.mapToPair(new PairFunction<Tuple2<String,Iterable<Integer>>, String, Iterable>() {        @Override
        public Tuple2<String, Iterable> call(Tuple2<String, Iterable<Integer>> values) throws Exception {
            Iterator<Integer> iter = values._2.iterator();
            List<Integer> list = new ArrayList<Integer>();
            while(iter.hasNext()){
                list.add(iter.next());
            }
            //将list中的元素排序
            list.sort(new Comparator<Integer>() {
                @Override
                public int compare(Integer t1, Integer t2) {
                    int i1 = t1;
                    int i2 = t2;
                    return -(i1 - i2);//逆序排列
                }
            });

             List<Integer> top3 = list.subList(0, 3);//直接去前3个元素
            return new Tuple2<String,Iterable>(values._1,top3);
        }
    });

为了便于验证,直接咋本地进行测试,并打印显示

groupedTopN.foreach(new VoidFunction<Tuple2<String,Iterable>>() { 
   @Override    
   public void call(Tuple2<String, Iterable> t) 
   throws Exception {
   System.out.println(t._1); 
   Iterator iterator = t._2.iterator();    
   while(iterator.hasNext()){  
   System.out.println(iterator.next()); 
   }        
   System.out.println("====华丽的分割线======="); 
   }});

2、使用SparkSQL的窗口函数来时上同样的功能

思路: 
窗口函数是HiveSQL中特有的,因此,首先将数据导入到hive表中,然后映射到Spark的DataFrame,在sql语句中直接调用窗口函数即可实现该功能

首先,直接在HiveSQL中创建对应的hive表,然后导入本地数据到hive表中

SparkConf conf = new SparkConf().setAppName("WindowFunctionTopN").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf);
HiveContext hiveContext = new HiveContext(sc.sc());
//将数据导入到hive表中
hiveContext.sql("DROP TABLE IF EXISTS class_info");
hiveContext.sql("CREATE TABLE IF NOT EXISTS class_info ("        + "class STRING,"        + "score INT");
hiveContext.sql("LOAD DATA "        + "LOCAL INPATH '/cqt/testdata/groupTopN.txt' "        + "INTO TABLE class_info");

然后,直接调用窗口函数row_number(),注意窗口函数的调用语法

<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">DataFrame tom3DF = hiveContext.sql("<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">select</span> class,score <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" +"</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">select</span> class,score,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"
                + "</span>row_number() OVER (PARTITION <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">BY</span> class <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ORDER</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">BY</span> score <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DESC</span>) rank <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> class_info) tmp <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">where</span> rank<=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">");</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li></li></ul>
将得到的数据回写到hive表中保存即可

// 将每组排名前3的数据,保存到一个表中

hiveContext.sql("DROP TABLE IF EXISTS grouped_top3"); tom3DF.saveAsTable("grouped_top3");

至此,代码,编写完毕,相比于第一种方式,代码清爽很多!







版权声明:本文为博主原创文章,未经博主允许不得转载。

Spark实例TopN---Spark学习笔记11

Spark是基于内存的分布式计算框架,性能是shi
  • u014388509
  • u014388509
  • 2014年05月14日 18:06
  • 8575

sparksql分组后topN(JAVA)

org.apache.spark spark-core_2.10 1.6.0 org.apache.spark spark-sql_2.10 1.6.0 ...
  • ZYJ_2012
  • ZYJ_2012
  • 2017年03月21日 10:56
  • 559

Spark SQL 函数操作

Spark 内置函数 使用Spark SQL中的内置函数对数据进行分析,Spark SQL API不同的是,DataFrame中的内置函数操作的结果是返回一个Column对象,而DataFrame...
  • qq_16103331
  • qq_16103331
  • 2016年12月11日 13:04
  • 8996

Spark 入门篇之spark&spark sql

Spark 入门篇 1      概述        Spark是一个通用的快速的大数据处理引擎,是类似于hadoop的map reduce大数据并行处理引擎。它的数据源可以是hdfs、cassa...
  • mozhizun
  • mozhizun
  • 2016年02月17日 20:40
  • 2747

Spark核心编程-分组取topN

案例需求 对每个班级内的学生成绩,取出前3名。(分组取topN)
  • kwu_ganymede
  • kwu_ganymede
  • 2015年12月31日 19:15
  • 3427

spark学习笔记之spark core 取topN

spark学习笔记之spark core 取topN
  • wjxing86
  • wjxing86
  • 2016年08月27日 09:43
  • 858

spark中实现分组取topN

分组取topN
  • high2011
  • high2011
  • 2016年06月04日 15:39
  • 2324

Spark的Dataset操作(三)-分组,聚合,排序

spark sql的分组聚合操作,包括groupBy, agg, count, max, avg, sort, orderBy等函数示例
  • coding_hello
  • coding_hello
  • 2017年07月14日 21:29
  • 3599

Spark SQL函数之分组排序

需求:根据class分组对组内的age进行排序 原表 结果 Spark  SQL : SELECT name,  age,  class,  row_number() ov...
  • m0_37942876
  • m0_37942876
  • 2018年02月02日 15:02
  • 33

Saprk数据倾斜七解决方案(二)

2、过滤少数导致倾斜的key 方案适用场景:如果发现导致倾斜的key就少数几个,而且对计算本身影响并不大的话,那么很适合适用这种方案,比如99%的key对应10条数据,只有一个key对应1...
  • qq_16400951
  • qq_16400951
  • 2017年03月15日 16:56
  • 172
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用Spark core和SparkSQL的窗口函数分别实现分组取topN的操作
举报原因:
原因补充:

(最多只允许输入30个字)