Spark源码分析-topN源码

Spark实现TopN 大数据实验教学系统练习 Spark实现TopN因为Spark RDD是分区并行计算的,因此要排序的话,需要指定一个分区。   使用sortByKey算子,按key排序,然后再使用take算子,取前几个元素,就得到了 Top N 的结果。掌握抓取文本中最大的前几位数字。   掌握排序算子的使用。1、使用Spark RDD实现 Top N。    假设我们有以下输入文件top.txt: 编写RDD代码,获取值最大的三个数(Top 3)。    2、使用Spark RDD实现分组 Top N。    假设我们有以 阅读详情
  1. 介绍

TopN算子是取RDD的前N个元素。取TopN元素,我们就一定要对其进行严格排序吗?非也,也正是如此,加大了此算子的效率。

  1. 源码理解

  

  def top(num: Int): JList[T] = {
  val comp = com.google.common.collect.Ordering.natural().asInstanceOf[Comparator[T]]
  top(num, comp)
}

我们需要传进去一个整形的参数,然后后面声明了一个默认的比较器comp,又调用了两个参数的top函数,然后可以看到又调用了RDD的takeOrdered函数:

def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T] = withScope {
  if (num == 0) {
    Array.empty
  } else {
    val mapRDDs = mapPartitions { items =>
      // Priority keeps the largest elements, so let's reverse the ordering.
      val queue = new BoundedPriorityQueue[T](num)(ord.reverse)
      queue ++= collectionUtils.takeOrdered(items, num)(ord)
      Iterator.single(queue)
    }
    if (mapRDDs.partitions.length == 0) {
      Array.empty
    } else {
      mapRDDs.reduce { (queue1, queue2) =>
        queue1 ++= queue2
        queue1
      }.toArray.sorted(ord)
    }
  }
}

    RDD的takeOrdered函数里面使用的是mapPartitions算子,从这里就可以知道他首先需要在每个partition中求top信息,然后就在对所有的partition信息进行统一的排序。

    重点看collectionUtils.takeOrdered方法,里面调用了一个ordering.leastOf(input.asJava, num)方法,重点看这个方法里面的内容:

public <E extends T> List<E> leastOf(Iterator<E> elements, int k) {
  checkNotNull(elements);
  checkArgument(k >= 0, "k (%s) must be nonnegative", k);

  if (k == 0 || !elements.hasNext()) {
    return ImmutableList.of();
  } else if (k >= Integer.MAX_VALUE / 2) {
    // k is really large; just do a straightforward sorted-copy-and-sublist
    ArrayList<E> list = Lists.newArrayList(elements);
    Collections.sort(list, this);
    if (list.size() > k) {
      list.subList(k, list.size()).clear();
    }
    list.trimToSize();
    return Collections.unmodifiableList(list);
  }

  /*
   * Our goal is an O(n) algorithm using only one pass and O(k) additional
   * memory.
   *
   * We use the following algorithm: maintain a buffer of size 2*k. Every time
   * the buffer gets full, find the median and partition around it, keeping
   * only the lowest k elements.  This requires n/k find-median-and-partition
   * steps, each of which take O(k) time with a traditional quickselect.
   *
   * After sorting the output, the whole algorithm is O(n + k log k). It
   * degrades gracefully for worst-case input (descending order), performs
   * competitively or wins outright for randomly ordered input, and doesn't
   * require the whole collection to fit into memory.
   */
  int bufferCap = k * 2;
  @SuppressWarnings("unchecked") // we'll only put E's in
  E[] buffer = (E[]) new Object[bufferCap];
  E threshold = elements.next();
  buffer[0] = threshold;
  int bufferSize = 1;
  // threshold is the kth smallest element seen so far.  Once bufferSize >= k,
  // anything larger than threshold can be ignored immediately.

  while (bufferSize < k && elements.hasNext()) {
    E e = elements.next();
    buffer[bufferSize++] = e;
    threshold = max(threshold, e);
  }

  while (elements.hasNext()) {
    E e = elements.next();
    if (compare(e, threshold) >= 0) {
      continue;
    }

    buffer[bufferSize++] = e;
    if (bufferSize == bufferCap) {
      // We apply the quickselect algorithm to partition about the median,
      // and then ignore the last k elements.
      int left = 0;
      int right = bufferCap - 1;

      int minThresholdPosition = 0;
      // The leftmost position at which the greatest of the k lower elements
      // -- the new value of threshold -- might be found.

      while (left < right) {
        int pivotIndex = (left + right + 1) >>> 1;
        int pivotNewIndex = partition(buffer, left, right, pivotIndex);
        if (pivotNewIndex > k) {
          right = pivotNewIndex - 1;
        } else if (pivotNewIndex < k) {
          left = Math.max(pivotNewIndex, left + 1);
          minThresholdPosition = pivotNewIndex;
        } else {
          break;
        }
      }
      bufferSize = k;

      threshold = buffer[minThresholdPosition];
      for (int i = minThresholdPosition + 1; i < bufferSize; i++) {
        threshold = max(threshold, buffer[i]);
      }
    }
  }

  Arrays.sort(buffer, 0, bufferSize, this);

  bufferSize = Math.min(bufferSize, k);
  return Collections.unmodifiableList(
      Arrays.asList(ObjectArrays.arraysCopyOf(buffer, bufferSize)));
  // We can't use ImmutableList; we have to be null-friendly!
}

    从最上面开始,如果k过大,超过了Int类型最大数的一半,那么久直接用Collections.sort进行排序,底层的排序代码如下:

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

    把原始的List放到一个数组中,然后用Arrays.sort进行排序,这个排序默认用的是Timsort方法排序(优化的归并排序-归并和插入排序集合),然后将排好序的数组重新放到list中,这也好解释,为什么上面有list.subList(k, list.size()).clear();代码,就是为了把所有多余的数据去掉。上面的是特殊情况,一般情况下没人取那么大的top值。

    下面接着看正常情况下的代码:

    首先声明了一个长度为k*2大小的数组buffer:

