Spark(Hive) SQL資料類型使用詳解(Python)

來源:互聯網
上載者:User

標籤:

Spark SQL使用時需要有若干“表”的存在,這些“表”可以來自於Hive,也可以來自“暫存資料表”。如果“表”來自於Hive,它的模式(列名、列類型等)在建立時已經確定,一般情況下我們直接通過Spark SQL分析表中的資料即可;如果“表”來自“暫存資料表”,我們就需要考慮兩個問題: (1)“暫存資料表”的資料是哪來的?(2)“暫存資料表”的模式是什嗎? 通過Spark的官方文檔可以瞭解到,產生一張“暫存資料表”需要兩個要素: (1)關聯著資料的RDD;(2)資料模式; 也就是說,我們需要將資料模式應用於關聯著資料的RDD,然後就可以將該RDD註冊為一張“暫存資料表”。在這個過程中,最為重要的就是資料(模式)的資料類型,它直接影響著Spark SQL計算過程以及計算結果的正確性。 目前pyspark.sql.types支援的資料類型:NullType、StringType、BinaryType、BooleanType、DateType、TimestampType、DecimalType、DoubleType、FloatType、ByteType、IntegerType、LongType、ShortType、ArrayType、MapType、StructType(StructField),其中ArrayType、MapType、StructType我們稱之為“複合類型”,其餘稱之為“基本類型”,“複合類型”在是“基本類型”的基礎上構建而來的。 這些“基本類型”與Python資料類型的對應關係如下: 
NullType None
StringType basestring
BinaryType bytearray
BooleanType bool
DateType datetime.date
TimestampType datetime.datetime
DecimalType decimal.Decimal
DoubleType float(double precision floats)
FloatType float(single precision floats)
ByteType int(a signed integer)
IntegerType int(a signed 32-bit integer)
LongType long(a signed 64-bit integer)
ShortType int(a signed 16-bit integer)
 下面我們分別介紹這幾種資料類型在Spark SQL中的使用。 1. 數字類型(ByteType、ShortType、IntegerType、LongType、FloatType、DoubleType、DecimalType) 數字類型可分為兩類,整數類型:ByteType、ShortType、IntegerType、LongType,使用時需要注意各自的整數表示範圍;浮點類型:FloatType、DoubleType、DecimalType,使用時不但需要注意各自的浮點數表示範圍,還需要注意各自的精度範圍。 我們以常見的資料類型IntegerType來說明數字類型的使用方法:  a. 類比“一行兩列”的資料,並通過parallelize方法將其轉換為一個RDD source,這個RDD就是關聯著資料的RDD; b. 建立資料模式,需要分別為這兩列指定列名、列類型、可否包含空(Null)值;其中模式需要使用StructType表示,每一列的各個屬性(列名稱、列類型、可否包含空(Null)值)需要使用StructField表示;第一列的列名為col1,列類型為IntegerType,不可包含空(Null)值(False);第二列的列名為col2,列類型為IntegerType,不可包含空(Null)值(False);(注意:實際使用中每列的資料類型並不一定相同) c. 通過applySchema方法將資料模式schema應用於RDD source,這會產生一個SchemaRDD(具有模式的RDD) table; d. 將SchemaRDD table註冊為一張表:temp_table; 到此我們就完成了建立RDD、建立Schema、註冊Table的整個過程,接下來就可以使用這張表(temp_table)通過Spark(Hive) SQL完成分析。其它數字類型的使用方式類似。 實際上本例中“一行兩列”的資料實際就是IntergerType的表示範圍:[-2147483648, 2147483647],其它數字類型的表示範圍如下: 
