一道来自大厂的真实大数据开发岗位面试题
问题:对一个文本文档进行词频统计并对统计结果按单词字典顺序进行排序,要求使用MapReduce、Linux、Java、Hive、Spark、Flink六种方式实现
第一种方式:用MapReduce实现(略)
第二种方式:使用Linux Shell命令行实现
思路: 多个Linux命令用管道连接实现词频统计和排序(管道的本质是文件)
答案:cat words.txt | tr -s " " "\n" | sort | uniq -c | awk '{print $2,$1}'
解析:
第1步:cat words.txt
显示文件words.txt内容
[root@hadoop ~]# cat words.txt
hadoop spark flink
linux java scala hadoop
hadoop spark storm
spark spark spark
hbase kafka flink hive
flink sql spark hadoop
第2步:cat words.txt | tr -s " " "\n"
tr -s命令作用:将文本文件中连续出现的1到多个空格符替换为换行符,实现“一个单词占一行”
[root@hadoop ~]# cat words.txt | tr -s " " "\n"
hadoop
spark
flink
linux
java
scala
hadoop
hadoop
spark
storm
spark
spark
spark
hbase
kafka
flink
hive
flink
sql
spark
hadoop
第3步:cat words.txt | tr -s " " "\n" | sort
sort命令作用:将文本文件内容以行为单位进行默认正序排序
[root@hadoop ~]# cat words.txt | tr -s " " "\n" | sort
flink
flink
flink
hadoop
hadoop
hadoop
hadoop
hbase
hive
java
kafka
linux
scala
spark
spark
spark
spark
spark
spark
sql
storm
第4步:cat words.txt | tr -s " " "\n" | sort | uniq -c
uniq -c命令作用:删除文本文件中重复的行,只保留一行,-c参数在每行左边显示重复的次数
[root@hadoop ~]# cat words.txt | tr -s " " "\n" | sort | uniq -c
3 flink
4 hadoop
1 hbase
1 hive
1 java
1 kafka
1 linux
1 scala
6 spark
1 sql
1 storm
第5步:cat words.txt | tr -s " " "\n" | sort | uniq -c | awk '{print $2,$1}'
awk '{print $2,$1}'命令作用:将文文文件按空格分割成多个列,输出第2列和第1列
[root@hadoop ~]# cat words.txt | tr -s " " "\n" | sort | uniq -c | awk '{print $2,$1}'
flink 3
hadoop 4
hbase 1
hive 1
java 1
kafka 1
linux 1
scala 1
spark 6
sql 1
storm 1
第三种方式:使用纯Java自带类库编程实现
要求:不允许使用任何框架和第三方实现类,如分布式计算框架MapReduce;
思路: 在本地磁盘下创建一个名称为words.txt的文本文件,用Java自带类库编程实现词频统计和排序,理解TreeMap和HashMap的区别
源码:
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.io.FileInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
public class WordCount
{
public static void main(String[] args)
{
String str = "";
//1.通过一个Map集合类,以键值对的方式去存储单词和出现的次数
Map map = new HashMap();
try
{
//2.定义一个文件字节读取流对象,去读取磁盘中的文件
FileInputStream fileInputStream = new FileInputStream("D:\\wordcount.txt");
//3.创建InputStreamReader对象,将字节流转换为字符流
//创建一个BufferedReader的缓冲流对象,将字符流对象放入进去,提高读取的效率
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String temp = "";
try
{
while ((temp = bufferedReader.readLine()) != null) //从BufferReader中读取下一行不为null
{
str = str + temp;//将读取到的文件每行内容拼接到字符串中
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
//System.out.println(str);
//4.创建一个spilt数组来分割字符串,用于统计单词出现的次数
String [] spilt = str.split(" ");
for (int i = 0; i存储在map集合中
}
else
{
int frequency = map.get(spilt[i]);//如果key存在,就获得key对应的value值
map.put(spilt[i], ++frequency);//value值加1,覆盖原有的,实现词频统计
}
}
//遍历输出HashMap的键值对
// Iterator iter = map.entrySet().iterator();
// while (iter.hasNext())
// {
// Map.Entry entry = (Map.Entry) iter.next();
// Object key = entry.getKey();
// Object value = entry.getValue();
// System.out.println("<" + key + "," + value + ">");
// }
//5.利用TreeMap实现Comparator接口,对Map集合进行排序
Comparator> comparator = new Comparator>()
{
public int compare(Map.Entry o1, Map.Entry o2)
{
return(o1.getKey().compareTo(o2.getKey()));//按单词字典序升序排序
//// return(o2.getKey().compareTo(o1.getKey()));//按单词字典序降序排序
//// return o1.getValue()-o2.getValue();//按照词频升序排序
//// return o2.getValue()-o1.getValue();//按照词频降序排序
}
};
//map转换成list进行排序;Entry是Map中的一个静态内部类,用来表示Map中的每个键值对;map.EntrySet()方法实现了Set接口,里面存放的是键值对.
List> list = new ArrayList>(map.entrySet());
// 6.执行排序
Collections.sort(list, comparator);
// 7.打印输出排序结果,默认情况下TreeMap按key进行升序排序
for (Map.Entry entry : list)
{
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
第四种方式:用Hive SQL实现
关系数据库SQL实现:select word ,count(*) as value from table group by word order by value
Hive SQL实现:select key ,count(*) as value from (select explode(split(line,"\\s+")) as key from wordcount) wc group by key order by value desc;
需要掌握Hive SQL常用函数:split,explode
第五种方式:用Spark内存计算框架实现
实现思路:利用Spark数据集RDD,使用对RDD进行操作的算子(方法)来实现MapReduce (map和reduce),编程语言采用scala,Spark 的transformation算子是惰性加载,action算子执行时才会加载
scala编程实现: lines.flatMap(_.split("\\s+")).map((_,1)).reduceByKey(_+_).sortBy(_._2,false).collect().foreach(println)
第六种方式:当前最先进的实时计算框架Flink实现(今后大数据职业生涯需要扩展学习,学无止境!)
深入思考:
这道面试题看似简单,但实际不简单;题目由基础到深入,先考察Linux,Java, SQL等计算机专业基础能力,再深入到大数据技术能力,如对分布式计算框架MapReduce、Spark和Flink,数据仓库工具Hive的掌握;从中看出,想进入大数据行业成为大数据开发工程师,基础非常重要,大厂主要考察面试者对基础知识的理解和掌握程度;学习大数据的基础必须牢固掌握Java,数据库SQL语句和Linux操作,一定要重视专业基础课程的学习,学习大数据先要打牢基础,根基不稳,寸步难行!