暑假前初步学习了一些大数据工具并实现了一个数据展示的demo。这是我对自己体验的东西的一些总结。
当然我不是再复述一遍什么大数据框架的介绍啊,用途啊什么的,那太没意思了。只是写一下自己的感想
而且很多像废话
基础环境
大数据很多框架迄今为止依旧构建在在jre1.8之上,切换成更新的jre版本会有很多问题。出于这个原因我在整个学习过程中使用的是OpenJDK 1.8。况且我确实遇到了这个情况,将最新版的HADOOP的运行环境由1.8修改为17,在运行过程中能运行,但是只能运行一点点,有些api会报一些比较神奇的错误,而我Java开发资历尚浅,尚不能理解为什么。所以我又切回1.8了。
hadoop
学习HDFS时,了解到这个FS的实现是和宿主机上的文件系统分离的。运行HDFS程序的宿主机上的文件系统对一般应用(不针对宿主机文件系统设计的程序)来说是不可见的,实际上操作系统会对一般应用屏蔽FS的细节和特殊操作而只保留最简单的文件读写等API,所以HDFS可以在很多文件系统上运行(或者是所有能被kernel支持的文件系统?),比如ext4、btrfs、ntfs等。和他们并不是并列关系。
对于Hadoop的环境配置,其实我有很多想不明白的地方,比如我在帮别人解决问题的时候确实遇到了配置JAVA_HOME
的环境变量但是在使用start-dfs.sh
时不能正常启动,依旧报错找不到环境变量。由于我当时直接在hadoop-env.sh
的文件中配置了JAVA_HOME
(毕竟是物理机,不想污染环境变量,而且用的是滚动更新的fedora发行版,使用包管理器安装的JDK版本过新)。
flume
仅限于搭建了一个可以接受telnet数据并转发给kafka,没有深学。据说主要用于日志文件等的采集,但是我没那个环境就放弃了。希望以后我能具体应用。
spark
虽然MapReduce很好用,但是由于MR会将中间结果储存在磁盘,在某些场景下的计算的瓶颈可能是存储在磁盘时的IO瓶颈,所以有了spark,将中间结果存储到内存。
对于仅将spark用来计算,我认为还是应该使用pyspark在python上进行编程,更加简单易用。而不是像我这样使用scala来应付作业而临时学一下,python真的很舒服。
针对scala的spark包似乎还挑打包版本,比如2.12编译的spark用scala2.12和对应版本的spark包出错比较少?水平太低无法分析。
scala2
因为这次学习严格意义上算实训,需要写作业,作业一部分要求scala语言操作spark,所以我不得不学习Scala2的语言,其中出现了很多令我费解的问题,比如圆括号传下标的List,取item用类似调用对象属性的tuple(它甚至从1个参数到22个参数写了整整几十个不同的类名,就感觉设计很神奇)。没有深学scala,只学了一周,学了之后也没再继续使用,所以很多问题无法解决。但是在使用scala的过程中自认为很好地学习了流式编程的思想至少我感觉写出来的代码挺漂亮的
说实话,scala2很多语法初看非常理解不能,再看也是理解不能,但是多少了解后进行实践才知道,某些语法是很好用的语法糖,比如scala2中某些函数在调用时是不加括号的,非常反直觉,毕竟这时候他就很像一个成员变量而不是成员方法了。写了之后发现大概还行?以及各种语句的简化写法,条件语句的返回值,模式匹配的守卫黑魔法等等。
scala很多东西意思差不多,但是就是换了个名词,也算是多少能了解到一点新单词吧。比如traits
啊case class
啊什么的,现在看虽然还是一些学别的语言就接触过东西,但是换了个名字确实让我苦恼了一阵子。
org.apache.spark
由于spark和scala2都不熟导致在scala利用spark进行计算的过程成了跑不起来重灾区。依托于IDEA的超超超智能提示,得以最终跑通。
在使用1.8的jdk作为底层编译环境(不知道怎么形容)的scala2.12尝试连接远程的spark master时出现一个神奇问题:java.lang.ClassCaseException
,反正就是不能使用lambda表达式,甚至scala函数也不能直接用,至今不知道怎么解决。虽然StackOverflow提供了一个问答,答案阐述了这个问题如何发生,但是我没找到一个简单的解决方法。询问老师得知一般不像我这么用,而是本地编写逻辑并进行正确性验证最后打包为jar由spark-submit
运行。但是我还是不知道怎么解决。水平还是够。
在切换底层到openjdk 17
出现一个新的问题,cannot access class sun.nio.ch.DirectBuffer
,这是解决方案。
接下来到了使用spark开发的过程。有一个很正常的需求,我需要对读入的文本每行字符串进行split。对身为dataframe对象的数据对象,我使用map,它接受一个参数为Row
的lambda表达式,而且这个Row
大概一个类似数组的玩意。如果我直接返回split后的字符串数组,下次流式编程的函数处理的对象就变成了一个Row
,其中有一个元素,这个元素是分割后的string数组。并没有将列修改。页不能直接返回ArryBuffer
什么的。最后不知道从哪里搜索得知可以返回case class
和tuple
来替换Row
这个很像数组的对象中的元素。例如
1 |
|
以及
1 |
|
我也不知道有没有什么更简单的方法来解决这个问题。case class
和tuple
都有类似属性名的东西来标识这个对象持有的数据,而在使用dataframe的toDF()不提供参数时,列名则和这些属性名相同,所以我认为或许只能这么用了。
学了一个半星期的scala和spark这套东西感觉磕绊很多,或许我应该直接使用pyspark或者scala3?
这是这一阵子的总结,在这期间为了理解scla的语法糖我还简单入门了一下kotlin,然后竟然真的理解了一部分scala语法糖设计。