操作Spark-SQL的两种方式:API和SQL
使用sparkSQL处理数据的“套路”:
- 读取数据,使用适当的分隔符,转为带列名的DataFrame。
- 将DF注册成临时表。
- 通过API或SQL方式清洗数据。
- 输出数据。
object LogApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().master("local[2]").appName("LogApp").getOrCreate()
import spark.implicits._ //添加这个才能在DF/DS上使用map等操作。
val df = spark.read.textFile("data/access.log")
.map(x => {
val splits = x.split("\t")
val user = splits(0)
val platform = splits(1)
val traffic = splits(4).toInt
(user, platform, traffic)
}).toDF("user", "platform", "traffic") //DS转 DF
// 如果你想使用SQL来进行处理,那么就是将df注册成一个临时视图
df.createOrReplaceTempView("log")
//使用sql的方式
val sql = "select platform, user, sum(traffic) as traffics from log group by platform, user order by traffics desc"
spark.sql(sql).show()
//使用API的方式,必须导入下面这个包
import org.apache.spark.sql.functions._
df.groupBy("platform", "user")
.agg(sum("traffic").as("traffics"))
.sort('traffics.desc).show()
spark.stop()
}
}
Catalog的使用
spark2.0才有catalog,使用catalog操作Hive元数据。
作用:方便读取hive表元数据,不用连接JDBC
object CatalogApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.master("local[2]")
.appName("CatalogApp")
.enableHiveSupport() //连接到hive一定要开启这个
.getOrCreate()
//也可在spark-shell中执行以下语句
val catalog = spark.catalog
catalog.listDatabases().show(false)
catalog.listFunctions().show(false)
catalog.listTables("test_db").show(false)
catalog.listColumns("test_db.test").show(false)
spark.stop()
}
}
DF ==> DS
RDD vs DataSet vs DataFrame ==> DF/DS = RDD + Schema
object DSApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.master("local")
.appName("DSApp")
.getOrCreate()
import spark.implicits._
val df = spark.read.option("header", "true") //这里如果在csv第一行有属性的话,没有就是"false"
.option("inferSchema", "true") //这是自动推断属性列的数据类型。
//.option("sep", ",") //指定分隔符,默认逗号
.csv("data/sales.csv")
df.printSchema()
df.show()
val ds = df.as[Sales]
ds.printSchema()
ds.show()
// ROW DF弱类型
// RDD vs DS vs DF ==> DF/DS = RDD + Schema
df.select("transactionId", "customerId").show(false)
ds.select("transactionId", "amountPaid").show(false)
ds.map(x=>(x.amountPaid,x.transactionId)).show(false) //map操作没有列信息。即没有Schema
spark.stop()
}
case class Sales(transactionId: Int, customerId: Int, itemId: Int, amountPaid: Double)
}
DataFrame的两种创建方式
- 写case class
- 定义StructType
object RDDApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.master("local")
.appName("RDDApp")
.getOrCreate()
import spark.implicits._
// RDD ==> DF/DS
//方式一:写case class
val peopleDF = spark.sparkContext
.textFile("data/people.txt")
.map(_.split(","))
.map(x => Person(x(0), x(1).trim.toInt))
//.toDS()
.toDF()
peopleDF.show(false)
//方式二:定义StructType
// step1: Create an RDD
val peopleRDD = spark.sparkContext.textFile("data/people.txt")
// Convert records of the RDD (people) to Rows
val rowRDD = peopleRDD
.map(_.split(","))
.map(attributes => Row(attributes(0), attributes(1).trim.toInt))
// step2: The schema is encoded in a string
val schema = StructType(Array(
StructField("name2", StringType),
StructField("age2", IntegerType)
))
// step3: Apply the schema to the RDD
val peopleDF2 = spark.createDataFrame(rowRDD, schema)
peopleDF2.show()
//TODO... 业务逻辑
spark.stop()
}
case class Person(name: String, age: Int)
}
自定义UDF
object UDFApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.master("local")
.appName("UDFApp")
.getOrCreate()
import spark.implicits._
/**
* step1: 定义 注册
* step2: 使用
*/
val df = spark.sparkContext.textFile("data/udf.txt")
.map(_.split("\t"))
.map(x => UDFtext(x(0), x(1), x(2).toInt))
.toDF()
df.createOrReplaceTempView("teams")
/**
* 根据年龄大小返回是否成年 成年:true,未成年:false
*/
def Adult(age: Int) = {
if (age < 18) {
false
} else {
true
}
}
val isAdult: UserDefinedFunction = spark.udf.register("isAdult2", Adult _) //注册自定义函数(通过实名函数)
val teams_length: UserDefinedFunction = spark.udf.register("teams_length2", (input: String) => { //注册自定义函数(通过匿名函数)
input.split(",").length
})
//通过sql方式调用UDF,只能使用定义在内部的函数名,如isAdult2、teams_length2
spark.sql("select name, teams, age, teams_length2(teams) B, isAdult2(age) A from teams").show()
//通过API方式调用UDF
//通过withColumn添加列
df.withColumn("A", isAdult(df.col("age")))
.withColumn("B", teams_length(df.col("teams"))).show
//通过select添加列
df.select(df.col("*"),
isAdult(df.col("age")).as("A"),
teams_length(df.col("teams")) as "B").show
//可通过withColumn实现增加一列或者替换一个已存在的列,它会先判断DataFrame里有没有这个列名,
//如果有的话就会替换掉原来的列,没有的话就用调用select方法增加一列,所以如果我们的需求是增加一列的话,两者实现的功能一样,
//且最终都是调用select方法,但是withColumn会提前做一些判断处理,所以withColumn的性能不如select好。
spark.stop()
}
case class UDFtext(name: String, teams: String, age: Int)
}