0. 比赛

公司里的第三届XX中间件性能挑战赛

我和另外两个P5组队参加,队名为“db kernel”。最后获得了第八,应该是P5里的最高排名。

以下简单扼要地介绍一下题目,以及我们的解题思路,真的非常简单扼要。

1. 题目

题目主要解决的是NewSQL领域中使用最频繁的一个场景:分页排序,其对应的SQL执行为order by id limit k,n 主要的技术挑战为"分布式"的策略,赛题中使用多个文件模拟多个数据分片。

1.1 题目内容

给定一批数据,求解按顺序从小到大,顺序排名从第k下标序号之后连续的n个数据

例如: top(k,3)代表获取排名序号为k+1,k+2,k+3的内容,例:top(10,3)代表序号为11、12、13的内容,top(0,3)代表序号为1、2、3的内容 需要考虑k值几种情况,k值比较小或者特别大的情况,比如k=1,000,000,000 对应k,n取值范围: 0 <= k < 2**63 和 0 < n < 100。

1.2 数据文件说明

  1. 文件个数:10
  2. 每个文件大小:1G
  3. 文件内容:由纯数字组成,每一行的数字代表一条数据记录
  4. 每一行数字的大小取值范围 0 <= k < 2**63 (数字在Long值范围内均匀分布)
  5. 数据文件的命名严格按照规则命名。命名规则:"KNLIMIT_X.data" ,其中X的范围是[0,9]

1.3 测试环境

测试环境为相同的24核物理机,内存为98GB,磁盘使用不做限制(一般不建议选手产生超过10G的中间结果文件)。选手可以使用的JVM堆大小为2.5G。

PS:

  1. 选手的代码执行时,JAVA_OPTS=" -XX:InitialHeapSize=2621440000 -XX:MaxHeapSize=2621440000 -XX:MaxNewSize=873816064 -XX:MaxTenuringThreshold=6 -XX:NewSize=873816064 -XX:OldPLABSize=16 -XX:OldSize=1747623936 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC "
  2. 不准使用堆外内存。

1.4 计算耗时

总共执行五轮的总耗时。

2. 解决思路

在这个题目的程序时间是以下两个部份的总和: 构建索引和查找TOP(K,N)。构建索引仅仅在第一次程序运行时进行,后面几轮的TOP(K,N)的查找都可以复用第一轮的索引。程序的基本流程是:

  1. 假如索引不存在,构建索引
  2. 利用索引查找TOP(K,N)

2.1 构建索引

由于程序的运行时间要尽可能地短,于是对数据做全局排序是不现实的。

这里我们的做法是将原文件切成若干个有序的Block,对每一个Block进行排序。通过对所有的Block进行多路归并,可以得出完全有序的数据。而该题目求TOP(K,N)并不需要得出有序的前K个值,只需要第K个值之后有序的结果。这时解题的关键就变成如何快速定位到K,从这个起点进行多路归并,快速地把结果得出。

索引的设计目标是快速定位到K。然而我们发现直接定位到K也很困难,但是定位到一个比K小的值K-相对容易,这时可以利用多路归并从K-逼近到K。此时再通过多路归并N轮求出最后的结果相对来说更简单。

现在问题就从找到第K个值转化成了找到第K-个值。此时K-离K值越近,效果越好。

解题思路也很简单。我们将0~pow(2,63)-1这个范围的数等距分成若干个Range,统计数据落在不同的Range内的个数。假如我们分成4个Range,即每个Range的范围是[0, pow(2,61)-1],[pow(2,61), 2pow(2,61)-1],[2pow(2,61), 3pow(2,61)-1],[3pow(2,61), 4*pow(2,61)-1]。

每个Block内存储一个对应的Range count的数组,在每个Block内部统计不同的range的计数。而所有的Block内Range count数组的总和即为一个全局的Range count的数组。Range的个数越多,落在每个range中的数字越少,定位的K-离真实的K的距离就越近,当然效果也就更好。

当然Range的个数也不是越多越好。随着Range的个数增多,提升的性能收益是不断减少的。而每个Block存储的索引信息需要持久化,需要IO时间,所需的时间是线性增长的。Range的个数必然存在着某个最优的上限。

通过将K与与全局的Range Count数组比对,可以快速定位第K个值落在哪个Range里。此时对应的Range的开头是可以获得的,这时我们将它称为K-。这时利用多路归并从K-逼近到K,再通过多路归并N轮求出最后的结果。

2.1.1 关键数据结构

将Block大小定为16MB,1GB左右的文件可以被分成大约64个Block,对应十个文件可以被划分为大约640个Block。对应一个有序的Block,我们并不存储真实的数据,而是存储它在原文件中的偏移量。此时一个Block内的所有数据的偏移量offset对于这个块头都在16MB以内,最多需要用3个字节即可索引。

每个Block的元数据用如下数据结构去描述。

struct BlockInfo
{
int file_index; //对应的"KNLIMIT_X.data" ,其中X的范围是[0,9]
int offset; //该Block相对该文件的偏移量
int count; //该Block内一共有多少条数据
int range_count[RANGE_NUM]; //RANGE_NUM是range的个数。
};

