常见大数据面试题汇总带答案

Posted Direction_Wind

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见大数据面试题汇总带答案相关的知识,希望对你有一定的参考价值。

大数据面试题汇总

redis

为什么快
首先,采用了多路复用io阻塞机制
然后,数据结构简单,操作节省时间
最后,运行在内存中,自然速度快
– 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
– 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
– 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
– 使用多路I/O复用模型,非阻塞IO;
– 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

flink(大部分知识点写过的帖子里都有)

interval join不上的数据,怎么处理?怎么做数据修复?
需要匹配join不上的,用cogroup实现
(CoGroup算子:将两个数据流按照key进行group分组,并将数据流按key进行分区的处理,最终合成一个数据流(与join有区别,不管key有没有关联上,都可以合并成一个数据流),只能在window中使用)
或者用flinkSQL的左右外关联

广播变量优势劣势
– 优势:Flink支持广播。可以将一份数据广播到一个TaskManager所有的task ,数据存储到内存中。这样可以减少大量的shuffle操作,而不需要多次传递给集群节点;

– 劣势:广播变量是要把dataset广播到内存中,所以广播的数据量不能太大,否则会出现OOM;广播变量的值不可修改,这样才能确保每个节点获取到的值都是一致的;

mr,java ,集群

hashSet底层去重原理
step1–>存入元素时,先比较要存入的元素的哈希值和集合中元素的哈希值是否一样
step2–>如果要存入的元素哈希值不同直接存入集合
step3–>如果存入元素的哈希值和集合元素的哈希值相同,再调用equals比较属性值,如果属性值相同,就不存入集合,属性值不相同,就存入集合

列存优势 lsm的存储结构和优势
行式存储可以看成是一个行的集合,其中每一行都要求对齐,哪怕某个字段为空(下图中的左半部分),而列式存储则可以看成一个列的集合(下图中的右半部分)。列式存储的优点很明显,主要有以下 4 点:
– 查询时可以只读取涉及的列(选择操作),并且列可以直接作为索引,非常高效,而行式存储则必须读入整行。
– 列式存储的投影操作非常高效。
– 在数据稀疏的情况下,压缩率比行式存储高很多,甚至可以考虑将相关的表进行预先连接,来完全避免投影操作。
– 因为可以直接作用于某一列上,聚合分析非常迅速。
– 行式存储一般擅长的是插入与更新操作,而列式存储一般适用于数据为只读的场景。对于结构化数据,列式存储并不陌生。因此,列式存储技术经常用于传统数据仓库中。
– lsm树 日志追加append的方式写入,会存几个副本 hbase就是,天生适合写多读少的场景, 会先写入 后合并,所以写入效率非常高,删除也是内存里先标记,后面异步合并操作才会真正的删除数据,效率高

MR提交流程 shuffle的过程? 哪些算子会产生shuffle?
https://@note.youdao.@com/s/@PcTseRlE

java线程池的实现原理

算法题

请你找出其中不含有重复字符的 最长子串 的长度?

public static int lengthOfLongestSubstring(String s) 
  if (s == null || "".equals(s)) 
        return 0;
    
    int n = s.length();
    Map<Character, Integer> map = new HashMap<>(16);
    int maxLength = 0;
    for (int i = 0,j = 0; j < n; j++) 
        if (map.containsKey(s.charAt(j))) 
            i = Math.max(map.get(s.charAt(j)), i);
        
        maxLength = Math.max(maxLength, j - i + 1);
        map.put(s.charAt(j), j + 1);
    
    return maxLength;



public static int lengthOfLongestSubstring(String s) 
    if (s == null || "".equals(s)) 
        return 0;
    
    List<Character> list = new ArrayList<>();
    int n = s.length();
    int maxLength = 0;
    for (int i = 0; i < n; i++) 
        int index = list.indexOf(s.charAt(i));
        if (index == -1) 
            list.add(s.charAt(i));
            maxLength = Math.max(list.size(), maxLength);
         else 
            for (int j = index; j >= 0; j--) 
                list.remove(j);
            
            list.add(s.charAt(i));
        
    
    return maxLength;