int bufferCap = k * 2;

E[] buffer = (E[]) new Object[bufferCap];

为什么是k*2的长度,是为了quickselect算法的实现:

在leastOf函数的第一个While循环中,直接将前K个元素复制到buffer数组中,并且记录前K个元素中的最大值,然后开始下面的while循环。总体思路如下:

开始遍历后面的元素,判断当前元素与前K元素中最大值比较,如果大于等于最大值,然后往buffer中放入值,直到长度为k*2的数组buffer元素填充满,然后开始取前K大值的操作:

int pivotIndex = (left + right + 1) >>> 1;

左右指针相加,再加一,然后无符号右移1位,取到buffer中位数的指针。然后后面的具体过程就是将所有的buffer中的元素前k大的元素移动到0到k-1之中,这个过程不需要排序,只需要移动动前k大的元素,并且需要记录此时前K大元素中最大值,然后再按照上面的过程再次将buffer填充满,再次移动找到前K大的值,直至遍历完所有的数。我们可以得到buffer中前K个元素就是该分区中最大的前K个值。

Arrays.sort(buffer, 0, bufferSize, this);

bufferSize = Math.min(bufferSize, k);
return Collections.unmodifiableList(
    Arrays.asList(ObjectArrays.arraysCopyOf(buffer, bufferSize)));

最后将数组排序,返回最前K大的值。

TOPMIN库:嵌入式系统中高效追踪N个最小值的轻量级方案 在嵌入式数据流处理中,动态维护前N个极值(如最小值)是环境监测、工业告警等场景的基础需求。其核心原理在于避免全量排序与动态内存分配,转而采用固定大小升序数组+插入排序策略,实现O(1)空间复杂度与O(N)确定性插入时间。该技术显著提升实时系统的可预测性与可靠性,特别适用于Arduino、STM32等资源受限MCU平台。结合标签机制(如时间戳、传感器ID),可支撑温度极值记录、电压跌落分析等典型应用。TOPMIN正是面向此类工程痛点设计的轻量级C++模板库。 阅读详情

相关推荐

Spark map与mapPartitions算子源码级深度解析

实现特征fT => U。

Aaron_PHPer的博客 972

机器具备认知能力的“神”操作!

简介: 目前认知概念图谱的构建还在不断完善中,有学者认为,概念是人脑对客观事物的本质反映,是思维活动的结果和产物,是思维活动借以开展的基本单元。建立概念的分类体系,为数以亿计的事物构建认知概念图谱,是人类在让机器具备认知能力的征程中所迈出的非常重要的一步。 背景 概念是人类认知从具体进入抽象的第一步,也是人类认知世界的基石。有学者认为,概念是人脑对客观事物的本质反映,是思维活动的结果和产物,是...

阿里云开发者 5677

ToPMine:我托管的是Ahmed El-Kishky最初在github上提供的文件,只做了最小的更改

