例子:将原始类型转处理布尔类型换为Spark 类型,使用 lit 函数
函数:lit()
用例:lit 函数:把其他语言的类型转换为与其相对应的Spark表示
// lit 函数:把其他语言的类型转换为与其相对应的Spark表示
df.select(lit(5),lit("five"),lit(5.0)).show()
处理布尔类型
例子:布尔语句由四个要素组成:and,or,true 和 false
函数:and,or,true,false
用例:基于零售数据来说明处理布尔类型的方法,可以在其中指定等于、小于或大于:
df.where(col("InvoiceNo").equalTo(536365))
.select("InvoiceNo", "Description")
.show(5, false)
例子:相等条件或者不相等条件
函数:相等:=== 或 equalTo
不相等:=!= 或not
用例:在spark 中,如果想通过相等条件来进行过滤,应该使用 ===(等于) 或者 =!=(不等于)符号,还可以使用not 或者equalTo 方法来实现。
df.where(col("InvoiceNo") === 536365)
.select("InvoiceNo", "Description")
.show(5, false)
例子:顺序执行的过滤器
用例:在spark 中最好是以链式连接的方式组合起来,形成顺序执行的过滤器
val priceFilter = col("UnitPrice") > 600
val descripFilter = col("Description").contains("POSTAGE")
df.where(col("StockCode").isin("DOT")).where(priceFilter.or(descripFilter)).show()
例子:设定一个Boolean 类型的列
用例:布尔表达式不一定非要在过滤器中使用,想要过滤DataFrame ,也可以设定一个Boolean类型的列
println("boolean 列:")
val DOTCodeFilter = col("StockCode") === "DOT"
df.withColumn("isExpensive", DOTCodeFilter.and(priceFilter.or(descripFilter)))
.where("isExpensive")
.select("unitPrice", "isExpensive")
.show(5)
下面两个等价:
//下面两个等价:
println("下面两个等价:")
df.withColumn("isExpansive", not(col("UnitPrice").leq(250)))
.filter("isExpansive")
.select("Description", "UnitPrice")
.show(5)
df.withColumn("isExpansive", expr("NOT UnitPrice <= 250"))
.filter("isExpansive")
.select("Description", "UnitPrice")
.show(5)
处理数值类型
例子:计算
函数:pow() 平方函数
用例:计算(当前数量* 单位数量)的平方 + 5
// 计算(当前数量* 单位数量)的平方 + 5
println("pow() 函数:对指定的列进行幂运算")
var fabricatedQuantity = functions.pow(col("Quantity") * col("UnitPrice"), 2)+5
df.select(expr("CustomerId"),fabricatedQuantity.alias("readQuantity")).show(2)//给fabricatedQuantity一个别名
// 使用SQL 等价代替
df.selectExpr("CustomerID","(POWER((Quantity * UnitPrice),2) + 5) as readQuantity")
例子:处理四舍五入的情况
函数:round 函数会向上取整,bround 函数进行向下取整
用例: 将四舍五入到小数点后一位,在默认情况下,如果恰好位于两个数字之间,则round 函数会向上取整,也可以通过bround 函数进行向下取整。
println("处理四舍五入的情况:")
// 将四舍五入到小数点后一位
df.select(round(col("UnitPrice"),1).alias("rounded"),col("UnitPrice")).show(5)
// 在默认情况下,如果恰好位于两个数字之间,则round 函数会向上取整,
// 也可以通过bround 函数进行向下取整
df.select(round(lit("2.5")), bround(lit("2.5"))).show(2)
例子:计算相关性
函数:corr()
用例:计算两列的相关性 例如,可以通过两列的Pearson 相关系数来查看是个东西越便宜买的越多。
//计算两列的相关性 例如,可以通过两列的Pearson 相关系数来查看是个东西越便宜买的越多
println("计算两列的相关性:")
df.stat.corr("Quantity","UnitPrice")
df.select(corr("Quantity","UnitPrice")).show(5)
例子:计算一列或一组列的汇总统计信息;
函数:describe()
用例:计算一列或一组列的汇总统计信息;包含:计数,平均值,标准差,最小值和最大值。
//计算一列或一组列的汇总统计信息;
println("计算一列或一组列的汇总统计信息")
// 包含:计数,平均值,标准差,最小值和最大值
df.describe().show()
例子:精确聚合操作
函数:approxQuantile()
用例:如果需要这些精确的数字,也可以通过导入函数并在所在列上应用来实现聚合操作
,StatFunction 包中封装了各种计算的DataFrame 方法,比如,可以使用 approxQuantile 方法来计算数据的精确分位数或近似分位数。
println("计算数据的精确分位数或近似分位数")
val colName = "UnitPrice"
val quantileProbs = Array(0.5)
val relError = 0.05
df.stat.approxQuantile("UnitPrice", quantileProbs, relError) // 2.51
例子:查看交叉列表或频繁项:
函数:crosstab() 查看交叉列表,freqItems() 查看频繁项
用例:
//查看交叉列表或频繁项:
println("查看交叉列表或频繁项:")
df.stat.crosstab("StockCode", "Quantity").show() // 交叉列表
df.stat.freqItems(Seq("StockCode", "Quantity")).show() // 频繁项
处理字符串类型
例子:initcap 函数会将给定字符串中空格分隔的每个单词首字母大写
函数:initcap()
用例:
// initcap 函数会将给定字符串中空格分隔的每个单词首字母大写
println("initcap 函数会将给定字符串中空格分隔的每个单词首字母大写")
df.select(initcap(col("Description"))).show(2,false)
例子:将字符串转为大写或小写
函数:lower() 小写 ,upper() 大写
用例:
// 将字符串转为大写或小写
println("将字符串转为大写或小写")
df.select(col("Description"),
lower(col("Description").alias("小写")),
upper(lower(col("Description")).alias("大写"))).show(2)
例子:删除字符串周围的空格或者在其周围添加空格
函数:lpad,ltrim,rpad,rtrim,trim
用例: 删除字符串周围的空格或者在其周围添加空格,可以使用lpad,ltrim,rpad,rtrim,trim
println("删除字符串周围的空格或者在其周围添加空格,可以使用lpad,ltrim,rpad,rtrim,trim")
df.select(
ltrim(lit(" HELLO ")).as("ltrim"),
rtrim(lit(" HELLO ")).as("rtrim"),
trim(lit(" HELLO ")).as("trim"),
lpad(lit("HELLO"), 3, " ").as("lp"),
rpad(lit("HELLO"), 10, " ").as("rp")).show(2)
// 注意:如果lpad 或rpad方法输入的数值参数小于字符串长度,他将从字符串的右侧删除字符
处理日期和时间戳类型
处理日期和时间戳类型 Spark
通过显示的关注两种时间相关信息来简化这个问题,分别是专门正对日历日期的date,以及包括日期和时间信息的timestamp
当设置inferSchema 为true 的时候,Spark可以自动推理出日期和时间戳数据类型
// 获取当前的日期和当前的时间戳
val dateDF = spark.range(10)
.withColumn("today", current_date())
.withColumn("now", current_timestamp())
dateDF.createOrReplaceTempView("dateTable")
例子:增加天数,减去天数
函数:date_sub() 减去天数,date_add() 增加天数
用例:现在有一个简单的DataFrame 可以使用,从今天起增加和减去5天,这些函数读取一列,然后将添加或减去的天数作为参数
// 现在有一个简单的DataFrame 可以使用,从今天起增加和减去5天,这些函数读取一列,然后将添加或减去的天数作为参数
println("读取一列,然后将添加或减去的天数作为参数")
dateDF.select(date_sub(col("today"),5),date_add(col("today"),5)).show(1)
例子:查看两个日期之间的间隔时间
函数: datediff()
用例:查看两个日期之间的间隔时间,可以使用datediff 函数来完成,返回两个日期之间的天数,该函数返回两个日期之间的天数,由于每个月的天数不用,还有一个months_between 函数,它可以给出两个日期之间相隔的月数
println("查看两个日期之间的间隔时间,可以使用datediff 函数来完成,返回两个日期之间的天数:")
dateDF.withColumn("week_age",date_sub(col("today"),7))
.select(datediff(col("week_age"),col("today")))
.show(1)
//查看两个日期之间间隔的月数
println("查看两个日期之间间隔的月数")
dateDF.select(
to_date(lit("2016-01-01")).alias("start"),
to_date(lit("2017-05-22")).alias("end"))
.select(months_between(col("start"), col("end"))).show(1)
例子:指定的格式将字符串转为日期格式
函数:to_date()
用例:
//to_date 函数,该函数以指定的格式将字符串转为日期格式
println("to_date 函数,该函数以指定的格式将字符串转为日期格式")
spark.range(5).withColumn("date", lit("2017-01-01"))
.select(to_date(col("date"))).show(1)
例子:Spark 无法解析日期,
函数:to_date 和 to_timestamp 前者可以选择一种日期格式,而后者则强制要求使用一种日期格式
用例:
// Spark 无法解析日期,
dateDF.select(to_date(lit("2016-20-12")), to_date(lit("2017-12-11"))).show(1)
//修复这个功能,将使用两个函数来解决此问题,to_date 和 to_timestamp 前者可以选择一种日期格式,而后者则强制要求使用一种日期格式
// to_date 可选择一种日期格式
val dateFormat = "yyyy-dd-MM"
val cleanDateDF = spark.range(1).select(
to_date(lit("2017-12-11"), dateFormat).alias("date"),
to_date(lit("2017-20-12"), dateFormat).alias("date2"))
cleanDateDF.createOrReplaceTempView("dateTable2")
// to_timestamp 强制要求使用一种日期格式
cleanDateDF.select(to_timestamp(col("date"), dateFormat)).show()
例子:比较
函数:
用例:
// 在以正确的格式和类型获取了日期或时间戳之后,他们之间的比较实际上很简单,只需要确保使用同一种日期/时间戳类型,或者根据 yyyy-MM-dd 这个正确格式来指定字符串
cleanDateDF.filter(col("date2") > lit("2017-12-12")).show()
// 另一个也要说明,也可以将他设置为一个字符串,这样spark 可以将它解释为文本
cleanDateDF.filter(col("date2") > "'2017-12-12'").show()
处理数据中的空值
例子:合并
函数:coalesce 函数,实现从一组列中选择第一个非空值
用例:
println("coalesce 函数,实现从一组列中选择第一个非空值")
df.select(coalesce(col("Description"),col("CustomerId"))).show()
例子:删除
函数:drop()
用例:用于删除包含null 的行,默认删除包含null 的行。 若指定any 作为参数,当存在一个值是null时,就删除该行,若指定 all 为参数,只有当所有的值为null 或NaN 时才能删除该行。
df.na.drop()
df.na.drop("any")
spark.stop()
df.na.drop("all")
// 指定列进行删除空值操作
// 通过指定某几列,来对这些列进行删除空值操作
df.na.drop("all", Seq("StockCode", "InvoiceNo"))
例子:fill() 填充
函数:fill()
用例:可以用一组值填充一列或多列,可以通过指定一个映射(即一个特定值和一组列)来完成此操作。
//替换某字符串类型列中的所有null 值为某一字符串
df.na.fill("All Null values become this string")
//对于Integer 类型的列,可以使用df.na.fill(5:Integer) 来实现
// 对于Double 类型的列,可以使用df.na.fill(5:Double) 来实现
df.na.fill(5, Seq("StockCode", "InvoiceNo"))
// 想要指定多列,需传入一个列名的数组,
val fillColValues = Map("StockCode" -> 5, "Description" -> "No Value")
df.na.fill(fillColValues)
例子:替换
函数:replace()
用例:常见的用例:是根据当前值替换某列中的所有值,唯一的要求是替换之与原始值的类型相同。
println("replace")
df.na.replace("Description", Map("" -> "UNKNOWN"))
处理负责数据类型
例子:处理结构体
函数:
用例:
println("结构体:")
// 用圆括号括起一组列来创建一个结构体
df.selectExpr("(Description, InvoiceNo) as complex", "*")
df.selectExpr("struct(Description, InvoiceNo) as complex", "*")
val complexDF = df.select(struct("Description", "InvoiceNo").alias("complex"))
complexDF.createOrReplaceTempView("complexDF")
// 现在有一个包含complex 列的DataFrame ,我们可以像查询另一个DataFrame 一样查询它,唯一的区别是,使用”.“ 来访问或列方法getField 来实现
complexDF.select("complex.Description")
complexDF.select(col("complex").getField("Description"))
// 还可以使用* 来查询结构体中的所有制,
complexDF.select("complex.*")
例子:数组
函数:
用例:
/**
* 数组
* 用例:使用当前数据,目标是读取Description 列中的每一个单词并将其转换成DataFrame 中的一行
* 第一个操作是将Description 列转换为一个复杂类型,即数组
*/
/**
* split()
* 使用split() ,并指定分隔符来执行此操作
* 这个功能非常有用,因为spark 允许我们将这种复杂类型作为另一列来操作
*/
df.select(split(col("Description")," ")).show(2)
// 数组长度,
df.select(size(split(col("Description")," "))).show(2) // 打印5 和 3
/**
* array_contains()
* 查询此数组是个包含某个值
*/
df.select(array_contains(split(col("Description")," "),"WHITE")).show(2)
/**
* 若想将复杂类型转换为一系列行(数组中的每个值为一行),则需要使用explode 函数
* explode函数输入参数为一个包含数组的列,并未该数组中的每个值创建一行(每行重复该值)
*/
df.withColumn("splitted", functions.split(col("Description"), " "))
.withColumn("exploded", explode(col("splitted")))
.select("Description", "InvoiceNo", "exploded").show(2)
例子:map
函数:
用例:
/**
* map
* map映射是通过map函数构建两列内容的键值对映射形式,然后,便可以想在数组中一样去选择他们
*/
df.select(functions.map(col("Description"),col("InvoiceNo")).alias("complex_map")).show(2)
// 可以使用正确的键值对他们进行查询。若键值不存在则返回null
df.select(functions.map(col("Description"),col("InvoiceNo")).alias("complex_map"))
.selectExpr("complex_map['WHITE METAL LANTERN']").show(2)
//展开map类型,将其转换为列
df.select(functions.map(col("Description"), col("InvoiceNo")).alias("complex_map"))
.selectExpr("explode(complex_map)").show(2)
处理JSON 类型
例子:
函数:to_json()、 get_json_object
用例:
//创建一个JSON 类型的列
val jsonDF = spark.range(1).selectExpr(
"""
'{"myJSONKey" : {"myJSONValue" : [1, 2, 3]}}' as jsonString
""")
// 无论是字典还是数组,均可以使用get_json_object 直接查询json 对象,如果此查询的json对象仅有一层嵌套,则可以使用json_tuple
jsonDF.select(
get_json_object(col("jsonString"), "$.myJSONKey.myJSONValue[1]") as "column",
json_tuple(col("jsonString"), "myJSONKey")).show(2)
// SQL 中的等价
jsonDF.selectExpr(
"json_tuple(jsonString, '$.myJSONKey.myJSONValue[1]') as column").show(2)
/**
* 使用to_json 函数将StructType 转换为JSON 字符串
* 这个函数也可以接收参数的映射作为输入,这些映射与json 的数据源相同,还可以使用from_json 函数将json 数据解析出来
* 这需要指定一个模式,也可以指定其他的映射
*/
// 使用to_json 函数将StructType 转换为JSON 字符串
df.selectExpr("(InvoiceNo, Description) as myStruct")
.select(to_json(col("myStruct")))
val parseSchema = new StructType(Array(
new StructField("InvoiceNo",StringType,true),
new StructField("Description",StringType,true)))
df.selectExpr("(InvoiceNo, Description) as myStruct")
.select(to_json(col("myStruct")).alias("newJSON"))
.select(from_json(col("newJSON"), parseSchema), col("newJSON")).show(2)