重要|Spark driver端得到executor返回值的方法

浪院长 浪尖聊大数据


有人说spark的代码不优雅,这个浪尖就忍不了了。实际上,说spark代码不优雅的主要是对scala不熟悉,spark代码我觉得还是很赞的,最值得阅读的大数据框架之一。
今天这篇文章不是为了争辩Spark 代码优雅与否,主要是讲一下理解了spark源码之后我们能使用的一些小技巧吧。
spark 使用的时候,总有些需求比较另类吧,比如有球友问过这样一个需求:

浪尖,我想要在driver端获取executor执行task返回的结果,比如task是个规则引擎,我想知道每条规则命中了几条数据,请问这个怎么做呢?

这个是不是很骚气,也很常见,按理说你输出之后,在mysql里跑条sql就行了,但是这个往往显的比较麻烦。而且有时候,在 driver可能还要用到这些数据呢?具体该怎么做呢?

大部分的想法估计是collect方法,那么用collect如何实现呢?大家自己可以考虑一下,我只能告诉你不简单,不如输出到数据库里,然后driver端写sql分析一下。

还有一种考虑就是使用自定义累加器。这样就可以在executor端将结果累加然后在driver端使用,不过具体实现也是很麻烦。大家也可以自己琢磨一下下~

那么,浪尖就给大家介绍一个比较常用也比较骚的操作吧。

其实,这种操作我们最先想到的应该是count函数,因为他就是将task的返回值返回到driver端,然后进行聚合的。我们可以从idea count函数点击进去,可以看到...

  def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum

也即是sparkcontext的runJob方法。
Utils.getIteratorSize _这个方法主要是计算每个iterator的元素个数,也即是每个分区的元素个数,返回值就是元素个数:

/**   * Counts the number of elements of an iterator using a while loop rather than calling   * [[scala.collection.Iterator#size]] because it uses a for loop, which is slightly slower   * in the current version of Scala.   */  def getIteratorSize[T](iterator: Iterator[T]): Long = {    var count = 0L    while (iterator.hasNext) {      count += 1L      iterator.next()    }    count  }

然后就是runJob返回的是一个数组,每个数组的元素就是我们task执行函数的返回值,然后调用sum就得到我们的统计值了。

那么我们完全可以借助这个思路实现我们开头的目标。浪尖在这里直接上案例了:

import org.apache.spark.{SparkConf, SparkContext, TaskContext}import org.elasticsearch.hadoop.cfg.ConfigurationOptionsobject es2sparkRunJob {  def main(args: Array[String]): Unit = {    val conf = new SparkConf().setMaster("local[*]").setAppName(this.getClass.getCanonicalName)    conf.set(ConfigurationOptions.ES_NODES, "127.0.0.1")    conf.set(ConfigurationOptions.ES_PORT, "9200")    conf.set(ConfigurationOptions.ES_NODES_WAN_ONLY, "true")    conf.set(ConfigurationOptions.ES_INDEX_AUTO_CREATE, "true")    conf.set(ConfigurationOptions.ES_NODES_DISCOVERY, "false")    conf.set("es.write.rest.error.handlers", "ignoreConflict")    conf.set("es.write.rest.error.handler.ignoreConflict", "com.jointsky.bigdata.handler.IgnoreConflictsHandler")    val sc = new SparkContext(conf)    import org.elasticsearch.spark._    val rdd = sc.esJsonRDD("posts").repartition(10)    rdd.count()    val func = (itr : Iterator[(String,String)]) => {      var count = 0      itr.foreach(each=>{        count += 1      })      (TaskContext.getPartitionId(),count)    }    val res = sc.runJob(rdd,func)    res.foreach(println)    sc.stop()  }}

例子中driver端获取的就是每个task处理的数据量。
效率高,而且操作灵活高效~
是不是很骚气~~

©著作权归作者所有:来自51CTO博客作者mob604756ed02fe的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. ThinkPHP框架:数据库链表查询和导航渲染(导航数据递归生成)
  2. Spark Core读取ES的分区问题分析
  3. 通过 Python 查询 Excel 数据
  4. 初识TiDB
  5. Zabbix4.x如何安全传输数据
  6. 安全星球将成为企业办公必备的工具
  7. EXCEL连通数据库,供应链进度追踪效率倍增
  8. Flink通过异步IO实现redis维表join
  9. 浪尖刷过leetcode的题

随机推荐

  1. 代码分析php中的回调函数
  2. PHP使用 is_numeric的实例解析
  3. PHP 使用 Trait 解决 PHP 单继承问题的实
  4. 详解PHP中password_hash的功能
  5. PHP中serialize的详细介绍
  6. php实现简单的登陆功能(附源码)
  7. PHP中unserialize的使用方法
  8. PHP使用JWT创建Token的实例详解
  9. PHP中php_uname的用法详解
  10. PHP源码加密方法实例详解