托品 我托管的是Ahmed El-Kishky最初在github上提供的文件,只做了最小的更改。 从El-Kishky Illimine版权 伊利诺伊大学香槟分校,2014年 illimine.cs.illinois.edu 附加版权 该软件包包含以下论文中使用的源代码和数据集: @inproceedings {conf / vldb / ElkishkySWVH13,作者= {Ahmed El-Kishky和Yanglei Song和Chi Chi和Clare R. Voss和Hanjiawei},标题= {来自文本语料库的可扩展主题短语挖掘},书名= {VLDB},年= {2015},} 如果您使用此包装中的任何物品,请引用以上文章作为参考。 代码说明 将输入语料库放置在rawFiles中,并将每个文档排成一行。在run.sh(linux)/win_run.bat(对于Window

15_VLDB_Scalable topical phrase mining from text

While most topic modeling algorithms model text corpora with unigrams, human interpretation often relies on inherent grouping of terms into phrases. As such, we consider the problem of discovering topical phrases of mixed lengths. Existing work either perf

Fitz的博客 614

Spark的TopN示例

Spark中实现MapReduce的TopN算法,分为唯一键TopN算法,非唯一键TopN算法和Group内的TopN算法

使用堆实现Top K算法(JS实现)

主要介绍了使用堆实现Top K算法,即JS实现,文中详细介绍了Top K算法,感兴趣的小伙伴们可以参考一下

[Spark的TopN算法实现]

一、TopN算法    MapRedce中的TopN算法是一个经典的算法,由于每个map都只是实现了本地的TopN算法,而假设map有M个,在归约的阶段只有M x N次运算,这个结果是可以接受的并不会造成性能瓶颈。  MapRedce中的TopN算法在map阶段将使用TreeMap来实现排序,以到达可伸缩的目的。      本文将介绍三种TopN的算法:       1.唯一键的TopN算法,就是...

程序车轮 2万+

Revit实战:从零到一,手把手教你用族(Family)搭建一个完整的水闸BIM模型

本文详细介绍了如何使用Revit的族(Family)功能从零开始构建一个完整的水闸BIM模型。通过参数化族设计,实现闸门开度调整自动关联流量计算等智能化功能,提升水利工程BIM模型的工程价值和应用效率。文章涵盖族库规划、核心构件创建、高级技巧及BIM数据深度应用,为水利工程数字化提供实用指南。

weixin_28738165的博客 263

spark 设置主类_Spark资源调度、任务调度源码及流程图

1. Spark-Submit提交参数Options: Master: MASTER_URL, 可以是spark://host:port, mesos://host:port, yarn, yarn-cluster,yarn-client, localdeploy-mode:DEPLOY_MODE, Driver程序运行的地方,client或者cluster,默认是client。Class:CLA...

weixin_39603823的博客 296

安卓风控对抗实战:如何用AOSP定制ROM绕过Momo、AIDA64等检测(从环境搭建到设备画像)

本文详细解析了如何通过定制AOSP ROM绕过Momo、AIDA64等安卓风控检测工具的设备指纹识别。从环境搭建到硬件参数修改,再到内核级特征混淆,提供了一套完整的底层对抗方案,显著提升设备伪装通过率。

weixin_30687051的博客 490

电商数据分析19——数据分析在电商平台价格弹性研究中的应用

价格弹性是一个衡量产品价格变化对销量影响的经济学指标,对于电商平台而言,深入理解和有效运用价格弹性,对于制定竞争策略、优化产品定价具有重要意义。随着大数据时代的到来,通过数据分析研究产品的价格弹性,成为了电商企业制定价格策略、调整市场定位、优化促销活动的重要依据。

theskylife的博客 2836

Spark核心编程:高级编程之topn

案例:对每个班级内的学生成绩,取出前3名1>文件部分数据

江南水景 553

硬件电路(22)-TTL和232切换电路

工作中会遇到TTL和232电平的通信的状态,为了实现一种便捷的切换方式,参考了一些文章,提供一种电路方便大家使用。

剑藏锋的博客 1864

在 Spark RDD 中,sortBy 和 top 算子的各自适用场景

用于对整个数据集进行分区排序或者全局排序。在 Spark RDD 中,个最大/最小的元素。

z1941563559的博客 814

高通camera:PDAF的配置与测试

确认相关log日志都已经打开了之后,判断是在3A算法中没有应用到PDAF,可能是之前在调试AF效果的时候关闭了PDAF,打开效果文件对应的文件夹,在\kamorta_lce_S5K3P9\Scenario.Default\XML\STATS。在log中搜索af_pdaf_proc_pd_single,这个函数是pdaf算法中的,源码被封装了,这里看不到,因此只能通过log打印出来的参数来分析pd是否正确,主要参数有pd ,defocus,confidence。PDAF的配置与测试。

arvin_xiong的博客 2487

第4篇:使用 NModbus 库快速搭建 Modbus TCP 通信(从零开始用 C# 开发 Modbus 上位机)

本文介绍了如何使用 NModbus 库快速搭建 Modbus TCP 上位机通信程序。通过安装 NModbus4 NuGet 包,开发者可以轻松实现 Modbus TCP 连接,无需手动处理底层协议细节。文章详细演示了核心功能实现: 创建 TCP 客户端连接设备 读取保持寄存器(功能码0x03) 写入单个寄存器(功能码0x06) 关闭连接释放资源 提供完整C#示例代码,包含初始化连接、数据读写等关键操作,帮助开发者快速构建Modbus TCP通信应用。相比手动实现,NModbus库大幅简化了开发流程,特别适

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1045

spark总结01

目录 第一部分:SaprkCore部分 Spark简介 1、什么是RDD? RDD的5大特性。 2、怎么理解partition,如何合理的设置partition的数量。 3、RDD或者partition里面存储数据吗?怎么理解内存计算。 4、Spark中的hello world (word count) 5、Spark架构原理 6、创建初始的RDD 7、RDD算子操作 8、RD...

yangshaojun1992的博客 827

python opencv的车牌识别分割详细教程 毕业设计

python opencv的车牌识别分割详细教程 毕业设计

机器学习深度学习业余选手 1327

spark学习

Scala基础语法大全总结 https://blog.youkuaiyun.com/qq_37142346/article/details/80977744 Spark基本工作原理与RDD https://blog.youkuaiyun.com/kaizuidebanli/article/details/83829304 Spark wordcount基本原理深度剖析 https://blog.youkuaiyun.com/yilu...

weixin_43212037的博客 162

【深度学习新浪潮】如何上手DINO v3:Meta新一代视觉大模型实战指南

自定义数据集类(适配本地/公开数据集)# 去除batch维度# 构建数据加载器# 定义分类模型(冻结预训练层,仅训练分类头)self.classifier = nn.Linear(dino_model.config.hidden_size, num_classes) # 分类头global_feat = outputs.global_attention_pool # 取全局特征# 初始化模型# 冻结预训练层(仅训练分类头)# 定义损失函数和优化器。

专注:太空算力、AI infra、异构调度、大模型成本工程 491

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Flink项目实战系列(Spark项目实战系列)

本人的知识星球内发布了大量的Flink和Spark的项目实战,文章的目录如下: 初识Flink Flink读取Kafka源码解读 Flink的状态后端 Flink的runtime Flink系列之数据流编程模型 Flink系列之checkpoint Flink系列之savepoint Flink系列之checkpoint和savepoint的区别 Flink系列之部署Standalone模式 ...

JasonLee实时计算 5800

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Spark——底层操作RDD,基于内存处理数据的计算引擎

Spark 第一章 是什么一 介绍简介特点二 Spark与MapReduce的区别三 Spark运行模式四 Spark CoreSpark RDDRDD LineageSpark任务执行原理Spark代码流程Spark 中的算子Transformations转换算子Action行动算子控制算子 第一章 是什么 一 介绍 简介 Apache Spark是一个快速的通用集群计算引擎。它提供Java,...

时间静止 4555

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

3.算子+PV&UV+submit提交参数+资源调度和任务调度源码分析+二次排序+分组topN+SparkShell...

1.补充算子 transformations Ø mapPartitionWithIndex 类似于mapPartitions,除此之外还会携带分区的索引值。 Ø repartition 增加或减少分区。会产生shuffle。(多个分区分到一个分区不会产生shuffle) 多用于增多分区. 底层调用的是coalesce Ø coalesc...

weixin_30315905的博客 141

Spark Core与Hadoop生态复习

Spark Core作用:内核,提供RDD、任务调度、内存管理、容错机制等。核心特性弹性分布式数据集(RDD)延迟计算(Lazy Evaluation)容错机制(DAG、血缘关系)内存计算口诀:RDD弹性,懒加载,血缘容错,快如闪电。Driver:作业提交、任务调度Executor:具体计算、内存缓存:资源分配Worker(Standalone模式):运行Executor进程口诀:Driver调度,Executor计算,Manager分配。Spark核心。

IT技术学习与工作笔记分享 1183

支持spark_大牛用10小时就把Spark讲完了,总计2.2G,6大技术文档

前言Apache Spark是一个开源集群运算框架,相对于Hadoop的MapReduce会在运行完工作后将中介数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘时即在存储器内分析运算。Spark 在存储器内运行程序的运算速度能做到比 Hadoop MapReduce 的运算速度快上 100 倍,即便是运行程序于硬盘时,Spark 也能快上 10 倍速度。Spark 允许用户...

weixin_29000417的博客 163

spark集群搭建_大牛用10小时就把Spark讲完了,总计2.2G,6大技术文档

前言Apache Spark是一个开源集群运算框架,相对于Hadoop的MapReduce会在运行完工作后将中介数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘时即在存储器内分析运算。Spark 在存储器内运行程序的运算速度能做到比 Hadoop MapReduce 的运算速度快上 100 倍,即便是运行程序于硬盘时,Spark 也能快上 10 倍速度。Spark 允许用户...

weixin_39862847的博客 105
上一篇: Spark数据倾斜的原因以及解决方案
下一篇: Spark源码分析-SortByKey源码
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值