大数据Top K问题
大数据下的2个Top K场景:
1、 1亿个数字中找出最大或最小的前100个数字(考虑判重和内存空间限制)?
思路: 考虑将数字分散存储在不同文件中, 然后依次读取各个文件, 例如1~10000存到1.txt、 2~20000存到2.tx、以此类推;
如果不判重,可以将前100个数字做成最大堆或最小堆的数据结构(找最大的Top100用最小堆, 找最小的Top100用最大堆), 然后依次遍历所有数字, 符合条件时替换根节点后并重新构建堆。堆的缺点是允许有重复数字!!!
如果要判重,则创建一个100个空间的空数组, 遍历1亿个数字依次插入值(按照升序), 使用二分查找算法判断新值在数组中的位置并插入, 该数组最多容纳100个值。 当有101个值时先判重, 如果重复继续向后遍历, 如果值大于数组最小值则插入到指定位置,数组第一个元素移出数组, 因为数组是连续的,所有可以用内存拷贝方式赋值,只有新插入的值要单独赋值到对应的下标(原理类似于android.util.SparseArray)。 因内存拷贝可认为不占用时间, 该思路的总会时间复杂度是O(1亿*log100), log100是二分查找的复杂度。
2、 1亿个搜索关键词找出次数最多的前100个搜索词(考虑内存空间限制)?
思路: 核心是“分治”、“归并”和哈希, 第一次遍历将关键词散列到不同的文件中(散列算法是性能关键,哈希函数的性能直接影响散列的结果, 尽量避免“数据倾斜”), 同一个关键词一定会散列到同一个文件, 理想情况是所有关键词均匀散列到不同的文件中(即分治思想,将大文件分解为小问题)。
读取每个文件并记录各关键词的次数, 做个冒泡排序, 从每个文件中排序出前100的关键词;
取第一个文件的记录结果, 和第二个文件做“合并”, 即200个结果中排序出前100个关键词, 然后依次合并第三个、第四个。。。。第N个文件(将子结果合并为总结果)。
PS: 大道同源, 我想到2个类似的场景。
1、 电脑里有众多的文件,但我们还是能从众多文件中找到你想要的。 这是为什么呢? 因为使用了文件夹, 按照文件类型保存在各个层级的目录里。 这个目录层级跟”在1亿个搜索词中找出频率最高的100个“的解决思路是一样的, 即将关键词分散存储到不同的文件里(也可以使用层级目录, 目录越深分散的粒度越细, 到底分几个文件/目录层级其实是时间空间的权衡)
2、 数据库用户表里要存储几亿个记录,该怎么办? 跟上面管理电脑文件的问题类似, 可以按地域、年龄、姓名等等因素将数据存储到N张表里, 术语叫做”横向切割“。
名词解释:
1、”数据倾斜“是大数据里的一个概念,就是数据集中到几个文件、处理器, 没均匀分散到各个处理单元。说白了就是忙的忙死,闲的闲死。
2、”分治“就是将大问题分解为小问题, 处理每个小问题并得到结果, 然后将所有子结果汇总成最终结果。
3、”横向切割“是数据库的一个概念, 就是将表记录分散存储到不同的表里,每个表里的记录都是完整的。 还有个“纵向切割”,就是将分拆表的列为多个表, 即一条记录要存到多张表里且每个表只存几个属性。
4、“哈希”即散列, 就是通过哈希值找到存储位置, 理想情况下时间复杂度O(1)。
下面开撸堆排序算法和代码:
堆是个完全二叉树, 节点先从上到下后从左到右都是满的, 说白了叶子节点可以不满且非叶节点都有。 用Java数组形容的话, 数组下标从0到N-1。 如果节点i有左子树,那么左子树的下标是2i+1;如果节点i有右子树,那么右子树的下标是2i+2;如果有父节点,对应下标是(i-1)/2取整。
堆分为最大堆和最小堆,也可以叫大根堆和小根堆; 最大堆的定义是任意子树根节点大于或等于子节点,所以根节点是最大值; 最小堆的定义是任意子树根节点小于或等于子节点, 所以根节点是最小值。
堆排序思想是先构造堆,然后做N次循环, 每次交互根节点和最后一个值(最后节点是递减的)重新构建堆。
构造堆是堆排序的核心, 算法是从最后一个非叶节点(即N/2)开始,先从右到左后从下到上依次判断交换值。详见堆排序动画: http://www.benfrederickson.com/heap-visualization/
使用最小堆找出最大的前10个数字:
//得到最大的前length个数字, 使用最小堆数据结果,理论上可能有重复数字public static void topNums(final int length)throws Exception{Scanner scanner=new Scanner(new FileInputStream("input.txt"));long array[]=new long[length];for(int i=0; i<array.length; i++){array[i]=scanner.nextLong();}buildMinHeap(array); //构造小顶堆while (scanner.hasNextLong()){long value = scanner.nextLong();if(value < array[0]) {continue; //根节点是数组最小值, 如果当前值比最小值还小就跳过}array[0] = value; //丢掉根节点,即替换array[0]ajustHeap(array, length,0); //重新构造小根堆}//将一个小根堆进行排序,用堆排序思想heapSort(array);for(int i=0; i<length; i++)System.out.println(array[i]);scanner.close();}public static void main(String[]args)throws Exception{randomData(); //生成随机数并保持到文件里long start=System.currentTimeMillis();topNums(10); //从文件中找出最大的前10个数字long end=System.currentTimeMillis();System.out.println(end-start);//验证堆排序是否正确的测试数据long[] array = {1, 3, -1, -5, 5, 10, 20, -10, 100, 30, 11, 16};System.out.println("原始数组:");for (int i = 0; i < array.length; i++) {System.out.print(array[i] + " ");}heapSort(array);System.out.println("排序后:");for (int i = 0; i < array.length; i++) {System.out.print(array[i] + " ");}}//得到从大到小的降序public static void heapSort(long[] array) {if (array == null || array.length <= 1) {return;}buildMinHeap(array); //构造堆for (int i = array.length - 1; i >= 1; i--) {long temp = array[i];array[i] = array[0];array[0] = temp;ajustHeap(array, i, 0); //重新调整第0个下标节点}}//构造小根堆private static void buildMinHeap(long[] array) {if (array == null || array.length <= 1) {return;}int half = array.length / 2;for (int i = half; i >= 0; i--) {ajustHeap(array, array.length, i);}}//构造小顶堆, 按照分治的思想递归private static void ajustHeap(long[] array, int heapSize, int index) {int left = index * 2 + 1;int right = index * 2 + 2;int smallest = index;if (left < heapSize && array[left] < array[index]) {smallest = left;}if (right < heapSize && array[right] < array[smallest]) {smallest = right;}if (index != smallest) {long temp = array[smallest];array[smallest] = array[index];array[index] = temp;ajustHeap(array, heapSize, smallest);}}//随机生成100000个数字并保存到文件里public static void randomData()throws Exception{//随机100万数据File file=new File("input.txt");if(!file.exists())file.createNewFile();PrintStream printStream=new PrintStream(new FileOutputStream(file));Random random=new Random(System.currentTimeMillis());for(int i=0;i<1000000;i++){long k=Math.abs(random.nextLong());printStream.println(k);//printStream.println(k); //连续写2个相同值, 验证使用堆得到的top k结果有重复数字}printStream.close();}
其中adjustHeap函数是核心函数, 思想是找出当前节点、左子节点、右子节点的最大或最小值, 如果当前节点已经是最大或最小则退出, 否则交换当前节点和子节点的值,然后递归处理子节点, 这是“分治法“的体现。
构造堆结果也可以使用非递归的方式实现:
//构造最大堆的非递归实现public void adjustHeapExt(long[] array, int parent, int length) {long temp = array[parent];int child = 2 * parent + 1; //左子节点while (child < length) {if (child + 1 < length && array[child] < array[child + 1]) {child++; //右子节点比左子节点更大}if (temp >= array[child]) {break; //当前节点最大则退出}array[parent] = array[child]; //替换根节点的值parent = child; //向下遍历child = 2 * child + 1; //从左子节点开始比较}array[parent] = temp; //存储原根节点值}
补充一下: 1亿个数字找出top 100的二分查找原理, 对于有序数组先比较array[0], 然后二分查找并数组前移、后移加上赋值。
摘自SparsArray.java
/*** 二分查找数据中是否存在值* @param array,数组,升序数组* @param value,要查找的值* @return 找到就返回数组下标, 找不到就返回负数(需要插入的位置)*/static int binarySearch(long[] array, long value) {int lo = 0;int hi = array.length - 1;while (lo <= hi) {final int mid = (lo + hi) >>> 1;final long midVal = array[mid];if (midVal < value) {lo = mid + 1;} else if (midVal > value) {hi = mid - 1;} else {return mid; // value found}}return ~lo; // value not present}
小结, 对于大数据第一步是要"分治”, “分治”算法是影响性能的关键。
大数据Top K问题相关推荐
- 堆实战(动态数据流求top k大元素,动态数据流求中位数)
动态数据集合中求top k大元素 第1大,第2大 ...第k大 k是这群体里最小的所以要建立个小顶堆 只需要维护一个大小为k的小顶堆 即可当来的元素(newCome)> 堆顶元素(smallTo ...
- 海量数据处理 大量数据中找出最大的前10个数 (Top K 问题)
在工作中我们常遇到此类问题,从一个大量甚至海量的数据中取出前几个大的数.必须在海量的文章中取出点击量最大的10篇文章. 此类问题其实就是Top K问题. 给定一个数据(数据量海量 N),想找到前 K ...
- 第K大/Top K及其简单实现
转载请注明出处:http://blog.csdn.net/u012469987/. 见网上第K大多数只给思路,没给实现,我就来填坑了. update 2017-09-23 有同学反馈说面试遇到这个题, ...
- 神策数据荣获 2017 年度商业影响力大数据领域新锐企业 TOP 10
近日,由品途集团联合中国电商委.中关村天使投资协会,以及国内多家产业投资机构.学术机构.商业领域创新领军企业.互联网科技媒体共同发起的品途 2017 NBI 影响力评选颁奖盛典正式举行.大会隆重发布了 ...
- 工具推荐 | 分析大数据最需要的Top 10数据挖掘工具
点击查看全文 本文讲的是 工具推荐 | 分析大数据最需要的Top 10数据挖掘工具, 首先,我们要了解什么是数据挖掘?官方提供的定义如下:数据挖掘又称为资料探勘.数据采矿.它是数据库知识发现(Know ...
- 各大数据竞赛 Top 解决方案汇总
现在,越来越多的企业.高校以及学术组织机构通过举办各种类型的数据竞赛来「物色」数据科学领域的优秀人才,并借此激励他们为某一数据领域或应用场景找到具有突破性意义的方案,也为之后的数据研究者留下有价值的经 ...
- GitHub 干货 | 各大数据竞赛 Top 解决方案开源汇总
AI 科技评论编者按:现在,越来越多的企业.高校以及学术组织机构通过举办各种类型的数据竞赛来「物色」数据科学领域的优秀人才,并借此激励他们为某一数据领域或应用场景找到具有突破性意义的方案,也为之后的数 ...
- 高并发和大数据下的高级算法与数据结构:如何快速获取给定年龄区间的微信用户数量或快速获取美团中购买量前k的品类
在技术领域有一句经典话:程序=算法+数据结构.这意味着一个好的程序员往往要在算法与数据结构上有扎实的功底.这也是为何各个国内外大厂在面试时一定会考核这个领域.随着时代的发展,算法与数据结构的定义也在发 ...
- 大语言模型参数说明(Temperature,Top p,Top k)
如下是一些模型的运行界面.在使用OpenAI的接口,常常遇见一些参数,搞清它们的含义促使我们更进一步理解输出的结果. 学习传送带 1.Temperature 用于调整随机从生成模型中抽样的程度,因此每 ...
- 地图大数据来了!中国人口吸引力城市TOP 10
导读:大湾区险胜包邮区. 作者:安十一 来源:城市战争(ID:sunbushu123) 近日,各大城市发布人口数据,媒体发现,2021北上广三大城市合计增长7.7万人. 要知道,过去十年,北上广合计每 ...
最新文章
- Citrix Avalon安装实验手册之一----Avalon概述及实验环境准备
- javascript eval函数解析json数据时为什加上圆括号eval((+data+))
- Membership角色与权限管理
- jQuery中find()方法和filter()方法的区别
- ecs服务器网站文件放在哪里,云服务器ecs文件放哪里
- QuickFIX/N入门
- PHP运行环境之IIS FastCGI 进程意外退出解决办法
- java treemap_Java TreeMap size()方法与示例
- Python学习8 函数 匿名函数 内置函数
- Idea 同一工程根据不同配置文件启动、idea 同一工程多实例同时运行
- LeetCode 1985. 找出数组中的第 K 大整数(排序)
- 【从0到1,搭建Spring Boot+RESTful API+Shiro+Mybatis+SQLServer权限系统】05、Shiro集成
- 动态通讯录(动态内存开辟)(C语言)
- 【学习教程】CMIP6数据处理方法与典型案例分析
- 英语介绍计算机,计算机英语自我介绍
- 40天python入门教程_【第41天】python全栈从入门到放弃
- 不习惯的 Vue3 起步六 の Echarts绘制下钻地图
- “走进名企”——微软亚洲研究院
- html 在td中加css,html td nowrap不换行属性使用方法
- Java面相对象练习案例其参考代码