ByteType [-128, 127]
ShortType [-32768, 32767]
IntegerType [-2147483648, 2147483647]
LongType [-9223372036854775808, 9223372036854775807]
FloatType [1.4E-45, 3.4028235E38]
DoubleType [4.9E-324, 1.7976931348623157E308]
 可以看出,雖然我們使用Python編寫程式,這些資料類型的表示範圍與Java中的Byte、Short、Integer、Long、Float、Double是一致的,因為Spark是Scala實現的,而Scala運行於Java虛擬機器之上,因此Spark SQL中的資料類型ByteType、ShortType、IntegerType、LongType、FloatType、DoubleType、DecimalType在運行過程中對應的資料實際上是由Java中的Byte、Short、Integer、Long、Float、Double表示的。 在使用Python編寫Spark Application時需要牢記:為分析的資料選擇合適的資料類型,避免因為資料溢出導致輸入資料異常,但這僅僅能夠解決資料輸入的溢出問題,還不能解決資料在計算過程中可能出現的溢出問題。 我們將上述例子中的樣本資料修改為(9223372036854775807, 9223372036854775807),資料類型修改為LongType,現在的樣本資料實際是LongType所能表示的最大值,如果我們將這兩例值相加,是否會出現溢出的情況呢?  輸出結果:  可以看出,實際計算結果與我們預想的完全一樣,這是因為col1與col2的類型為LongType,那麼col1 + col2的類型也應為LongType(原因見後),然而col1 + col2的結果值18446744073709551614已經超過LongType所能表示的範圍([-9223372036854775808, 9223372036854775807]),必然導致溢出。 因為我們使用的是HiveContext(SQLContext目前不被推薦使用),很多時候我們會想到使用“bigint”,  輸出結果依然是:  要解釋這個原因,需要瞭解一下Hive中數字類型各自的表示範圍: 通過比對可以發現Hive BIGINT的表示範圍與LongType是一致的,畢竟Hive是Java實現的,因此我們可以猜想Hive tinyint、smallint、int、bigint、float、double與Java Byte、Short、Integer、Long、Float、Double是一一對應的(僅僅是猜想,並沒有實際查看源碼驗證),所以我們將LongType的資料類型轉換為BIGINT的方式是行不通的,它們的數值範圍是一樣的。 那麼我們應該如何解決溢出問題呢?注意到Hive Numeric Types中的最後一個數字類型:DECIMAL,從Hive 0.11.0引入,Hive 0.13.0開始支援使用者可以自訂“precision”和“scale”。Decimal基於Java BigDecimal實現,可以表示不可變的任務精度的十進位數字,支援常規的數學運算(+,-,*,/)和UDF(floor、ceil、round等),也可以與其它數字類型相互轉換(cast)。使用樣本如下:  使用Decimal時需要注意“precision”和“scale”值的選取,Java BigDecimal(BigInteger,後續會提到)取值範圍理論上取決於(虛擬)記憶體的大小,可見它們是比較消耗記憶體資源的,因此我們需要根據我們的實際需要為它們選取合適的值,並且需要滿足下述條件: 整數部分位元(precision - scale) + 小數部分位元(scale) = precision LongType所能表示的最大位元:19,因為在我們的樣本中會導致溢出問題,因此我們將數值轉換為Decimal,並指定precision為38,scale為0,這樣我們便可以得到正確的結果:  需要注意的是計算結果類型也變成decimal.Decimal(Python),使用Python編寫Spark Application時,pyspark也提供了DecimalType,它是一種比較特殊的資料類型,它不是Python內建的資料類型,使用時需要匯入模組decimal,使用方式如下:  使用資料類型DecimalType時有兩個地方需要注意: (1)建立RDD時需要使用模組decimal中的Decimal產生資料; (2)DecimalType在Spark 1.2.0環境下使用時會出現異常:java.lang.ClassCastException: java.math.BigDecimal cannot be cast to org.apache.spark.sql.catalyst.types.decimal.Decimal,在Spark 1.5.0環境下可以正常使用,但需要將模組名稱由“pyspark.sql”修改為“pyspark.sql.types”。 我們明確指定資料的類型是什麼,那麼什麼決定我們常規數學運算(+,-,*,/)之後的結果類型呢?這些數學運行在Hive中實際都是由UDF實現的(org.apache.hadoop.hive.ql.exec.FunctionRegistry),  (1)+  (2)-  (3)*  (4)/  (5)%  可以看出,“+”,“-”,“*”,“%”通過重載支援的資料類型:byte、short、int、long、float、double、decimal,“/”通過重載僅僅支援資料類型:double、decimal,計算的結果類型與輸入類型是相同的,這也意味著:(1)數學運算“+”、“-”,“*”,“%”時可能會出現隱式轉換(如int + long => long + long);(2)數學運算“/”則統一將輸入資料轉換為資料類型double或decimal進行運算,這一點也意味著,計算結果相應地為資料類型double或decimal。 2. 時間類型(DateType,TimestampType) DateType可以理解為年、月、日,TimestampType可以理解為年、月、日、時、分、秒,它們分別對著著Python datetime中的date,datetime,使用樣本如下:  輸出結果:  3. StringType、BooleanType、BinaryType、NoneType 這幾種資料類型的使用方法大致相同,就不一一講解了,注意BinaryType對應著使用了Python中的bytearray。  輸出結果:  4. 複合資料型別(ArrayType、MapType、StructType) 複合資料型別共有三種:數組(ArrayType)、字典(MapType)、結構體(StructType),其中數組(ArrayType)要求數組元素類型一致;字典(MapType)要求所有“key”的類型一致,所有“value”的類型一致,但“key”、“value”的類型可以不一致;結構體(StructType)的元素類型可以不一致。 (1)ArrayType ArrayType要求指定數組元素類型。  (2)MapType MapType要求指定鍵(key)類型和值(value)類型。   (3)StructType StructType包含的元素類型可不一致,需要根據元素的次序依次為其指定合適的名稱與資料類型。   綜上所述,Spark(Hive)SQL為我們提供了豐富的資料類型,我們需要根據分析資料的實際情況為其選取合適的資料類型(基本類型、複合類型)、尤其是資料類型各自的表示(精度)範圍以及資料溢出的情況處理。

Spark(Hive) SQL資料類型使用詳解(Python)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.