大数据工程师基础试题

1.在Linux环境下,用Linux基本命令完成如下操作:
1、重命名/home/qqbook/script/下的aa.txt 文件名为:cc.txt ;
2、清空/home/qqbook/script目录下的所有内容。

	参考:
	1、mv /home/qqbook/script/aa.txt /home/qqbook/script/cc.txt

	2、rm -rf /home/qqbook/script/

2.在Linux环境下,用Linux基本命令完成如下操作:
1、切换到/home/qqbook/script目录下 ;
2、在该目录下,查找包含有“feidu”文本内容的所有文件名。

参考:
1、cd /home/qqbook/scrip/
2、find ./ -type f -exec grep feidu {} \;
or find /home/qqbook/scrip/ -type f -exec grep feidu {} \;

3.有两个文件,分别有20亿个QQ号(bigint类型,8字节),我们只有2G内存,如何找到两个文件交集?

参考:【哈希方法精确比较】
步骤1:使用hash函数将第一个文件的所有整数映射到1000个文件中,每个文件有2000万个整数,大约160M内存,内存可以放下,把1000个文件记为 a1,a2,a3.....a1000;
步骤2:用同样的hash函数映射第二个文件到1000个文件中,这1000个文件记为b1,b2,b3......b1000;
步骤3:由于使用的是相同的hash函数,所以两个文件中一样的数字会被分配到文件下标一致的文件中,分别对a1和b1求交集,a2和b2求交集,ai和bi求交集;
步骤4;最后将步骤3的结果汇总,即为两个文件的交集。

4.QQ阅读的阅读行为日志的文件/home/log/aa.txt,占用存储1.5T,在Linux环境下,用Linux基本命令完成如下操作:
1、统计该文件具体有多少行记录;
2、查看第12行到第15行这四行记录。【提示:有非常多种方法:①使用管道;②使用awk;③使用sed。总之请1行搞定。】

参考:
1、wc -l /home/log/aa.txt
 2、如下:
方案一:head -n 15 /home/log/aa.txt | tail -n 4
方案二:sed -n '12,15p'/home/log/aa.txt
方案三:awk 'NR>=12 && NR<=15 {print $0}' /home/log/aa.txt

5.我们知道Kimball的维度建模里面将事实表按粒度划分成了三种主要的事实表,包括:事务事实表,周期快照事实表和累积快照事实表。请问这三种事实表有什么区别?
【提示:可从定义、粒度、用途、事实表更新机制、使用场景等多个角度进行比较】

参考:
定义:
事务事实表
一条记录代表了业务系统中的一个事件。事务出现后,就会在事实中出现一条记录。以订单域举例:下单是一个事实;付款是一个事实;退款是一个事实。
周期快照事实表
记录指定周期内一些聚集事务值或者度量状态。如:库存日快照事实表。
累积快照事实表
用于研究业务过程中各里程碑事件之间的时间间隔,一般会用一个字段记录最后更新时间。如:订单各种状态的开始结束时间。
其他区别:
从用途角度:事务事实表,离散时间点记录事务;周期快照事实表,以规律的间隔产生实施快照;累积快照事实表,时间跨度不确定且不断变化的业务事实。
从时间/日期角度:事务事实表,时间;周期快照事实表,日期;累积快照事实表,时间跨度较短的多个时点。
从粒度角度:事务事实表,每行代表一个事务;周期快照事实表,每个代表一个时间周期内的事实;累积快照事实表,每行代表一个业务周期事务事实。
从事实角度:事务事实表,交易活动;周期快照事实表,时间周期内的绩效;累积快照事实表,限定多个业务阶段内的绩效。
从事实表更新角度:事务事实表,只插入、不更新;周期快照事实表,只插入、不更新;累积快照事实表,新事件产生时更新、可插入、可更新。
……

6.谈谈数据倾斜是如何发生的?并给出优化方案

参考:
1)group by时倾斜
解决方式:hive.groupby.skewindata=true

2)join时倾斜。对于一些热点key,他们所在的reduce运行比较慢。
解决方式:
过滤不正常的记录;
数据去重
使用map join
打开set Hive.optimize.skewjoin = true;

3)无法从sql层面优化时,可以从业务算法角度提升
只读需要的列和分区
周,月任务按天累计计算
先聚合后join