每个Block内数据的索引用如下数据结构去描述。

struct BlockDataOffset
{
uint24_t offset[DATA_NUM];
};

此时Block内的第n条数据可以通过BlockInfo::offset + BlockDataOffset::offset[n]的方式去原文件中去获得。

另外一个很重要的数据结构是全局的Range Count的统计。

struct OverallRangeCount
{
int range_count[RANGE_NUM]; //RANGE_NUM是range的个数。
};

2.2 TOP(K,N)

求TOP(K,N)的过程相对简单,如下:

  1. 通过将K与OverallRangeCount的统计对比,找到对应的K落在具体哪个Range上,以及Range的起点K-。
  2. 找出每一个BlockInfo中对应的Range的计数,这个计数找到对应在BlockDataOffset中的起点,这是每一个Block归并的起点。需要将BlockDataOffset中的值换算成真实偏移值对原文件中去获得真实数据。
  3. 将属于同一个文件KNLIMIT_X.data的Block绑定在一起,放在一个线程里进行多路归并,提供给上层一个有序的数据流的抽象。
  4. 对这十个抽象出来的数据流进行多路归并,先从K-归并至K,再归并至K+N,得出结果。

top(k,n)—db kernel队解题思路的更多相关文章

  1. Top K问题的两种解决思路

    Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小1 ...

  2. 【LeetCode】692. Top K Frequent Words 解题报告(Python)

    [LeetCode]692. Top K Frequent Words 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/top ...

  3. [LeetCode] Top K Frequent Words 前K个高频词

    Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted b ...

  4. 海量数据处理之top K问题

    题目: CVTE笔试题https://www.1024do.com/?p=3949 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节. 假设目前有一千万 ...

  5. 【分步详解】两个有序数组中的中位数和Top K问题

    (这也是一道leetcode的经典题目:<LeetCode>解题笔记:004. Median of Two Sorted Arrays[H] 问题介绍 这是个超级超级经典的分治算法!!这个 ...

  6. 堆与堆排序、Top k 问题

     堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先讲解下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树. 二叉堆满 ...

  7. 【leetcode】347. Top K Frequent Elements

    题目地址:https://leetcode.com/problems/top-k-frequent-elements/ 从一个数组中求解出现次数最多的k个元素,本质是top k问题,用堆排序解决. 关 ...

  8. PTA 1014 Waiting in Line (30分) 解题思路及满分代码

    题目 Suppose a bank has N windows open for service. There is a yellow line in front of the windows whi ...

  9. [刷题] 347 Top K Frequent Elements

    要求 给定一个非空数组,返回前k个出现频率最高的元素 示例 [1,1,1,2,2,3], k=2 输出:[1,2] 思路 出队逻辑,普通队列是先进先出,优先队列是按最大/最小值出队 通过堆实现优先队列 ...

随机推荐

  1. 选择标识符(identifier)

    整数通常是标识列最好的选择,因为它们很快并且可以使用auto_increment:千万不要使用enum和set类型作为标识列:尽量避免使用字符串类型作为标识列,因为他们很消耗空间,并且通常比数字类型慢 ...

  2. 使用LAMP创建基于wordpress的个从博客网站 分类: B3_LINUX 2014-07-15 16:45 800人阅读 评论(0) 收藏

    参考: http://blog.csdn.net/ck_boss/article/details/27866117 一.mysql配置 1.安装mysql yum install mysql-serv ...

  3. SpringMVC接受参数若干问题

    最近2年在工作问题总结中,好几次遇到了SpringMVC接收参数的问题,今天特别总结下.  SpringMVC接收参数的方法:  Html参数输入: <input name="stat ...

  4. 【26.8%】【CF 46D】Parking Lot

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  5. web网站如何获取用户的地理位置

    web网站如何获取用户的地理位置 一.总结 一句话总结:通过gps知道用户的经度和纬度,然后通过经度和纬度在在地图(google或者百度)上面显示位置. 1.html5如何通过gps知道用户的经度和纬 ...

  6. 【转】优先队列priority_queue 用法详解

    http://www.cnblogs.com/void/archive/2012/02/01/2335224.html 优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的 ...

  7. SqlBulkCopy 帮助类

    using System;using System.Collections.Generic;using System.Configuration;using System.Data;using Sys ...

  8. 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(5)有趣的指针

    一.指针是C语言的灵魂 # include <stdio.h> int main(){ int *p; //p是变量名,int *表示p变量存放的是int类型变量的地址,p是一个指针变量 ...

  9. D3.js以及通用JS(JavaScript)读取并解析server端JSON的注意事项

    这个需求事实上挺明白的.可是网上搜出来的教程都乱七八糟,认为实在须要自己总结一下. D3.js眼下已经被广泛使用在数据可视化领域,随着大数据的持续发展,这个框架预计会在今后更加流行(据说其作者Mike ...

  10. Mina框架项目运用

    近期最一个项目对通信要求比較严格,须要建立长连接,且能处理多并发,所以选择了Mina框架.以下就简单记录开发的过程吧: mina 开发须要的jar包: mina pc端通信: 服务端: package ...