Spark SQL中對Json支持的詳細介紹

jopen 9年前發布 | 71K 次閱讀 Spark SQL 分布式/云計算/大數據

在這篇文章中,我將介紹一下Spark SQL對Json的支持,這個特性是Databricks的開發者們的努力結果,它的目的就是在Spark中使得查詢和創建JSON數據變得非常地簡單。隨著WEB和手機應用的流行,JSON格式的數據已經是WEB Service API之間通信以及數據的長期保存的事實上的標準格式了。但是使用現有的工具,用戶常常需要開發出復雜的程序來讀寫分析系統中的JSON數據集。而 Spark SQL中對JSON數據的支持極大地簡化了使用JSON數據的終端的相關工作,Spark SQL對JSON數據的支持是從1.1版本開始發布,并且在Spark 1.2版本中進行了加強。

現有Json工具實踐

在實踐中,用戶往往在處理現代分析系統中JSON格式的數據中遇到各種各樣的困難。如果用戶需要將數據集寫成JSON格式的話,他們需要編寫復雜的邏輯程序來轉換他們的數據集到JSON格式中。如果需要讀取或者查詢JSON數據集,他們通常需要預先定義好數據結構并用它來轉換JSON數據。在這種情況下,用戶必須等待這些數據處理完成之后,才能夠使用他們生成的JSON數據。無論是在寫或者是讀,預先定義和維護這些模式往往使得ETL工作變得非常地繁重!并且可能消除掉JSON這種半結構化(semi-structured)的數據格式的好處。如果用戶想消費新的數據,他們不得不在創建外部表的時候定義好相關的模式,并使用自定義的JSON serialization/deserialization依賴庫,或者是在查詢JSON數據的時候使用UDF函數。

作為一個例子,如果有下面的一些JSON數據模式

{"name":"Yin", "address":{"city":"Columbus","state":"Ohio"}}
{"name":"Michael", "address":{"city":null, "state":"California"}}

在類似于Hive的系統中,這些JSON對象往往作為一個值儲存到單個的列中,如果需要訪問這個數據,我們需要使用UDF來抽取出我們需要的數據。在下面的SQL查詢例子中,外層的字段(name和address)被抽取出來,嵌套在內層的address字段也被進一步的抽取出來:

/**
 * User: 過往記憶
 * Date: 15-02-04
 * Time: 上午07:30
 * bolg: http://www.iteblog.com
 * 本文地址:http://www.iteblog.com/archives/1260
 * 過往記憶博客,專注于hadoop、hive、spark、shark、flume的技術博客,大量的干貨
 * 過往記憶博客微信公共帳號:iteblog_hadoop
 */

SELECT
  v1.name, v2.city, v2.state 
FROM people
  LATERAL VIEW json_tuple(people.jsonObject, 'name', 'address') v1 
     as name, address
  LATERAL VIEW json_tuple(v1.address, 'city', 'state') v2
     as city, state;

Spark SQL中對JSON的支持

Spark SQL提供了內置的語法來查詢這些JSON數據,并且在讀寫過程中自動地推斷出JSON數據的模式。Spark SQL可以解析出JSON數據中嵌套的字段,并且允許用戶直接訪問這些字段,而不需要任何顯示的轉換操作。上面的查詢語句如果使用Spark SQL的話,可以這樣來寫:

SELECT name, age, address.city, address.state FROM people

在Spark SQL中加載和保存JSON數據集

為了能夠在Spark SQL中查詢到JSON數據集,唯一需要注意的地方就是指定這些JSON數據存儲的位置。這些數據集的模式是直接可以推斷出來,并且內置就有相關的語法支持,不需要用戶顯示的定義。在編程中使用API中,我們可以使用SQLContext提供的jsonFile和jsonRDD方法。使用這兩個方法,我們可以利用提供的JSON數據集來創建SchemaRDD 對象。并且你可以將SchemaRDD 注冊成表。下面是一個很好的例子:

/**
 * User: 過往記憶
 * Date: 15-02-04
 * Time: 上午07:30
 * bolg: http://www.iteblog.com
 * 本文地址:http://www.iteblog.com/archives/1260
 * 過往記憶博客,專注于hadoop、hive、spark、shark、flume的技術博客,大量的干貨
 * 過往記憶博客微信公共帳號:iteblog_hadoop
 */
// Create a SQLContext (sc is an existing SparkContext)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
// Suppose that you have a text file called people with the following content:
// {"name":"Yin", "address":{"city":"Columbus","state":"Ohio"}}
// {"name":"Michael", "address":{"city":null, "state":"California"}}
// Create a SchemaRDD for the JSON dataset.
val people = sqlContext.jsonFile("[the path to file people]")
// Register the created SchemaRDD as a temporary table.
people.registerTempTable("people")

當然,我們也可以使用純的SQL語句來創建JSON數據集。例如

CREATE TEMPORARY TABLE people
USING org.apache.spark.sql.json
OPTIONS (path '[the path to the JSON dataset]')

在上面的例子中,因為我們沒有顯示地定義模式,Spark SQL能夠自動地掃描這些JSON數據集,從而推斷出相關的模式。如果一個字段是JSON對象或者數組,Spark SQL將使用STRUCT 類型或者ARRAY類型來代表這些字段。即使JSON數是半結構化的數據,并且不同的元素肯恩好擁有不同的模式,但是Spark SQL仍然可以解決這些問題。如果你想知道JSON數據集的模式,你可以通過使用返回來的SchemaRDD 對象中提供的printSchema()函數來打印出相應的模式,或者你也可以在SQL中使用DESCRIBE [table name]。例如上面的people數據集的模式可以通過people.printSchema()打印出:

root
 |-- address: struct (nullable = true)
 |    |-- city: string (nullable = true)
 |    |-- state: string (nullable = true)
 |-- name: string (nullable = true)

當然,用戶在利用 jsonFile 或 jsonRDD創建表的時候也可以顯示的指定一個模式到JSON數據集中。在這種情況下,Spark SQL將把這個模式和JSON數據集進行綁定,并且將不再會去推測它的模式。用戶不需要了解JSON數據集中所有的字段。指定的模式可以是固定數據集的一個子集,也可以包含JSON數據集中不存在的字段。

當用戶創建好代表JSON數據集的表時,用戶可以很簡單地利用SQL來對這個JSON數據集進行查詢,就像你查詢普通的表一樣。在Spark SQL中所有的查詢,查詢的返回值是SchemaRDD對象。例如:

val nameAndAddress = sqlContext.sql("SELECT name, address.city, address.state FROM people")
nameAndAddress.collect.foreach(println)

查詢的結果可以直接使用,或者是被其他的分析任務使用,比如機器學習。當然,JSON數據集可以通過Spark SQL內置的內存列式存儲格式進行存儲,也可以存儲成其他格式,比如Parquet或者 Avro。

將SchemaRDD對象保存成JSON文件

在Spark SQL中,SchemaRDDs可以通過toJSON 方法保存成JSON格式的文件。因為SchemaRDD中已經包含了相應的模式,所以Spark SQL可以自動地將該數據集轉換成JSON,而不需要用戶顯示地指定。當然,SchemaRDDs可以通過很多其他格式的數據源進行創建,比如Hive tables、 Parquet文件、 JDBC、Avro文件以及其他SchemaRDD的結果。這就意味著用戶可以很方便地將數據寫成JSON格式,而不需要考慮到源數據集的來源。

來源:過往記憶的博客

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!