4)reduce任务数不合理导致
set mapred.reduce.tasks=N

5)多维分析带来的低效
当含有rollup和cube语句的from子句中包含子查询或者join时,将子查询或join的结果放到临时表,然后从临时表中读取数据做多维分析

6)业务数据本身存在倾斜
配置参数,优化SQL语句,将数据值较多的数据分散到多个reducer中

7.hdfs存储机制是怎样的?

HDFS存储机制,包括HDFS的写入过程和读取过程两个部分:
1、写入过程:
1)客户端向namenode请求上传文件,namenode检查目标文件是否已存在,父目录是否存在。
2)namenode返回是否可以上传。
3)客户端请求第一个 block上传到哪几个datanode服务器上。
4)namenode返回3个datanode节点,分别为dn1、dn2、dn3。
5)客户端请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成
6)dn1、dn2、dn3逐级应答客户端
7)客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答
8)当一个block传输完成之后,客户端再次请求namenode上传第二个block的服务器。(重复执行3-7步)
2、读取过程:
1)客户端向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址。
2)挑选一台datanode(就近原则,然后随机)服务器,请求读取数据。
3)datanode开始传输数据给客户端(从磁盘里面读取数据放入流,以packet为单位来做校验)。
4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。

8.请列出你所知道的hadoop调度器,并简要说明其工作方法

Fifo schedular:默认,先进先出的原则
Capacity schedular:计算能力调度器,选择占用最小、优先级高的先执行,依此类推。
Fair schedular:公平调度,所有的 job 具有相同的资源。

1.先进先出调度器(FIFO)
Hadoop 中默认的调度器,也是一种批处理调度器。它先按照作业的优先级高低,再按照到达时间的先后选择被执行的作业。
2.容量调度器(Capacity Scheduler)
支持多个队列,每个队列可配置一定的资源量,每个队列采用FIFO调度策略,为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源量进行限定。调度时,首先按以下策略选择一个合适队列:计算每个队列中正在运行的任务数与其应该分得的计算资源之间的比值,选择一个该比值最小的队列;然后按以下策略选择该队列中一个作业:按照作业优先级和提交时间顺序选择,同时考虑用户资源量限制和内存限制。
3.公平调度器(Fair Scheduler)
公平调度是一种赋予作业(job)资源的方法,它的目的是让所有的作业随着时间的推移,都能平均的获取等同的共享资源。所有的 job 具有相同的资源,当单独一个作业在运行时,它将使用整个集群。当有其它作业被提交上来时,系统会将任务(task)空闲资源(container)赋给这些新的作业,以使得每一个作业都大概获取到等量的CPU时间。与Hadoop默认调度器维护一个作业队列不同,这个特性让小作业在合理的时间内完成的同时又不"饿"到消耗较长时间的大作业。公平调度可以和作业优先权搭配使用——优先权像权重一样用作为决定每个作业所能获取的整体计算时间的比例。同计算能力调度器类似,支持多队列多用户,每个队列中的资源量可以配置, 同一队列中的作业公平共享队列中所有资源。
9.Hive中两大表连接,发生了数据倾斜,有一个reduce无法完成,检查发现t1中guid=''的记录有很多,其他guid都不重复,这条语句该怎样优化?
 select t1.*
 ,nvl(t2.x,1)
 from t1
 left join t2
 on t1.guid = t2.guid
参考:
 大表与大表连接,但分桶判断的字段的’’值太多,这些’’值都有一个reducer处理,所以会非常慢。处理方式:将guid字段的’’值的数据打散(加随机数)分布到其他reducer中。
select t1.*,nvl(t2.x,1)
from t1
left join t2
on case when t1.guid='' then concat('hh', rand()) else t1.guid end = t2.guid

10.某种产品中,合格品率为0.96.一个合格品被检查成次品的概率是0.02,一个次品被检查成合格品的概率为0.05.
问题:求一个被检查成合格品的产品确实为合格品的概率.

参考:
先利用全概率公式得P(A) = 0.96*0.98+0.04*0.05
后利用贝叶斯公式得P= (0.98*0.96) /(0.96*0.98+0.04*0.05)= 0.9978

11.有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M,要求返回频数最高的100个词

