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万+

Node.js内存溢出?一招搞定JavaScript heap out of memory错误(附永久配置方案)

本文深入解析Node.js内存溢出问题,提供从临时调整到永久配置的完整解决方案。重点介绍通过设置`max-old-space-size`参数和`NODE_OPTIONS`环境变量来扩展JavaScript堆内存限制,适用于Webpack、Vite等构建工具的大型项目场景,并涵盖Windows、Linux/macOS多平台配置方法。

cake8的博客 1057

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

基于STM32的最简易蓝牙遥控小车

基于STM32的蓝牙遥控小车,基于HAL库编写代码,具有移动功能,读者可自行添加其他扩展功能。按下状态的对应关系:2前进,4左转,5停止,6右转,8后退,松开状态都是5,都选择16进制。首先按照小车的图纸把小车的机械部分装好。做这个小车的成本在200元左右,包括焊接设备,杜邦线等。

weixin_43469377的博客 1万+

手把手教你用LTspice仿真BUCK-BOOST电路(附波形分析)

本文详细介绍了如何使用LTspice进行BUCK-BOOST电路的仿真与波形分析,涵盖电路原理、CCM与DCM模式特性、效率优化及常见问题解决方案。通过实战案例,帮助工程师快速掌握升降压转换电路的设计与调试技巧,提升电力电子设计能力。

julia4scientist的博客 1048

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

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

江南水景 553

DB文件在编程中的作用及示例代码

通过使用DB文件,我们可以实现数据的持久化存储,并能够高效地进行数据的增删改查操作。在本文中,我们以SQLite数据库为例,演示了如何使用Python语言创建和操作DB文件的示例代码。在实际的编程中,我们可以根据具体的需求和使用的数据库系统来进行更复杂的操作和优化。通过使用DB文件,我们可以实现数据的持久化存储,确保数据在程序关闭后也能被保留,并且能够高效地进行数据检索和更新。在本文中,我们将探讨DB文件的作用,并提供一些示例代码展示如何在编程中使用DB文件。上述代码中,我们使用SQLite提供的。

CodeSpark的博客 1821

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

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

z1941563559的博客 814

基于非接触式微波雷达设计的跌倒检测预警系统【短信报警】

本项目选择基于非接触式微波雷达的跌倒检测预警装置作为技术核心,采用云帆瑞达的R60AFD1跌倒检测模组。这一模组能够根据人体的运动变化,如速度、距离和姿态等特征,判断是否发生跌倒,并可以持续监控老年人是否处于危险状态。此外,本项目还结合4G通信技术,通过Air724UG模块实现短信报警功能,一旦检测到跌倒事故,系统将自动通过4G网络向紧急联系人发送短信报警,及时通知亲属或医护人员进行救援。

1755

IEEE S&P 2026 大模型安全论文整理

本文梳理了 IEEE S&P 2026(第47届 IEEE 安全与隐私研讨会)中与 LLM Safety 相关的论文,涵盖大模型越狱攻击、防御与对齐、隐私保护、RAG 安全、多模态大模型安全、智能体安全、图-LLM 安全、工具链安全及生成式 AI 安全与隐私等方向。

CSPhD-winston的博客 1335

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

Agent Skills应用解析:构建可扩展、高效率AI探员

Agent Skills是一个简洁而强大的概念:它是一个包含组织化的指令、脚本和资源的文件夹,智能体可以动态地发现并加载这些内容,以在特定任务中表现更佳。可组合性(Composability):一个Agent Skill是一个独立的、封装良好的能力单元。开发者可以为不同的功能(例如PDF处理、网络浏览、数据分析)创建独立的技能,然后根据需要将它们组合起来,赋能不同的智能体。这意味着不再需要为每个用例构建碎片化、定制设计的智能体,而是可以通过组合现有技能来快速构建新的专业智能体。

形上得其象,形下合于数;阴阳自济,玄理自明。 1627

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

【用unity实现100个游戏之2】复刻实现经典2d平台跳跃游戏《蔚蓝 Celeste》(附工程源码)

蔚蓝》是一款备受好评的独立游戏,由游戏开发工作室开发并由发行。这款游戏于2016年首次发布,并在玩家和评论界收获了广泛赞誉。蔚蓝以其独特的艺术风格和引人入胜的故事而著称。游戏以深海为背景,玩家将扮演一个能够探索水下世界的神秘生物。游戏通过惊人的视觉表现和动态的海洋生态系统为玩家带来了令人难忘的游戏体验。无论是广阔的水下景观还是充满生机的海洋生物,蔚蓝都让玩家感受到深海的神秘和美丽。蔚蓝在玩法上注重探索和解谜。玩家可以在海底环境中自由游动,发现隐藏的地点和秘密,与各种生物互动,并解决环境谜题以继续前进。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 4167

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

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

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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、付费专栏及课程。

余额充值