微信红包
还是以10元10个红包为例,随机10个数,红包金额公式为:红包总额 * 随机数/随机数总和,假设10个随机数为[5,9,8,7,6,5,4,3,2,1],10个随机数总和为50,

第一个红包105/50,得1元。
第二个红包10
9/50,得1.8元。
第三个红包10*8/50,得1.6元。
以此类推。

写个快排

package Launcher;


import java.util.Arrays;

public class QuickSort 

    public static int partition(int[] array, int low, int high) 
        // 取最后一个元素作为中心元素
        int pivot = array[high];
        // 定义指向比中心元素大的指针,首先指向第一个元素
        int pointer = low;
        // 遍历数组中的所有元素,将比中心元素大的放在右边,比中心元素小的放在左边
        for (int i = low; i < high; i++) 
            if (array[i] <= pivot) 
                // 将比中心元素小的元素和指针指向的元素交换位置
                // 如果第一个元素比中心元素小,这里就是自己和自己交换位置,指针和索引都向下一位移动
                // 如果元素比中心元素大,索引向下移动,指针指向这个较大的元素,直到找到比中心元素小的元素,并交换位置,指针向下移动
                int temp = array[i];
                array[i] = array[pointer];
                array[pointer] = temp;
                pointer++;
            
            System.out.println(Arrays.toString(array));
        
        // 将中心元素和指针指向的元素交换位置
        int temp = array[pointer ];
        array[pointer] = array[high];
        array[high] = temp;
        return pointer;
    

    public static void quickSort(int[] array, int low, int high) 
        if (low < high) 
            // 获取划分子数组的位置
            int position = partition(array, low, high);
            // 左子数组递归调用
            quickSort(array, low, position -1);
            // 右子数组递归调用
            quickSort(array, position + 1, high);
        
    

    public static void main(String[] args) 
        int[] array = 6,72,113,11,23;
        quickSort(array, 0, array.length -1);
        System.out.println("排序后的结果");
        System.out.println(Arrays.toString(array));
    


kafka


kafka offset在一个名为 __consumer_offsets 的Topic中

kafka的ISR机制 副本同步机制 保证数据准确性
— 首先我们知道kafka 的数据是多副本的,某个topic的replication-factor为N且N大于1时,每个Partition都会有N个副本(Replica)。kafka的replica包含leader与follower。每个topic 下的每个分区下都有一个leader 和(N-1)个follower,
—每个follower 的数据都是同步leader的 这里需要注意 是follower 主动拉取leader 的数据
---- Replica的个数小于等于Broker的个数,也就是说,对于每个Partition而言,每个Broker上最多只会有一个Replica,因此可以使用Broker id 指定Partition的Replica
http@s://www.c@nblogs.com/@zzzzrrrr/p/13197390.html

Kafka 并不支持主写从读(读写分离),这是为什么呢?
1.kafka的follower与leader会有延时,不好解决
2.kafka写多读也多,不太适合
3.之后支持读写分离,为了解决跨数据中心消费的问题(就是机器不在一个地儿,带宽不够),才搞得读写分离。

kafka保证分区内顺序
设置一个分区
生产时指定分区;生产时用相同的key

维度建模分为哪几种?

https:/@/www.csdn.net/tags/NtT@aUg2sNTYx@MzMtYmxvZwO0O0OO0O0O.html
星型 : 事实表+维度
雪花 :事实表+维度-维度
星座:事实+维度+事实+维度

SQL高频面试题

刷题网站:https://www.nowcoder.com/exam/oj?page=1&tab=SQL%E7%AF%87&topicId=268

sql面试题:求连续最大登录天数
连续签到领金币:https://www.nowcoder.com/practice/aef5adcef574468c82659e8911bb297f?tpId=268&tqId=2285347&ru=/exam/oj&qru=/ta/sql-factory-interview/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DSQL%25E7%25AF%2587%26topicId%3D268