参考:
1). 顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为f0 ,f1 ,… ,f4999)中,这样每个文件大概是200k左右,如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M;
2). 对每个小文件,统计每个文件中出现的词以及相应的频率(可以采用trie树/hash_map等),并取出出现频率最大的100个词(可以用含100个结点的最小堆),并把100词及相应的频率存入文件,这样又得到了5000个文件;
3). 把这5000个文件进行归并(类似与归并排序);

12.hive 中的压缩格式 RCFile、TextFile、SequenceFile各有什么区别?

参考:
TextFile:Hive默认格式,不作压缩,磁盘及网络开销较大。可以结合Gzip, Bzip2使用,但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
SequenceFile: SequenceFile 是Hadoop API提供支持的一种二进制文件,具有使用方便,可分割,可压缩的特点,支持三种压缩选择:NONE, RECORD, BLOCK。RECORD压缩率低,一般建议使用BLOCK压缩。
RCFILE: RCFILE是一种行列存储相结合的的存储方式。首先,将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩。

13.写出下面各逻辑表达式的值(真:1,假:0)。设 a=3,b=4,c=5。

(1)a+b>c && b==c
(2)a || b+c && b-c
(3)!(a>b) && ! c || 1
(4)!(x=a) && (y=b) && 0
答案:
(1)0
(2)1
(3)1
(4)0

14.hive 内部表和外部表的区别?

未被external修饰的是内部表(managed table),被external修饰的为外部表(external table);
区别:
1.内部表数据由Hive自身管理,外部表数据由HDFS管理;
2.内部表数据存储的位置是hive.metastore.warehouse.dir(默认:/user/hive/warehouse),外部表数据的存储位置由自己指定;
3.删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
4.对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE table_name;)
5.Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。

15.Hive 的 sort by 和 order by 的区别?

参考:
order by 会对输入数据做全局排序,只有一个reduce,数据量较大时,很慢。
sort by 不是全局排序,只能保证每个reduce有序,不能保证全局有序,需设置mapred.reduce.tasks>1。

16.常见的聚类算法可以分为几类?

参考:
聚类分析的算法可以分为划分法、层次法、基于密度的方法、基于网格的方法、基于模型的方法。
1、划分法,给定一个有N个元组或者纪录的数据集,分裂法将构造K个分组,每一个分组就代表一个聚类,K<N。
2、层次法,这种方法对给定的数据集进行层次似的分解,直到某种条件满足为止。
3、基于密度的方法,基于密度的方法与其它方法的一个根本区别是:它不是基于各种各样的距离的,而是基于密度的。这样就能克服基于距离的算法只能发现“类圆形”的聚类的缺点。
4、图论聚类方法解决的第一步是建立与问题相适应的图,图的节点对应于被分析数据的最小单元,图的边(或弧)对应于最小处理单元数据之间的相似性度量。
5、基于网格的方法,这种方法首先将数据空间划分成为有限个单元的网格结构,所有的处理都是以单个的单元为对象的。
6、基于模型的方法,基于模型的方法给每一个聚类假定一个模型,然后去寻找能够很好的满足这个模型的数据集。

17.常见分类算法有哪些?

参考:
1、决策树分类
2、基于规则分类
3、最邻近分类(K-NN)
4、朴素贝叶斯分类器
5、人工神经网络
6、支持向量机(SVM)

18.起点APP每天访问数据存放在表wsd.t_sd_qidain_access_log里面,该表总共有98个字段,其中包含日期字段ds(格式:YYYY-MM-DD,如:2020-01-28),用户类型user_type,用户账号user_id,用户访问时间log_time,请问在2020年2月份里:
【脚本书写整齐很关键!】

