海量数据处理-重新思考排序

海量数据处理--重新思考排序(1)

海量数据处理常用技术概述

如今互联网产生的数据量已经达到PB级别,如何在数据量不断增大的情况下,依然保证快速的检索或者更新数据,是我们面临的问题。
所谓海量数据处理,是指基于海量数据的存储、处理和操作等。因为数据量太大无法在短时间迅速解决,或者不能一次性读入内存中。

在解决海量数据的问题的时候,我们需要什么样的策略和技术,是每一个人都会关心的问题。今天我们就梳理一下在解决大数据问题
的时候需要使用的技术,但是注意这里只是从技术角度进行分析,只是一种思想并不代表业界的技术策略。
常用到的算法策略

  1. 分治:多层划分、MapReduce
  2. 排序:快速排序、桶排序、堆排序
  3. 数据结构:堆、位图、布隆过滤器、倒排索引、二叉树、Trie树、B树,红黑树
  4. Hash映射:hashMap、simhash、局部敏感哈希

海量数据处理–重新思考排序(1)

定义排序

排序:
  将一组无序的集合,根据某个给定的条件,将其变成有序的方法就是排序。从这个我给出的不严谨的定义中排序是方法,目的是让原来无序的集合满足条件有序。
  这里我们基于海量数据的考虑重新思考排序,不会详述每一种排序方法的原理,主要面向的是如何在海量数据情况下使用排序方法。

常用的排序方法:
  插入排序,选择排序,冒泡排序,希尔排序,快速排序,归并排序,堆排序,桶排序,计数排序,基数排序。
下面给出几种排序算法的简单介绍图。
     Screenshot-from-2018-11-05-14-04-03

既然有这么多的排序方法,我们可以直接读取数据到内存中直接调用语言中封装好的排序方法即可。但是数据量很大,不能将数据同时读入内存。
这就出现了所有的外排序,我们可以用归并排序的思想来解决这个问题,也可以基于数据范围用"计数排序"的思想来解决。
排序真的很重要吗?我一直相信一句话:没有排序解决不了的问题。这里给出几个需求,例如:

  • 取最大的k个数,直接降序排序取前k个即可;
  • 推荐、搜索业务,我们也可以直接排序(精度不高)
  • 二分查找之前也要求数据有序

但是在这里我们不讲排序,只说排序中用到的思想,以及在海量数据处理的过程中,如何用到的排序。依然接着
上次的文章,我们求top k的时候,最后用到了一个数据结构,叫做堆,堆可以找个top k,就能找到n个数中的
top n,这样就是有序,叫做堆排序。

堆排序

在top k中我们用到了一个数据结构堆(有最大堆和最小堆),这里就先介绍一下这个数据结构的性质,基于最大
堆进行介绍。堆是一个完全二叉树,对于任意的节点,我们可以使用数据来表示最大堆,设置下标从0开始, 满足以下性质:

  • root > left && root > right. (左右节点存在)
  • 根节点:root_index; 左孩子节点:left_index; 右孩子节点:right_index
  • left_index = root_index * 2 + 1
  • right_index = root_index * 2 + 2
  • root_index = (*_index - 1) / 2

在堆的数据结构进行增删改查的过程中,我们始终维护堆的数据结构,定义MaxheapFy(int *A, int i)表示维护第i个
节点满足最大堆的性质,注意这里没有考虑到泛型编程,正常应该提供一个比较方法的函数,让使用者自己设置比较方式。
从下面的伪代码中,我们可以知道对于一个大小为n的堆,维护一次堆的性质,最坏时间为O(logn),但是必须保证
在改变之前,他是满足堆的性质的。

void MaxheapFy(int *A,int i) {
    // i 要在A的范围之内,
    assert(i >= 0);
    assert(i < n) // 堆的大小
    l = LEFT(i), r = RIGHT(i); // 得到左右子节点,如果存在
    now = i;

    // 找到左右孩子的最大值
    if(l<=heapsize&&A[l]>A[now]){
        now=l;//交换A[l]和A[i],并递归维护下一个当前结点now
    }
    if(r<=heapsize&&A[r]>A[now]){
        now=r;//交换A[l]和A[i],并递归维护下一个当前结点now
    }

    if(now != i) { // 交换,递归维护
        swap(A[i], A[now]);
        MaxheapFy(A, now);
    }
}