连续签到领金币 7天一周期 37天 多领 计算总领的金币
WITH t1 AS( -- t1表筛选出活动期间内的数据,并且为了防止一天有多次签到活动,distinct 去重
	SELECT
		DISTINCT uid,
		DATE(in_time) dt,
		DENSE_RANK() over(PARTITION BY uid ORDER BY DATE(in_time)) rn -- 编号
	FROM
		tb_user_log
	WHERE
		DATE(in_time) BETWEEN '2021-07-07' AND '2021-10-31' AND artical_id = 0 AND sign_in = 1
),
t2 AS (
	SELECT
	*,
	DATE_SUB(dt,INTERVAL rn day) dt_tmp, 
	case DENSE_RANK() over(PARTITION BY DATE_SUB(dt,INTERVAL rn day),uid ORDER BY dt )%7 -- 再次编号
		WHEN 3 THEN 3
		WHEN 0 THEN 7
		ELSE 1
	END as day_coin -- 用户当天签到时应该获得的金币数
	FROM
	t1
)
	SELECT
		uid,DATE_FORMAT(dt,'%Y%m') `month`, sum(day_coin) coin  -- 总金币数
	FROM
		t2
	GROUP BY
		uid,DATE_FORMAT(dt,'%Y%m')
	ORDER BY
		DATE_FORMAT(dt,'%Y%m'),uid;

sql:表名:test,字段(user_id1,user_id2,time)求这个表里,互相关注的用户有多少?

select 
  a.from_user,
  a.to_user,
  if( sum(1) over (partition by feature) > 1, 1, 0) as is_friend
from 
(
  select 
    a.from_user,
    a.to_user,
    if(from_user > to_user, concat(to_user, from_user), concat(from_user, to_user)) as feature
  from table_relation 
)a

hbase

写入过程
1)客户端处理阶段:客户端将用户的写入请求进行预处理,并根据集群元数据定位写入数据所在的RegionServer,将请求发送给对应的RegionServer。
2)Region写入阶段:RegionServer接收到写入请求之后将数据解析出来,首先写入WAL,再写入对应Region列簇的MemStore。
3)MemStore Flush阶段:当Region中MemStore容量超过一定阈值,系统会异步执行flush操作,将内存中的数据写入文件,形成HFile。
注意:用户写入请求在完成Region MemStore的写入之后就会返回成功。MemStore Flush是一个异步执行的过程。

RowKey设计原则
– 1.Rowkey的唯一原则
– 2.Rowkey的排序原则:HBase的Rowkey是按照ASCII有序设计的,我们在设计Rowkey时要充分利用这点。
– 3.Rowkey的散列原则 也就是热点问题,经常与2冲突。

热点问题:
– 1.Reverse反转
针对固定长度的Rowkey反转后存储,这样可以使Rowkey中经常改变的部分放在最前面,可以有效的随机Rowkey。
– 2.Salt是将每一个Rowkey加一个前缀,前缀使用一些随机字符,使得数据分散在多个不同的Region,达到Region负载均衡的目标。
– 3.rowkey做hash

高可用原理

jvm

1、JVM 主要组成部分

1、类加载器(ClassLoader)

2、运行时数据区(Runtime Data Area)

3、执行引擎(Execution Engine)

4、本地库接口(Native Interface)

2、组件的作用
首先,通过类加载器(ClassLoader)会把 Java 代码转换成字节码;

其次,运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行;

于是,需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行;

最后,此过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能

mysql

联合索引机制:
– 遵守最左前缀匹配原则,检索数据时从联合索引的最左边开始匹配,直到遇到范围查询就停止匹配。
– 本质上联合索引也是一个 B+树,和单列索引不同的是,联合索引的键值不是一个,而是大于 1 个。建立联合索引的时候,B+树只能选择一个字段构建有序的树,默认是第一个字段,即最左边的字段,只有当第一个字段的值是相同的,才会按照第二个字段的值进行排序,即先确定第一个字段有序,才会匹配第二个字段
– 对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找