1、输出每天每个类型访问的pv,uv,最早访问时间和最晚访问时间;
2、输出每天访问用户数最高的用户类型的top100(按照访问次数降序)用户,输出的字段有:日期,用户类型,用户账号,访问次数

		--仅供参考: 
		--==每天每个类型访问的pv,uv;每天每个类型最早访问时间和最晚访问时间;
		select ds
		,user_type
		,count(1) as pv
		,count(distinct user_id) as uv
		,min(log_time) as min_log_time
		,max(log_time) as max_log_time
		from wsd.t_sd_qidain_access_log
		where ds>='2020-02-01' 
		and ds<'2020-03-01' 
		--=输出每天访问用户数最高的用户类型的top100(按照访问次数降序)用户 
		with aa as ( --输出每天访问用户数最高的用户类型 
		select ds, user_type
		from (
		select ds, user_type
		,row_number() over(partition by ds order by user_uv desc) as rn
		from (
		select ds, user_type, count(distinct user_id) as user_uv
		from wsd.t_sd_qidain_access_log
		where ds>='2020-02-01' 
		and ds<'2020-03-01' 
		group by ds, user_type
		) tt
		) hh
		where rn=1 
		)
		, bb as (
		select t1.ds, t1.user_type, t2.user_id
		from aa t1
		join (
		select ds, user_type, user_id 
		from wsd.t_sd_qidain_access_log
		where ds>='2020-02-01' 
		and ds<'2020-03-01' 
		) t2
		)
		select ds, user_type, user_id 
		from (
		select ds, user_type, user_type
		,row_number() over(partition by ds order by log_cnt desc) as rn
		from (
		select ds, user_type, user_id, count(1) as log_cnt
		from bb
		group by ds, user_type, user_id 
		) tt
		) hh
		where rn<=100 

19.红袖APP付费记录中间表u_wsd.t_od_qidian_pay_hx,该表仅有3个字段,包含日期字段ds(格式:YYYY-MM-DD,如:2020-02-28),用户登录账号qq_no,用户当天的总付费金额hx_amt(单位:分),请问在2020年2月份里:
1、累计总付费金额大于等于100元的用户及其付费总金额并按照付费金额降序排列(只取top100);
2、连续付费4天及以上的用户,同时输出该连续付费的起止日期。输出字段: qq_no, 起始日期,结束日期
【建议:脚本书写整齐很关键!利用with语法子查询,分步骤写清注释】

		--仅供参考: 
		--=累计总付费金额大于等于100元的用户及其付费总金额 
		select qq_no, sum(hx_amt) as hx_amt
		from u_wsd.t_od_qidian_pay_hx
		where ds>='2020-02-01' 
		and ds<'2020-03-01' 
		group by qq_no
		having sum(hx_amt)>=10000 
		order by hx_amt desc 
		limit 100 
		



--=用户登录账号qq_no, 起始日期,结束日期 
		with base as ( --获取2020-02的消费记录,并按照qq_no分组,按照日期升序排序得到row_num 
		select qq_no, ds
		,row_number() over(partition by qq_no order by ds) as row_num
		from u_wsd.t_od_qidian_pay_hx
		where ds>='2020-02-01' 
		and ds<'2020-03-01' 
		)
		, aa as ( --用日期减去其所在的排序值row_num,获取一个"差值"日期,同一个qq_no下该日期相同的则为连续。 
		select qq_no
		,ds
		,row_num
		,date_sub(ds, row_num) as date_rank
		from base
		)
		, res_pre as ( --若连续则"差值"日期的前一天为起始日期,再根据"差值"日期分组按照排序值row_num降序排序为获取结束日期做准备。 
		select qq_no
		,ds
		,date_add(date_rank,1) as start_date 
		,row_number() over(partition by date_rank order by row_num desc) as rn
		from aa
		)
		select qq_no as qq_no
		,start_date as start_date 
		,ds as end_date
		from res_pre
		where rn=1 --获取end_date 
		and datediff(end_date, start_date)>= 3 --连续4天及以上 