基于上面的这个维护的性质,我们可以直接对于长度为n的数组建立最大堆,我们知道当只有一个元素的时候,一定满足最大堆的性质,
基于这个性质,我们对于长度为n的数组A,从 n / 2向前维护每一个节点的性质,就可以得到最大堆.从下面给出的最大堆
的构建代码,我们可以分析建堆的时间复杂度是O(nlogn).因为每次维护是O(logn),维护n次,(这里计算时间复杂度的时候,忽略常数系数)。

void BuildMaxHeap(int *A,int n){//A[1..n]
    heapsize=n;//全局变量,表示最大堆的大小
    for(int i=n/2;i>=1;i--){//从n/2..1维护堆中每个节点的最大堆性质:结点的值大于起孩子的值
        MaxheapFY(A,i);
    }
}

建成最大堆之后,从最大堆的性质我们知道,A[0]一定是最大值,如果要堆A升序排序,就可以swap(A[0], A[n-1]);
继续维护A[0],直到堆中只是一个元素,这就完成了堆排序。从这个思路出发,对于top k问题,我们为什么要维护一个
最小堆呢,因为我们要过滤所有的数据,保证每次弹出一个最小值,之后剩下的k个一定是top k的最大值,但是这k个不一定
有序,如果需要我们可以堆这k进行任何排序,因为我们通过过滤,数据已经很少了,时间复杂度就是从n个中过滤出来k个。
首先任选k个构建最小堆, 时间复杂度O(klogk), 用最小堆过滤n-k个数字,每次维护堆的性质,时间O((n-k)logk).
总的时间复杂度O(klogk + (n-k)logk)。(注意当k多大时,我们不在使用堆的数据结构,这里留给读者计算)。

void HeapSort(int *A,int n){
    BuildMaxHeap(A,n);//建立最大堆
    for(int i=n;i>=2;i--){
        //cout<<A[1]<<" ";
        swap(A[1],A[i]);//交互A[1]和A[i],使得A[i]中为当前最大的元素
        heapsize--;//堆大小减去1,便于下次操作去掉已经排好序的元素
        MaxheapFY(A,1);//此时A[1]不一定满足最大堆的性质,重新维护下标1的最大堆的性质
    }
}

我们可以知道堆的使用可以很好的找到top k,堆使用场景都有什么呢?这里我们给出工业界常用到的使用场景。
推荐系统大家都很了解,例如手机百度、今日头条等会推荐用户喜欢的新闻,在推荐系统中就有用到堆。为了很好的了解到堆的
应用,我简单介绍一个简化推荐系统,至少有recall和rank两个部分,在recall(召回的阶段)),对于使用手机百度的用户,
当你进行一次刷新的时候,后天会根据的你各种profile等静态和动态的特征,请求后端,后端会从多个方面召回一可能感兴趣
的文章,例如基于地域,性别,当天热门,学历,浏览记录等,这样就会返回多个带有权重的队列,下一步会从这多个队列中,选择
100个得分最高的传到下一层,这个过程中就要用到堆。这里用到的是大根堆。

问题抽象
例如我们有100个有序(降序)的数组,现在从这个100个数组中找到最大的k个元素。这就是上述问题的抽象。使用100路归并(后面的归并排序)。
用一个大小为k的最大堆,每次弹出一个最大值,记录是那个队列中的值,直到出现k个数,就结束。这里里面的两个思想,

  • 归并,不能处理的大问题,分成多个小问题并行处理,之后归并结果,比如外排序
  • 堆,帮助我们找到top k,k要相对n较小。

Screenshot-from-2018-11-05-16-53-45

