背景:
采用spark读取mongodb和Excel的数据,由于mongodb是bson类型的数据,需要的字段名比较少且按照层级选取,想到的办法是先把数据全部读成df,然后通过select操作查找需要的字段
出现的问题是:
因为将生成特定字段的df封装成函数,而函数本身是需要传入字段名列表(Seq类型)的,而select操作通过看源码接收的参数类型是
col : scala.Predef.String, cols : scala.Predef.String*
类型的,所以需要处理
相关函数
读取Excel的
def readFromExcel(spark: SparkSession, file: String):DataFrame = {
spark.sqlContext.read
.format("com.crealytics.spark.excel")
.option("path", file)
.option("useHeader", "true")
.option("treatEmptyValuesAsNulls", "true")
.option("inferSchema", "true")
.option("addColorColumns", "False")
.option("sheetName", "Sheet1")
.load()
.toDF()
}
其中的file可以放在resource路径下
获取方式为:
val file = this.getClass.getClassLoader.getResource("file.xlsx").getFile
读取mongdb:
def readFromMongo(spark: SparkSession, collection: String, field: Seq[String])(implicit mongoConfig: MongoConfig):DataFrame = {
spark.read
.option("uri", mongoConfig.uri)
.option("collection", collection)
.format("com.mongodb.spark.sql")
.load()
.toDF()
}
其中关于mongodb的配置操作为
在resource下面新建mongodb.properties文件
mongodb.host=127.0.0.1
mongodb.port=27017
mongodb.db=db
然后新建配置类
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class MongoDBUtil {
private String host;
private int port;
private String db;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getDb() {
return db;
}
public MongoDBUtil() {
// 获取配置文件输入流
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("mongodb.properties");
// 配置类
Properties properties = new Properties();
try{
properties.load(inputStream);
this.host = properties.getProperty("mongodb.host");
this.port = Integer.parseInt(properties.getProperty("mongodb.port"));
this.db = properties.getProperty("mongodb.db");
}catch (IOException e){
e.printStackTrace();
}
}
}
在sparksession里面加载mongodb的配置
val mongo = new MongoDBUtil()
val uri = "mongodb://" + mongo.getHost + ":" + mongo.getPort + "/" + mongo.getDb
val config = Map(
"mongo.uri" -> uri,
"mongo.db" -> mongo.getDb
)
implicit val mongoConfig: MongoConfig = MongoConfig(config("mongo.uri"), config("mongo.db"))
最后读成df之后,需要选择特定的字段
val field_list = Seq("_id", "data.field_name")
这里表示field_name和data为父子层级,data与_id为同一层级
操作为
val df= readFromMongo(spark, MONGODB_DC_COLLECTION)
val select_df = df.select(field_list.head, field_list.tail: _*)
如果字段名是字符类型的话,比如'a','b'这些
则
df.select(field_list.map(field.col(_)): _*)