20.Hive中表t_od_qqbook_coin_account是用户在QQ阅读看书时的章节订阅明细表,主要有以下字段:statis_day(日期),qq_no(qq号),bookid(书籍id),cid(章节id),fee(该章节订阅费用,单位:分).
表t_rd_qqbook_all_book是书籍属性表(每个分区都是截止当时历史全量数据),主要有以下字段:bookid(书籍id),bookname(书名),two_level(书籍所属二级分类).
请问在2020年1月里:
1、输出每天每本书的阅读人数及其订阅费用(仅保留订阅费用大于10元的记录)并按照订阅费用降序排列;
2、输出每天每个书籍二级分类付费总金额Top5的qq号及对应的金额,输出的字段有:日期、书籍二级分类、qq_no、金额.

		参考:
		--=输出每天每本书的阅读人数及其订阅费用(仅保留订阅费用大于10元的记录)并按照订阅费用降序排列
		select statis_day, bookid
		,count(distinct qq_no) as user_uv
		,sum(fee) as fee
		from t_od_qqbook_coin_account
		where statis_day>=20200101
		and statis_day<20200201
		group by statis_day, bookid
		having sum(fee) > 1000
		order by fee desc 
	

	
		--=输出每天每个书籍二级分类付费总金额Top5的qq号及对应的金额
		with aa as (
		select statis_day, t1.bookid, two_level, fee, qq_no
		from (
		select * from t_od_qqbook_coin_account
		where statis_day>=20200101
		and statis_day<20200201
		) t1
		left outer join (
		select * from t_rd_qqbook_all_book
		where statis_day=20200131
		) t2
		on t1.bookid=t2.bookid
		)
		, bb as (
		select statis_day, two_level, qq_no, fee
		,row_number() over(partition by statis_day, two_level order by fee desc) as rn
		from (
		select statis_day, two_level, qq_no, sum(fee) as fee
		from aa
		group by statis_day, two_level, qq_no
		) tt
		)
		select statis_day, two_level, qq_no, fee
		from bb
		where rn<=5

21.Hive中表t_od_qqbook_coin_account是用户在QQ阅读看书时的章节订阅明细表,主要有以下字段:statis_day(日期),qq_no(qq号),bookid(书籍id),cid(章节id),fee(该章节订阅费用,单位:分).
用户订阅章节时支持多章同时订阅,此时表中的cid会把多个章节id通过连接合并存储。
例如表中,一条订阅流水如下:例如表a中,一条订阅流水如下:20200102,905781969,273561,50
5152535455,10
请问在2020年1月里:
1、输出每天每本书的阅读人数及其订阅费用(仅保留订阅费用大于10元的记录)并按照订阅费用降序排列;
2、输出每天每本书每个章节订阅的人数。

		参考:
		--=输出每天每本书的阅读人数及其订阅费用(仅保留订阅费用大于10元的记录)并按照订阅费用降序排列
		select statis_day, bookid
		,count(distinct qq_no) as user_uv
		,sum(fee) as fee
		from t_od_qqbook_coin_account
		where statis_day>=20200101
		and statis_day<20200201
		group by statis_day, bookid
		having sum(fee) > 1000
		order by fee desc 
		--=每天每本书每个章节订阅的人数
		select 
		statis_day
		,bookid
		,cid
		,count(distinct qq_no)  user_uv
		from (
		select 
		statis_day
		,bookid
		,cid
		,qq_no
		from t_od_qqbook_coin_account
		lateral view explode(split(cid, '\\*')) tt as cid
		where statis_day>=20200101
		and statis_day<20200201
		) tt
		group by statis_day,bookid,cid

22.冒泡排序(Bubble Sort)
算法步骤
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

def bubble_sort(alist):
    """冒泡排序"""
    n = len(alist)
    for j in range(n - 1, 0, -1):
        flag = 0
        for i in range(j):
            if alist[i] > alist[i + 1]:
                alist[i], alist[i + 1] = alist[i + 1], alist[i]
                flag += 1
        if flag == 0:
            break


if __name__ == "__main__":
    data = list(map(int, input().strip().split(',')))
    bubble_sort(data)
    print(data)

23.快速排序
快速排序又是一种分而治之思想在排序算法上的典型应用。
算法步骤
1、从数列中挑出一个元素,称为 “基准”(pivot)。
2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
4、递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

def quick_sort(alist, first, last):
    """快速排序"""
    if first >= last:     # 递归头
        return
    mid_value = alist[first]
    low = first
    high = last
    while low < high:
        while low < high and alist[high] >= mid_value:
            high -= 1
        alist[low] = alist[high]
        while low < high and alist[low] < mid_value:
            low += 1
        alist[high] = alist[low]
    # 从循环退出时,low == high
    alist[low] = mid_value
    # 递归体
    # 对low左边的列表执行快速排序
    quick_sort(alist, first, low-1)
    # 对low右边的列表执行快速排序
    quick_sort(alist, low+1, last)


if __name__ == "__main__":
    data = list(map(int, input().strip().split(',')))
    quick_sort(data, 0, len(data) - 1)
    print(data)
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值