参考:
数据结构: 构建和使用堆
《算法导论》第六章:堆排序
《编程之美:面试与算法心得》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Batch 是一个用于批处理海量数据的开源框架。它提供了一种简单且灵活的方式来处理大量的数据,帮助开发人员根据自定义的规则和逻辑进行批量处理任务。 在处理海量数据时,Spring Batch 提供了以下特性: 1. 分批处理:Spring Batch 可以将大数据集分成多个小批次进行处理,避免一次性加载全部数据,降低了内存的压力。 2. 事务管理:Spring Batch 支持事务管理,可以保证数据的一致性和完整性,确保批处理任务的可靠性。 3. 异常处理:Spring Batch 提供了灵活的异常处理机制,可以捕捉并处理异常,保证任务的顺利执行。 4. 监控和报告:Spring Batch 提供了可视化的监控和报告功能,可以实时查看任务的执行进度和状态,方便开发人员进行调试和排错。 5. 多线程处理:Spring Batch 支持多线程处理数据,可以并发执行多个任务,提高数据处理的效率。 6. 可扩展性:Spring Batch 提供了丰富的扩展点和接口,可以根据业务需求进行定制和扩展,实现个性化的数据处理逻辑。 总之,Spring Batch 是一个强大的批处理框架,它能够帮助开发人员高效地处理海量数据,具有良好的可靠性、可扩展性和灵活性,是处理大规模数据任务的不错选择。 ### 回答2: Spring Batch是一个用于大规模数据处理的开源框架。它提供了一种有效的方式来处理海量的数据,以实现批处理任务的分解和并发执行。 首先,Spring Batch提供了丰富的组件来管理和控制批处理任务。这些组件包括job、step、tasklet和chunk等,它们可以帮助我们定义和配置批处理任务的各个环节,从而使得海量数据处理变得更加可控和可管理。 其次,Spring Batch提供了高效的数据处理机制。它采用了读-处理-写的模式来处理数据,可以将输入数据进行分块读取,并通过多线程、多进程或分布式集群的方式进行并发处理,再将处理结果进行批量写入。这样可以大大提高数据处理的效率和吞吐量,适应海量数据的处理需求。 此外,Spring Batch还提供了一系列的错误处理和容错机制。对于处理过程中可能出现的错误或异常,Spring Batch可以捕获并记录,然后根据配置的策略进行重试或跳过等处理。这样可以保证批处理任务的数据完整性和可靠性,防止数据丢失或处理中断导致的问题。 总之,Spring Batch是一个非常适合处理海量数据的框架。它可以帮助我们高效地处理大量数据,并提供了灵活的批处理任务管理和容错机制,从而满足海量数据处理的需求。 ### 回答3: Spring Batch 是一个Java框架,用于处理海量数据的批处理任务。它提供了一套强大的工具和功能,可以有效地处理大量的数据,并且具有良好的可扩展性和可维护性。 在处理海量数据时,Spring Batch 提供了以下功能和优势: 1. 分批处理:Spring Batch 可以将海量数据分为多个小批次进行处理,每次处理一批数据,以降低内存和CPU的使用量。这种方式可以提高整体的性能和效率,并且可以更好地管理资源。 2. 事务管理:Spring Batch 提供了事务管理机制,确保数据处理的原子性和一致性。即使在处理过程中出现错误或异常,Spring Batch 也可以回滚事务,保证数据的完整性。 3. 多线程处理:Spring Batch 支持多线程处理,可以同时处理多个批次的数据。通过合理的线程配置,可以更好地利用多核处理器的性能,并且可以并行处理不同的数据批次,提高整体的处理速度。 4. 容错和错误处理:Spring Batch 提供了强大的容错和错误处理机制。它可以记录和重试失败的任务,并且可以自定义错误处理策略。这样可以有效地处理异常情况,并且可以保证数据的准确性和完整性。 5. 可扩展性和可维护性:Spring Batch 使用了模块化的架构,提供了丰富的可重用组件和扩展点。这样可以更好地实现代码的可维护性和可扩展性,方便开发人员进行定制化开发和集成其他系统。 总之,Spring Batch 是一个功能强大的框架,适用于处理海量数据的批处理任务。它可以提高处理效率和性能,并且具有良好的可扩展性和可维护性,非常适合处理大量的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值