在日常使用Spark處理數據時, 半結構化的JSON數據(JSONObject, JSONArray)可能是最常見的一種數據結構,那麼能熟練並快速地處理JSON格式數據應該是數據開發人員的必備技能。
接下來我們就看看該如何將各種格式的JSON數據轉成DataFrame。
1. 讀取JSON文件
讀取指定路徑下的json文件(或者存放json文件的目錄),加載爲DataFrame。
本地文件
//本地路徑
val path = "file:/opt/package/jar/bank_statement_detail.json"
spark.read.json(path).show()
HDFS文件
//HDFS路徑
val path = "/file/bank_statement_detail.json"
spark.read.json(path).show()
2. List、Seq
將一個List或Seq加載爲DataFrame。
import spark.implicits._
val ds = spark.createDataset("""[{"name": "Spark", "age": 10}, {"name": "Flink", "age": 5}]""" :: Nil)
spark.read
//默認的timestampFormat爲 yyyy-MM-dd'T'HH:mm:ss.SSSXXX, SSS爲毫秒數, XXX爲非法字符(會報錯"java.lang.IllegalArgumentException: Illegal pattern component: XXX"),
//需要手動設置時區爲Z(即UTC時間)
.option("timestampFormat", "yyyy/MM/dd HH:mm:ss.SSSZ")
.json(ds)
.show()
3. JSON String類型的Column
JSON String類型的Column, 拿Hive來舉例的話,就是Hive表中的某一列,其類型爲String,其值是JSONArray類型("[{‘name’: ‘Spark’, ‘age’: 10}, {‘name’: ‘Flink’, ‘age’: 5}]"),或者是JSONObject類型("{‘name’: ‘Spark’, ‘age’: 10}")。
這種情況可以用以下兩種方式處理:
方式一(map函數處理)
import com.alibaba.fastjson.JSON
import spark.implicits._
//person_info爲string類型的JSONArray("[{'name': 'Spark', 'age': 10}, {'name': 'Flink', 'age': 5}]")
val df = spark.read.table("db_name.table_name").select("person_info")
//JSON string類型的Dataset轉成DataFrame
val ds = df.map(row => JSON.parseArray(row.toString).get(0).toString)
ds.show()
方式二(指定schema)
import org.apache.spark.sql.types._
import spark.implicits._
//person_info爲string類型的JSONArray("[{'name': 'Spark', 'age': 10}, {'name': 'Flink', 'age': 5}]")
val df = spark.read.table("db_name.table_name").select("person_info")
val schema = ArrayType(StructType(StructField("name", StringType):: StructField("age", IntegerType)::Nil))
val resultDF = df.select(from_json($"person_info", schema).as("info")) //將JSONArray列映射到一個schema上
.select(explode($"info").as("info")) //展開JSONArray中的元素(JSONObject)爲多行
.select("info.name", "info.age") //獲取每個JSONObject中每個key對應的value
resultDF.show()