Spark、MongoDB技术分享
注:本文初始写于2021年9月26日22时40分,当时用于公司内部技术分享,现整理至博客,供大家交流学习
文章目录
一、目标
1、了解Spark
、MongoDB
的基本概念
2、了解如何自定义
改造源码
3、了解UUID
基本概念及其进制转换
二、概述
1、Spark
概念:加州大学伯克利分校AMP
实验室(Algorithms, Machines, and People Lab
)开发通用内存并行计算框架。(简述:把数据放在内存中进行计算的框架)
2、MongoDB驱动包
概念:MongoDB
官方提供的连接器给Spark
和MongoDB
作为连接桥梁。(简述:连接Mongo
数据库的一个jar
包,可以与spark
协同工作)
3、UUID
概念:是Universally Unique Identifier
的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符,是一个128bit
的数字,也可以表现为32
个16进制
的字符,中间用”-”分割。(简述:128
位的标识符,具有唯一性)
三、背景
SparkMongo
处理MongoDB
的数据不符合GVP
(公司内部的产品简称)的业务需求。
场景一
BJSON
中Array
为空时,SparkMongo
会自动忽略该字段的schema
,业务需求为空时,就是空。
修改代码前:
注:下列的
schema
中没有orderBys
,joinNodes
字段,通俗的讲把我们的想要的信息丢掉了
root
|-- _id: struct (nullable = true)
|-- columns: array (nullable = true)
|-- groupBys: array (nullable = true)
|-- metaData: array (nullable = true)
|-- options: struct (nullable = true)
|-- paging: struct (nullable = true)
|-- pivotQuery: struct (nullable = true)
|-- widgetId: string (nullable = true)
修改代码后:
注:新增的这两列中都是空
array
root
|-- _id: struct (nullable = true)
|-- columns: string (nullable = true)
|-- groupBys: string (nullable = true)
|-- joinNodes: string (nullable = true) #新增
|-- metaData: string (nullable = true)
|-- options: struct (nullable = true)
|-- orderBys: string (nullable = true) #新增
|-- paging: struct (nullable = true)
|-- pivotQuery: struct (nullable = true)
|-- widgetId: string (nullable = true)
最终产品展示图:
场景二
- BJSON中Timestamp/uuid/luuid/md5等类型为结构化类型,不符合业务需求;业务需求是产品数据为数据库中显示的值。
修改代码前:
修改代码后:
最终产品效果图:
四、如何修改
1、分析、定位代码
- 时序图
- 脑图
MongoInferSchema
:获取schema
,映射数据库与代码的数据库类型,通俗的说这个文件是目标修改文件之一
MapFunctions
:从数据库中得到的数据转化为代码中的数据,通俗的说这个文件也是目标修改文件之一
MongoSpark
:MongoInferSchema
、MongoRelation
的入口文件
MongoRelation
:MapFunctions
的入口文件
2、是否一定要修改?
是否一定要修改,这个一定要慎重考虑。
- 必须要修改
- 可以修改但非必须
前者,再思考一个问题,如何最小改动源码?n个问题,可能只有1个必须要修改的,n-1非必须修改的。
注:因为当修改源码可以解决问题时,再遇到问题,可能还会去修改源码,思维定式,陷入一个误区。
3、建包
为什么要建包?因为有很多类以及方法,只在同包名才能使用或指定包名下使用。也可以理解最真实的去模拟源码的编码环境。
4、新建文件,copy源码
先创建需要修改的文件,然后把源代码copy下来(因为scala的object不支持继承使用,所以都是用的copy方法);从需要修改的文件到入口文件都要新建文件然后copy。scala的类也是支持继承的,具体情况具体使用。
5、修改关键代码
注意:修改代码的影响范围
6、删除多余代码,保留关键需要的代码
在copy的过程中有很多的代码是没有被用到的,从入口文件到需要修改的文件,一点点删除。删除方法:点击类中的方法查看是否被使用,没有就直接删除。
五、拓展
1、UUID
在源码中的处理过程(17
=0001
0001
=11
)
def byte16ToString(array: Array[Byte]): StringBuffer = {
val stringBuffer = new StringBuffer()
array.foreach(x => {
var hexStr = Integer.toHexString(x).replace("ffffff", "")
//如果十进制为0~15,那么对应的十六进制是00、01、...、0f,Integer.toHexString(x)转化出来的就只有一位字符,不符合预期两位字符
if (hexStr.length == 1) {
hexStr = "0" + hexStr
}
stringBuffer.append(hexStr)
})
stringBuffer
}
2、如果找不到源码包,如何找到源码?答:使用 jdgui
工具进行反编译,百度教程很全;经过测试,jdgui
可以反编译java,但是不能反编译scala。