4.mysql的主从节点数据复制机制,可以开启主从双写吗?会有什么问题?
不可以,MySQL 默认采用异步复制方 双写会有重复吧,
本来读写分离,现在双写,就不分离了

sql递归

WITH CTE AS(
 SELECT 部门ID,父级ID,部门名称,部门名称 AS 父级部门名称
 FROM Company
 WHERE 父级ID=-1
 UNION ALL
 SELECT c.部门ID,c.父级ID,c.部门名称,p.部门名称 AS 父级部门名称
 FROM CTE P
 INNER JOIN Company c ON p.部门ID=c.父级ID
)
 
SELECT 部门ID,父级ID,部门名称,父级部门名称
FROM CTE

hive

reduceByKey和groupByKey:
reduceByKey在分区内会进行预聚合,而后再将所有分区的数据按照关键字来分组聚合。
而groupByKey则不会先进行预聚合,它直接将所有分区的数据一起分组,如果要再进行聚合,则groupByKey还需要使用其他函数,比如sum()

大小表数据倾斜,用MAPjoin 原理 :
join本来是reduce进行关联查找,改成了map端进行关联查找
适用于大表join小表,使用DistributedCache机制将小表存储到各个Mapper进程所在机器的磁盘空间上,各个Mapper进程读取不同的大表分片,将分片中的每一条记录与小表中所有记录进行合并
合并后直接输出map结果即可得到最终结果。
注:不需要进行shuffle流程,也不需要reduce处理

distinct 和 group by有什么区别?在哪种情况下使用group by性能会更优?
--------仅仅从查询的作用角度看:
distinct 和 group by 都可以用来去重
不同之处,distinct 是针对要查询的全部字段去重,而 group by 可以针对要查询的全部字段中的部分字段去重,它的作用主要是:获取数据表中以分组字段为依据的其他统计数据。
-------- 从性能角度看:
两者执行方式不同,distinct主要是对数据两两进行比较,需要遍历整个表。group by分组类似先建立索引再查索引,当数据量较大时,group by速度要优于distinct。

hive的执行流程
客户端提交到接口 ,解析 校验 优化 执行,mr任务关联元数据库

解释一下hive 的 skew join?
set hive.optimize.skewjoin = true;
开启后,在运行时,会对数据进行扫描并检测哪个key会出现倾斜,对于会倾斜的key,用map join做处理,不倾斜的key正常处理。

hive 几种join
内连接 ,左右外联 ,全连接 ,笛卡尔积,(mapjoin ,skew join 是开启配置 实现 shuffle前对数据分配,另一个是应对数据倾斜的)

hive 行转列列转行
多行转一列:一般用case when,再做一个group by 去掉0值。
一行转多列:lateral view

select t.gameId, singleTag
from (
select gameId, tags from gamepublish.knights_game where date=20181127 limit 20
) t LATERAL VIEW explode(t.tags) v as singleTag


应该case when sum group by name
列转行:concat_ws

distinct 和 group by
在语义相同,有索引的情况下
group by和distinct都能使用索引,效率相同。
在语义相同,无索引的情况下:
distinct效率高于group by。原因是distinct 和 group by都会进行分组操作,但group by可能会进行排序,触发filesort,导致sql执行效率低下。

以上是关于常见大数据面试题汇总带答案的主要内容,如果未能解决你的问题,请参考以下文章

2021最全大数据面试题汇总---hadoop篇,附答案!

Android面试题及答案整理(2022年最新Android面试题大全带答案)

2021 大厂大数据高频面试题汇总+答案详解

最常见的Java面试题及答案汇总

高级前端面试题大汇总(只有试题,没有答案)

2020最常见的200+Java面试题汇总(含答案解析)