移行ガイド: SQL、データセット、データフレーム
- Spark SQL 3.4 から 3.5 へのアップグレード
- Spark SQL 3.3 から 3.4 へのアップグレード
- Spark SQL 3.2 から 3.3 へのアップグレード
- Spark SQL 3.1 から 3.2 へのアップグレード
- Spark SQL 3.0 から 3.1 へのアップグレード
- Spark SQL 3.0.1 から 3.0.2 へのアップグレード
- Spark SQL 3.0 から 3.0.1 へのアップグレード
- Spark SQL 2.4 から 3.0 へのアップグレード
- Spark SQL 2.4.7 から 2.4.8 へのアップグレード
- Spark SQL 2.4.5 から 2.4.6 へのアップグレード
- Spark SQL 2.4.4 から 2.4.5 へのアップグレード
- Spark SQL 2.4.3 から 2.4.4 へのアップグレード
- Spark SQL 2.4 から 2.4.1 へのアップグレード
- Spark SQL 2.3 から 2.4 へのアップグレード
- Spark SQL 2.2 から 2.3 へのアップグレード
- Spark SQL 2.1 から 2.2 へのアップグレード
- Spark SQL 2.0 から 2.1 へのアップグレード
- Spark SQL 1.6 から 2.0 へのアップグレード
- Spark SQL 1.5 から 1.6 へのアップグレード
- Spark SQL 1.4 から 1.5 へのアップグレード
- Spark SQL 1.3 から 1.4 へのアップグレード
- Spark SQL 1.0-1.2 から 1.3 へのアップグレード
- Apache Hive との互換性
Spark SQL 3.4 から 3.5 へのアップグレード
- Spark 3.5 以降、DS V2 プッシュダウンに関連する JDBC オプションはデフォルトで
true
です。これらのオプションには、pushDownAggregate
、pushDownLimit
、pushDownOffset
、およびpushDownTableSample
が含まれます。レガシーな動作を復元するには、それらをfalse
に設定してください。例えば、spark.sql.catalog.your_catalog_name.pushDownAggregate
をfalse
に設定します。 - Spark 3.5 以降、Spark Thrift Server は実行中のステートメントをキャンセルする際にタスクを中断します。以前の動作を復元するには、
spark.sql.thriftServer.interruptOnCancel
をfalse
に設定してください。 - Spark 3.5 以降、Row の json および prettyJson メソッドは
ToJsonUtil
に移動しました。 - Spark 3.5 以降、
plan
フィールドはAnalysisException
からEnhancedAnalysisException
に移動しました。 - Spark 3.5 以降、
spark.sql.optimizer.canChangeCachedPlanOutputPartitioning
はデフォルトで有効になっています。以前の動作を復元するには、spark.sql.optimizer.canChangeCachedPlanOutputPartitioning
をfalse
に設定してください。 - Spark 3.5 以降、
array_insert
関数は負のインデックスに対して 1 ベースになります。インデックス -1 の場合、入力配列の末尾に新しい要素を挿入します。以前の動作を復元するには、spark.sql.legacy.negativeIndexInArrayInsert
をtrue
に設定してください。 - Spark 3.5 以降、Avro は Interval 型を Date または Timestamp 型として読み取る場合、または精度が低い Decimal 型を読み取る場合に、
AnalysisException
をスローします。レガシーな動作を復元するには、spark.sql.legacy.avro.allowIncompatibleSchema
をtrue
に設定してください。
Spark SQL 3.3 から 3.4 へのアップグレード
- Spark 3.4 以降、ターゲットテーブルよりも少ない列で構成される明示的な列リストを持つ INSERT INTO コマンドは、残りの列に対応するデフォルト値(または明示的に割り当てられたデフォルト値を持たない列の場合は NULL)を自動的に追加します。Spark 3.3 以前では、これらのコマンドは、指定された列の数がターゲットテーブルの列の数と一致しないことを報告するエラーを返して失敗していました。
spark.sql.defaultColumn.useNullsForMissingDefaultValues
を無効にすると、以前の動作が復元されることに注意してください。 - Spark 3.4 以降、Teradata の Number または Number(*) は Decimal(38, 18) として扱われます。Spark 3.3 以前では、Teradata の Number または Number(*) は Decimal(38, 0) として扱われ、その場合、小数部分は削除されていました。
- Spark 3.4 以降、v1 データベース、テーブル、永続ビュー、および関数識別子は、データベースが定義されている場合、カタログ名として 'spark_catalog' を含めます。例えば、テーブル識別子は
spark_catalog.default.t
になります。レガシーな動作を復元するには、spark.sql.legacy.v1IdentifierNoCatalog
をtrue
に設定してください。 - Spark 3.4 以降、ANSI SQL モード(構成
spark.sql.ansi.enabled
)が有効になっている場合、Spark SQL は、存在しないキーでマップ値を取得する際に常に NULL 結果を返します。Spark 3.3 以前では、エラーが発生していました。 - Spark 3.4 以降、SQL CLI
spark-sql
は、AnalysisException
のエラーメッセージの前にプレフィックスError in query:
を出力しません。 - Spark 3.4 以降、
split
関数は、regex
パラメータが空の場合、末尾の空の文字列を無視します。 - Spark 3.4 以降、
to_binary
関数は、不正な形式のstr
入力に対してエラーをスローします。不正な形式の入力を許容し、代わりに NULL を返すには、try_to_binary
を使用してください。- 有効な Base64 文字列には、base64 アルファベット(A-Za-z0-9+/)の記号、オプションのパディング(
=
)、およびオプションの空白が含まれる必要があります。空白は、パディング記号が先行する場合を除き、変換時にスキップされます。パディングが存在する場合は、文字列を終了し、RFC 4648 § 4 で説明されているルールに従う必要があります。 - 有効な 16 進数文字列には、許可された記号(0-9A-Fa-f)のみが含まれている必要があります。
fmt
の有効な値は、大文字と小文字を区別しないhex
、base64
、utf-8
、utf8
です。
- 有効な Base64 文字列には、base64 アルファベット(A-Za-z0-9+/)の記号、オプションのパディング(
- Spark 3.4 以降、パーティションを作成する際に、一部のパーティションが既に存在する場合、Spark は
PartitionsAlreadyExistException
のみをスローします。Spark 3.3 以前では、Spark はPartitionsAlreadyExistException
またはPartitionAlreadyExistsException
のいずれかをスローする可能性があります。 - Spark 3.4 以降、Spark は ALTER PARTITION でのパーティション仕様の検証を実行して、
spark.sql.storeAssignmentPolicy
の動作に従うようになり、型変換が失敗した場合(例えば、列p
が int 型の場合のALTER TABLE .. ADD PARTITION(p='a')
など)、例外が発生する可能性があります。レガシーな動作を復元するには、spark.sql.legacy.skipTypeValidationOnAlterPartition
をtrue
に設定してください。 - Spark 3.4 以降、ベクトル化されたリーダーは、ネストされたデータ型(配列、マップ、構造体)に対してデフォルトで有効になっています。レガシーな動作を復元するには、
spark.sql.orc.enableNestedColumnVectorizedReader
とspark.sql.parquet.enableNestedColumnVectorizedReader
をfalse
に設定してください。 - Spark 3.4 以降、
BinaryType
は CSV データソースでサポートされていません。Spark 3.3 以前では、ユーザーは CSV データソースにバイナリ列を書き込むことができましたが、CSV ファイルの出力内容はObject.toString()
であり意味がありませんでした。一方、ユーザーがバイナリ列を含む CSV テーブルを読み取ると、Spark はUnsupported type: binary
例外をスローします。 - Spark 3.4 以降、ブルームフィルター結合はデフォルトで有効になっています。レガシーな動作を復元するには、
spark.sql.optimizer.runtime.bloomFilter.enabled
をfalse
に設定してください。
Spark SQL 3.2 から 3.3 へのアップグレード
-
Spark 3.3 以降、Spark SQL の
histogram_numeric
関数は、構造体 (x, y) の配列の出力型を返します。ここで、戻り値の 'x' フィールドの型は、集計関数で使用される入力値から伝播されます。Spark 3.2 以前では、'x' は常に double 型でした。オプションで、Spark 3.3 以降では構成spark.sql.legacy.histogramNumericPropagateInputType
を使用して、以前の動作に戻すことができます。 -
Spark 3.3 以降、Spark SQL の
DayTimeIntervalType
は、ArrowWriter
およびArrowColumnVector
開発者 API で Arrow のDuration
型にマップされます。以前は、DayTimeIntervalType
は Arrow のInterval
型にマップされていましたが、これは Spark SQL がマップする他の言語の型と一致しませんでした。例えば、DayTimeIntervalType
は Java でjava.time.Duration
にマップされます。 -
Spark 3.3 以降、関数
lpad
とrpad
はバイトシーケンスをサポートするようにオーバーロードされました。最初の引数がバイトシーケンスの場合、オプションのパディングパターンもバイトシーケンスである必要があり、結果は BINARY 値になります。この場合のデフォルトのパディングパターンはゼロバイトです。常に文字列型を返すというレガシーな動作を復元するには、spark.sql.legacy.lpadRpadAlwaysReturnString
をtrue
に設定してください。 -
Spark 3.3 以降、ユーザーがスキーマを指定し、かつ非 NULL フィールドを含む場合、API
DataFrameReader.schema(schema: StructType).json(jsonDataset: Dataset[String])
およびDataFrameReader.schema(schema: StructType).csv(csvDataset: Dataset[String])
では、非 NULL スキーマが NULL 許容スキーマに変換されるようになりました。NULL 許容を尊重する従来の動作を復元するには、spark.sql.legacy.respectNullabilityInTextDatasetConversion
をtrue
に設定してください。 -
Spark 3.3 以降、日付またはタイムスタンプのパターンが指定されていない場合、Spark は
CAST
式アプローチを使用して入力文字列を日付/タイムスタンプに変換します。この変更は、CSV/JSON データソースとパーティション値の解析に影響します。Spark 3.2 以前では、日付またはタイムスタンプのパターンが設定されていない場合、Spark は日付にはyyyy-MM-dd
、タイムスタンプにはyyyy-MM-dd HH:mm:ss
のデフォルトパターンを使用していました。変更後も、Spark は次のパターンを認識します。日付パターン
[+-]yyyy*
[+-]yyyy*-[m]m
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d *
[+-]yyyy*-[m]m-[d]dT*
タイムスタンプパターン
[+-]yyyy*
[+-]yyyy*-[m]m
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d [h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
[+-]yyyy*-[m]m-[d]dT[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
T[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
-
Spark 3.3 以降、
format_string(strfmt, obj, ...)
およびprintf(strfmt, obj, ...)
のstrfmt
では、最初の引数を指定するために "0$" を使用できなくなりました。引数の位置を引数リストで示すために引数インデックスを使用する場合は、常に最初の引数を "1$" で参照する必要があります。 -
Spark 3.3 以降、CSV データソースではデフォルトで NULL が空文字列として書き込まれるようになりました。Spark 3.2 以前では、NULL は引用符で囲まれた空文字列
""
として書き込まれていました。以前の動作を復元するには、nullValue
を""
に設定するか、構成spark.sql.legacy.nullValueWrittenAsQuotedEmptyStringCsv
をtrue
に設定してください。 -
Spark 3.3 以降、関数が存在しない場合、DESCRIBE FUNCTION は失敗するようになりました。Spark 3.2 以前では、DESCRIBE FUNCTION は引き続き実行され、「Function: func_name not found」と表示されていました。
-
Spark 3.3 以降、テーブルプロパティ
external
は予約済みになりました。CREATE TABLE ... TBLPROPERTIES
やALTER TABLE ... SET TBLPROPERTIES
など、external
プロパティを指定すると、特定のコマンドが失敗します。Spark 3.2 以前では、テーブルプロパティexternal
は暗黙的に無視されていました。古い動作を復元するには、spark.sql.legacy.notReserveProperties
をtrue
に設定できます。 -
Spark 3.3 以降、関数名が組み込み関数の名前のいずれかと一致し、修飾されていない場合、DROP FUNCTION は失敗します。Spark 3.2 以前では、名前が修飾されておらず、組み込み関数の名前と同じであっても、DROP FUNCTION は永続的な関数を削除できました。
-
Spark 3.3 以降、
FloatType
またはDoubleType
として定義された JSON 属性から値を読み取る場合、既にサポートされている"Infinity"
および"-Infinity"
のバリエーションに加えて、文字列"+Infinity"
、"+INF"
、および"-INF"
が適切な値に解析されるようになりました。この変更は、これらの値の引用符なしバージョンを Jackson が解析するとの一貫性を向上させるために行われました。また、allowNonNumericNumbers
オプションが尊重されるようになったため、このオプションが無効になっている場合、これらの文字列は無効と見なされるようになりました。 -
Spark 3.3 以降、Spark は
INSERT OVERWRITE DIRECTORY
で Hive serde の代わりに組み込みのデータソースライターを使用しようとします。この動作は、Parquet および ORC 形式に対してそれぞれspark.sql.hive.convertMetastoreParquet
またはspark.sql.hive.convertMetastoreOrc
が有効になっている場合にのみ有効です。Spark 3.3 より前の動作を復元するには、spark.sql.hive.convertMetastoreInsertDir
をfalse
に設定できます。 -
Spark 3.3 以降、round のような関数の戻り値の型の精度が修正されました。これにより、古いバージョンで作成されたビューを使用すると、Spark が
CANNOT_UP_CAST_DATATYPE
エラークラスのAnalysisException
をスローする可能性があります。このような場合は、新しい Spark バージョンで ALTER VIEW AS または CREATE OR REPLACE VIEW AS を使用してビューを再作成する必要があります。 -
Spark 3.3 以降、
unbase64
関数は、形式が正しくないstr
入力に対してエラーをスローします。形式が正しくない入力を許容して代わりに NULL を返すには、try_to_binary(<str>, 'base64')
を使用してください。Spark 3.2 以前では、unbase64
関数は、形式が正しくないstr
入力に対して最善の結果を返していました。 -
Spark 3.3.1 および 3.2.3 以降、
SELECT ... GROUP BY a GROUPING SETS (b)
スタイルの SQL ステートメントの場合、grouping__id
は Apache Spark 3.2.0、3.2.1、3.2.2、および 3.3.0 とは異なる値を返します。これは、ユーザーが指定した group-by 式とグループ化セットの列に基づいて計算されます。3.3.1 および 3.2.3 より前の動作を復元するには、spark.sql.legacy.groupingIdWithAppendedUserGroupBy
を設定できます。詳細については、SPARK-40218 および SPARK-40562 を参照してください。
Spark SQL 3.1 から 3.2 へのアップグレード
-
Spark 3.2 以降、パスに空白が含まれている場合、ADD FILE/JAR/ARCHIVE コマンドでは、各パスを
"
または'
で囲む必要があります。 -
Spark 3.2 以降、サポートされているすべての JDBC ダイアレクトで ROWID に StringType が使用されます。Spark 3.1 以前では、Oracle ダイアレクトでは StringType が使用され、その他のダイアレクトでは LongType が使用されていました。
-
Spark 3.2 では、PostgreSQL JDBC ダイアレクトは MONEY に StringType を使用し、PostgreSQL 用 JDBC ドライバーがこれらの型を適切に処理できないため、MONEY[] はサポートされていません。Spark 3.1 以前では、DoubleType および DoubleType の ArrayType がそれぞれ使用されていました。
-
Spark 3.2 では、
spark.sql.adaptive.enabled
がデフォルトで有効になっています。Spark 3.2 より前の動作を復元するには、spark.sql.adaptive.enabled
をfalse
に設定できます。 - Spark 3.2 では、
show()
アクションで次のメタ文字がエスケープされます。Spark 3.1 以前では、次のメタ文字はそのまま出力されていました。\n
(改行)\r
(キャリッジリターン)\t
(水平タブ)\f
(改ページ)\b
(バックスペース)\u000B
(垂直タブ)\u0007
(ベル)
-
Spark 3.2 では、ターゲットパーティションが既に存在する場合、Hive 外部のテーブルに対して
ALTER TABLE .. RENAME TO PARTITION
がAnalysisException
の代わりにPartitionAlreadyExistsException
をスローします。 -
Spark 3.2 では、スクリプト変換のデフォルトの FIELD DELIMIT は serde モードなしの場合は
\u0001
、ユーザーが serde を指定した場合は Hive serde モードの serde プロパティfield.delim
は\t
です。Spark 3.1 以前では、デフォルトの FIELD DELIMIT は\t
、ユーザーが serde を指定した場合は Hive serde モードの serde プロパティfield.delim
は\u0001
でした。 -
Spark 3.2 では、自動生成された
Cast
(型強制ルールによって追加されたものなど) は、列エイリアス名を生成するときに削除されます。たとえば、sql("SELECT floor(1)").columns
はFLOOR(CAST(1 AS DOUBLE))
ではなくFLOOR(1)
になります。 -
Spark 3.2 では、
SHOW TABLES
の出力スキーマはnamespace: string, tableName: string, isTemporary: boolean
になります。Spark 3.1 以前では、組み込みカタログの場合、namespace
フィールドの名前はdatabase
であり、v2 カタログにはisTemporary
フィールドはありません。組み込みカタログで古いスキーマを復元するには、spark.sql.legacy.keepCommandOutputSchema
をtrue
に設定できます。 -
Spark 3.2 では、
SHOW TABLE EXTENDED
の出力スキーマはnamespace: string, tableName: string, isTemporary: boolean, information: string
になります。Spark 3.1 以前では、組み込みカタログの場合、namespace
フィールドの名前はdatabase
であり、v2 カタログには変更はありません。組み込みカタログで古いスキーマを復元するには、spark.sql.legacy.keepCommandOutputSchema
をtrue
に設定できます。 -
Spark 3.2 では、テーブルプロパティキーを指定するかどうかにかかわらず、
SHOW TBLPROPERTIES
の出力スキーマはkey: string, value: string
になります。Spark 3.1 以前では、テーブルプロパティキーを指定した場合、SHOW TBLPROPERTIES
の出力スキーマはvalue: string
でした。組み込みカタログで古いスキーマを復元するには、spark.sql.legacy.keepCommandOutputSchema
をtrue
に設定できます。 -
Spark 3.2 では、
DESCRIBE NAMESPACE
の出力スキーマはinfo_name: string, info_value: string
になります。Spark 3.1 以前では、組み込みカタログの場合、info_name
フィールドの名前はdatabase_description_item
であり、info_value
フィールドの名前はdatabase_description_value
でした。組み込みカタログで古いスキーマを復元するには、spark.sql.legacy.keepCommandOutputSchema
をtrue
に設定できます。 - Spark 3.2では、テーブルのリフレッシュは、テーブルのキャッシュデータだけでなく、ビューなどのすべての依存関係のキャッシュデータもクリアしますが、依存関係はキャッシュされたままになります。以下のコマンドがテーブルのリフレッシュを実行します。
ALTER TABLE .. ADD PARTITION
ALTER TABLE .. RENAME PARTITION
ALTER TABLE .. DROP PARTITION
ALTER TABLE .. RECOVER PARTITIONS
MSCK REPAIR TABLE
LOAD DATA
REFRESH TABLE
TRUNCATE TABLE
- およびメソッド
spark.catalog.refreshTable
。Spark 3.1以前では、テーブルのリフレッシュは依存関係を非キャッシュのままにします。
-
Spark 3.2では、あいまいな結果が生じるのを避けるため、
count(tblName.*)
の使用がブロックされます。count(*)
とcount(tblName.*)
は、NULL値がある場合、異なる出力になります。Spark 3.2以前の動作を復元するには、spark.sql.legacy.allowStarWithSingleTableIdentifierInCount
をtrue
に設定できます。 -
Spark 3.2では、INSERTおよびADD/DROP/RENAME PARTITIONのパーティション仕様で型付きリテラルをサポートします。たとえば、
ADD PARTITION(dt = date'2020-01-01')
は、日付値2020-01-01
を持つパーティションを追加します。Spark 3.1以前では、パーティション値は文字列値date '2020-01-01'
として解析されます。これは無効な日付値であり、最後にNULL値を持つパーティションが追加されます。 -
Spark 3.2では、
DataFrameNaFunctions.replace()
は、SQL構文に一致させ、修飾された列名をサポートするために、入力列名に対して厳密な文字列一致を使用しなくなりました。名前(ネストされていない)にドットが含まれる入力列名は、バッククォートでエスケープする必要があります。列がデータフレームスキーマに見つからない場合、AnalysisException
をスローします。また、入力列名がネストされた列である場合は、IllegalArgumentException
をスローします。Spark 3.1以前では、無効な入力列名とネストされた列名を無視していました。 -
Spark 3.2では、
date1 - date2
などの日付減算式は、DayTimeIntervalType
の値を返します。Spark 3.1以前では、返される型はCalendarIntervalType
でした。Spark 3.2以前の動作を復元するには、spark.sql.legacy.interval.enabled
をtrue
に設定できます。 -
Spark 3.2では、
timestamp '2021-03-31 23:48:00' - timestamp '2021-01-01 00:00:00'
などのタイムスタンプ減算式は、DayTimeIntervalType
の値を返します。Spark 3.1以前では、同じ式の型はCalendarIntervalType
でした。Spark 3.2以前の動作を復元するには、spark.sql.legacy.interval.enabled
をtrue
に設定できます。 -
Spark 3.2では、
CREATE TABLE .. LIKE ..
コマンドは予約済みのプロパティを使用できません。それらを指定するには、特定の句が必要です。たとえば、CREATE TABLE test1 LIKE test LOCATION 'some path'
です。spark.sql.legacy.notReserveProperties
をtrue
に設定してParseException
を無視できます。この場合、これらのプロパティはサイレントに削除されます。たとえば、TBLPROPERTIES('owner'='yao')
は効果がありません。Sparkバージョン3.1以下では、予約済みのプロパティはCREATE TABLE .. LIKE ..
コマンドで使用できますが、副作用はありません。たとえば、TBLPROPERTIES('location'='/tmp')
はテーブルの場所を変更しませんが、'a'='b'
のようにヘッドレスプロパティを作成するだけです。 -
Spark 3.2では、
TRANSFORM
演算子は入力でエイリアスをサポートできません。Spark 3.1以前では、SELECT TRANSFORM(a AS c1, b AS c2) USING 'cat' FROM TBL
のようにスクリプト変換を記述できました。 -
Spark 3.2では、
TRANSFORM
演算子は、Hive SerDeなしでArrayType/MapType/StructType
をサポートできます。このモードでは、StructsToJson
を使用して、ArrayType/MapType/StructType
列をSTRING
に変換し、JsonToStructs
を使用して、STRING
をArrayType/MapType/StructType
に解析します。Spark 3.1では、SparkはArrayType/MapType/StructType
列をSTRING
としてサポートするだけで、STRING
をArrayType/MapType/StructType
出力列に解析することはできませんでした。 -
Spark 3.2では、
INTERVAL '1-1' YEAR TO MONTH
のような単位間隔リテラルと、INTERVAL '3' DAYS '1' HOUR
のような単位リスト間隔リテラルは、ANSI間隔型:YearMonthIntervalType
またはDayTimeIntervalType
に変換されます。Spark 3.1以前では、このような間隔リテラルはCalendarIntervalType
に変換されていました。Spark 3.2以前の動作を復元するには、spark.sql.legacy.interval.enabled
をtrue
に設定できます。 -
Spark 3.2では、単位リストの間隔リテラルは、年月のフィールド(YEARとMONTH)と日時フィールド(WEEK、DAY、…、MICROSECOND)を混在させることができません。たとえば、
INTERVAL 1 month 1 hour
はSpark 3.2では無効です。Spark 3.1以前では、このような制限はなく、リテラルはCalendarIntervalType
の値を返します。Spark 3.2以前の動作を復元するには、spark.sql.legacy.interval.enabled
をtrue
に設定できます。 -
Spark 3.2では、SparkはHive
SERDE
モードのTRANSFORM
句の入力および出力としてDayTimeIntervalType
とYearMonthIntervalType
をサポートします。これらの2つの型が入力として使用される場合、HiveSERDE
モードとROW FORMAT DELIMITED
モードでは動作が異なります。HiveSERDE
モードでは、DayTimeIntervalType
列はHiveIntervalDayTime
に変換され、その文字列形式は[-]?d h:m:s.n
ですが、ROW FORMAT DELIMITED
モードでは形式はINTERVAL '[-]?d h:m:s.n' DAY TO TIME
です。HiveSERDE
モードでは、YearMonthIntervalType
列はHiveIntervalYearMonth
に変換され、その文字列形式は[-]?y-m
ですが、ROW FORMAT DELIMITED
モードでは形式はINTERVAL '[-]?y-m' YEAR TO MONTH
です。 -
Spark 3.2では、浮動小数点型の場合、
hash(0) == hash(-0)
です。以前は、異なる値が生成されていました。 -
Spark 3.2では、空ではない
LOCATION
を持つCREATE TABLE AS SELECT
は、AnalysisException
をスローします。Spark 3.2以前の動作を復元するには、spark.sql.legacy.allowNonEmptyLocationInCTAS
をtrue
に設定できます。 -
Spark 3.2では、
epoch
、today
、yesterday
、tomorrow
、およびnow
などの特別な日時値は、型付きリテラルまたは折り畳み可能な文字列のキャストでのみサポートされます。たとえば、select timestamp'now'
やselect cast('today' as date)
です。Spark 3.1および3.0では、このような特別な値は、文字列から日付/タイムスタンプへの任意のキャストでサポートされています。これらの特別な値をSpark 3.1および3.0で日付/タイムスタンプとして保持するには、それらを手動で置き換える必要があります。たとえば、if (c in ('now', 'today'), current_date(), cast(c as date))
のようにします。 -
Spark 3.2では、
FloatType
はMySQLでFLOAT
にマッピングされます。これより前は、MySQLではデフォルトでDOUBLE PRECISION
の同義語であるREAL
にマッピングされていました。 -
Spark 3.2では、
DataFrameWriter
によってトリガーされたクエリ実行は、QueryExecutionListener
に送信されるときに常にcommand
という名前になります。Spark 3.1以前では、名前はsave
、insertInto
、saveAsTable
のいずれかでした。 -
Spark 3.2では、
allowMissingColumns
がtrueに設定されたDataset.unionByName
は、欠落しているネストされたフィールドをstructの最後に追加します。Spark 3.1では、ネストされたstructフィールドはアルファベット順にソートされます。 -
Spark 3.2では、入力クエリの出力列に自動生成されたエイリアスが含まれている場合、ビューの作成/変更は失敗します。これは、クエリの出力列名が異なるSparkバージョン間で安定していることを保証するために必要です。Spark 3.2以前の動作を復元するには、
spark.sql.legacy.allowAutoGeneratedAliasForView
をtrue
に設定します。 - Spark 3.2では、
date '2011-11-11' + interval 12 hours
のような、日時のフィールドのみを含む日付+/-間隔は、タイムスタンプを返します。Spark 3.1以前では、同じ式は日付を返します。Spark 3.2以前の動作を復元するには、cast
を使用してタイムスタンプを日付として変換できます。
Spark SQL 3.0 から 3.1 へのアップグレード
-
Spark 3.1では、統計集計関数である
std
、stddev
、stddev_samp
、variance
、var_samp
、skewness
、kurtosis
、covar_samp
、corr
は、式の評価中にDivideByZero
が発生した場合(例えば、単一要素の集合に対してstddev_samp
が適用された場合など)、Double.NaN
ではなくNULL
を返します。Sparkバージョン3.0以前では、このような場合Double.NaN
を返していました。Spark 3.1以前の動作に戻すには、spark.sql.legacy.statisticalAggregate
をtrue
に設定してください。 -
Spark 3.1では、grouping_id()はlong値を返します。Sparkバージョン3.0以前では、この関数はint値を返していました。Spark 3.1以前の動作に戻すには、
spark.sql.legacy.integerGroupingId
をtrue
に設定してください。 -
Spark 3.1では、SQL UIデータはクエリプランの説明結果に
formatted
モードを採用しています。Spark 3.1以前の動作に戻すには、spark.sql.ui.explainMode
をextended
に設定してください。 -
Spark 3.1では、
from_unixtime
、unix_timestamp
、to_unix_timestamp
、to_timestamp
、to_date
は、指定された日時パターンが無効な場合、失敗します。Spark 3.0以前では、NULL
を返していました。 -
Spark 3.1では、Parquet、ORC、Avro、JSONデータソースは、トップレベルのカラムとネストされた構造の両方で重複する名前を検出した場合、読み込み時に例外
org.apache.spark.sql.AnalysisException: Found duplicate column(s) in the data schema
をスローします。データソースは、カラム名の重複を検出する際にSQL設定spark.sql.caseSensitive
を考慮します。 -
Spark 3.1では、構造体とマップは、文字列にキャストする際に
{}
括弧で囲まれます。例えば、show()
アクションやCAST
式は、このような括弧を使用します。Spark 3.0以前では、同じ目的で[]
括弧が使用されていました。Spark 3.1以前の動作に戻すには、spark.sql.legacy.castComplexTypesToString.enabled
をtrue
に設定してください。 -
Spark 3.1では、構造体、配列、マップのNULL要素は、文字列にキャストする際に「null」に変換されます。Spark 3.0以前では、NULL要素は空文字列に変換されていました。Spark 3.1以前の動作に戻すには、
spark.sql.legacy.castComplexTypesToString.enabled
をtrue
に設定してください。 -
Spark 3.1では、
spark.sql.ansi.enabled
がfalseの場合、10進数型カラムの合計がオーバーフローすると、常にnullを返します。Spark 3.0以前では、この場合、10進数型カラムの合計がnullまたは不正な結果を返す可能性があり、実行時(実際のクエリプランの実行に依存)に失敗する可能性さえありました。 -
Spark 3.1では、以下のメソッドがパスパラメータ付きで呼び出された場合、
path
オプションを共存させることはできません:DataFrameReader.load()
、DataFrameWriter.save()
、DataStreamReader.load()
、またはDataStreamWriter.start()
。さらに、DataFrameReader.load()
ではpaths
オプションを共存させることはできません。例えば、spark.read.format("csv").option("path", "/tmp").load("/tmp2")
またはspark.read.option("path", "/tmp").csv("/tmp2")
は、org.apache.spark.sql.AnalysisException
をスローします。Sparkバージョン3.0以前では、上記のメソッドに1つのパスパラメータが渡された場合、path
オプションが上書きされます。DataFrameReader.load()
に複数のパスパラメータが渡された場合、path
オプションが全体のパスに追加されます。Spark 3.1以前の動作に戻すには、spark.sql.legacy.pathOptionBehavior.enabled
をtrue
に設定してください。 -
Spark 3.1では、不正な不完全な間隔リテラル(例:
INTERVAL '1'
、INTERVAL '1 DAY 2'
)に対してIllegalArgumentException
が返されます。Spark 3.0では、これらのリテラルはNULL
になります。 -
Spark 3.1では、組み込みのHive 1.2を削除しました。カスタムSerDesをHive 2.3に移行する必要があります。詳細については、HIVE-15167を参照してください。
-
Spark 3.1では、タイムスタンプが1900-01-01 00:00:00Zより前のタイムスタンプをparquetファイルから/へ読み込み/保存する場合、INT96型としてロード(保存)されると失敗します。Spark 3.0では、アクションは失敗しませんが、ユリウス暦からプロレプティックグレゴリオ暦への変換により、入力タイムスタンプがシフトする可能性があります。Spark 3.1以前の動作に戻すには、
spark.sql.legacy.parquet.int96RebaseModeInRead
または/およびspark.sql.legacy.parquet.int96RebaseModeInWrite
をLEGACY
に設定してください。 -
Spark 3.1では、
schema_of_json
関数とschema_of_csv
関数は、フィールド名が引用符で囲まれたSQL形式でスキーマを返します。Spark 3.0では、関数はフィールド引用符なしで小文字のカタログ文字列を返します。 -
Spark 3.1では、テーブルをリフレッシュすると、テーブル自体がキャッシュされていない場合でも、テーブルを参照する他のすべてのキャッシュのアンキャッシュ操作がトリガーされます。Spark 3.0では、テーブル自体がキャッシュされている場合にのみ、操作がトリガーされます。
-
Spark 3.1では、永続的なビューを作成または変更すると、ランタイムSQL設定がキャプチャされ、ビュープロパティとして保存されます。これらの設定は、ビュー解決の解析および分析フェーズ中に適用されます。Spark 3.1以前の動作に戻すには、
spark.sql.legacy.useCurrentConfigsForView
をtrue
に設定してください。 -
Spark 3.1では、一時ビューは永続ビューと同じ動作になります。つまり、ランタイムSQL設定、SQLテキスト、カタログ、名前空間をキャプチャして保存します。キャプチャされたビュープロパティは、ビュー解決の解析および分析フェーズ中に適用されます。Spark 3.1以前の動作に戻すには、
spark.sql.legacy.storeAnalyzedPlanForView
をtrue
に設定してください。 -
Spark 3.1では、
CACHE TABLE ... AS SELECT
を使用して作成された一時ビューも、永続ビューと同じ動作になります。特に、一時ビューが削除されると、Sparkはそのキャッシュ依存関係をすべて無効にし、一時ビュー自体のキャッシュも無効にします。これは、後者のみを実行するSpark 3.0以前とは異なります。以前の動作に戻すには、spark.sql.legacy.storeAnalyzedPlanForView
をtrue
に設定してください。 -
Spark 3.1以降、CHAR/CHARACTER型とVARCHAR型がテーブルスキーマでサポートされています。テーブルスキャン/挿入は、char/varcharセマンティクスを尊重します。char/varcharがテーブルスキーマ以外の場所で使用されている場合、例外がスローされます(CASTは例外であり、以前のようにchar/varcharを文字列として扱います)。
CHAR(4)
などのように、STRING型として扱い、長さパラメータを無視するSpark 3.1以前の動作に戻すには、spark.sql.legacy.charVarcharAsString
をtrue
に設定してください。 -
Spark 3.1では、次の状況で、Hive外部カタログからのテーブルに対してスローされる
AnalysisException
が、そのサブクラスに置き換えられます。ALTER TABLE .. ADD PARTITION
は、新しいパーティションがすでに存在する場合、PartitionsAlreadyExistException
をスローします。ALTER TABLE .. DROP PARTITION
は、存在しないパーティションに対してNoSuchPartitionsException
をスローします。
Spark SQL 3.0.1 から 3.0.2 へのアップグレード
- Spark 3.0.2では、次の状況で、Hive外部カタログからのテーブルに対してスローされる
AnalysisException
が、そのサブクラスに置き換えられます。ALTER TABLE .. ADD PARTITION
は、新しいパーティションがすでに存在する場合、PartitionsAlreadyExistException
をスローします。ALTER TABLE .. DROP PARTITION
は、存在しないパーティションに対してNoSuchPartitionsException
をスローします。
-
Spark 3.0.2では、
PARTITION(col=null)
は、パーティション指定で常にnullリテラルとして解析されます。Spark 3.0.1以前では、パーティションカラムが文字列型の場合、テキスト表現の文字列リテラル(例:文字列「null」)として解析されます。以前の動作を復元するには、spark.sql.legacy.parseNullPartitionSpecAsStringLiteral
をtrueに設定できます。 - Spark 3.0.2では、
SHOW DATABASES
の出力スキーマがnamespace: string
になります。Sparkバージョン3.0.1以前では、スキーマはdatabaseName: string
でした。Spark 3.0.2以降では、spark.sql.legacy.keepCommandOutputSchema
をtrue
に設定することで、古いスキーマを復元できます。
Spark SQL 3.0 から 3.0.1 へのアップグレード
-
Spark 3.0では、JSONデータソースとJSON関数
schema_of_json
は、JSONオプションtimestampFormat
で定義されたパターンに一致する場合、文字列値からTimestampTypeを推論します。バージョン3.0.1以降、タイムスタンプ型の推論はデフォルトで無効になっています。このような型推論を有効にするには、JSONオプションinferTimestamp
をtrue
に設定します。 -
Spark 3.0 では、文字列型から整数型 (tinyint, smallint, int, bigint)、日時型 (date, timestamp, interval)、およびブール型へのキャスト時に、先頭と末尾の文字 (ASCII 32 以下) がトリムされます。例えば、
cast('\b1\b' as int)
の結果は1
になります。Spark 3.0.1 以降では、先頭と末尾の空白 ASCII 文字のみがトリムされます。例えば、cast('\t1\t' as int)
の結果は1
になりますが、cast('\b1\b' as int)
の結果はNULL
になります。
Spark SQL 2.4 から 3.0 へのアップグレード
データセット/データフレーム API
-
Spark 3.0 では、Dataset および DataFrame API の
unionAll
が非推奨ではなくなりました。これはunion
のエイリアスです。 -
Spark 2.4 およびそれ以前のバージョンでは、
Dataset.groupByKey
は、キーが int, string, array などの非構造型の場合、キー属性が誤って "value" という名前のグループ化されたデータセットになります。これは直感的ではなく、集計クエリのスキーマが予期しないものになります。例えば、ds.groupByKey(...).count()
のスキーマは(value, count)
になります。Spark 3.0 以降では、グループ化属性の名前が "key" になります。古い動作は、新しく追加された構成spark.sql.legacy.dataset.nameNonStructGroupingKeyAsValue
(デフォルト値はfalse
) で維持されます。 -
Spark 3.0 では、
Column.name
およびColumn.as
API で常に列のメタデータが伝播されます。Spark バージョン 2.4 以前では、NamedExpression
のメタデータは、API が呼び出されたときに新しい列のexplicitMetadata
として設定され、基になるNamedExpression
がメタデータを変更しても変更されません。Spark 3.0 より前の動作を復元するには、明示的なメタデータを使用してas(alias: String, metadata: Metadata)
API を使用できます。 -
Dataset を別の Dataset に変換する場合、Spark は元の Dataset のフィールドをターゲット DataSet の対応するフィールドの型にアップキャストします。バージョン 2.4 以前では、このアップキャストはあまり厳密ではありませんでした。例えば、
Seq("str").toDS.as[Int]
は失敗しますが、Seq("str").toDS.as[Boolean]
は動作し、実行中に NPE をスローします。Spark 3.0 では、アップキャストがより厳密になり、String を他の型に変換することは許可されません。つまり、Seq("str").toDS.as[Boolean]
は分析中に失敗します。Spark 3.0 より前の動作を復元するには、spark.sql.legacy.doLooseUpcast
をtrue
に設定します。
DDL ステートメント
-
Spark 3.0 では、異なるデータ型のテーブル列に値を挿入する場合、ANSI SQL 標準に従って型変換が実行されます。
string
からint
への変換や、double
からboolean
への変換など、一部の不合理な型変換は許可されません。値が列のデータ型の範囲外である場合は、ランタイム例外がスローされます。Spark バージョン 2.4 以前では、テーブル挿入時の型変換は、有効なCast
である限り許可されていました。範囲外の値を整数フィールドに挿入すると、値の下位ビットが挿入されます (Java/Scala の数値型キャストと同じ)。例えば、257 をバイト型のフィールドに挿入すると、結果は 1 になります。この動作は、オプションspark.sql.storeAssignmentPolicy
で制御され、デフォルト値は "ANSI" です。オプションを "Legacy" に設定すると、以前の動作が復元されます。 -
ADD JAR
コマンドは、以前は単一の値 0 を持つ結果セットを返していました。現在は空の結果セットを返します。 -
Spark 2.4 およびそれ以前:
SET
コマンドは、指定されたキーがSparkConf
エントリ用であっても、警告なしで動作します。コマンドはSparkConf
を更新しないため、効果はありませんが、この動作はユーザーを混乱させる可能性があります。3.0 では、SparkConf
キーが使用されている場合、コマンドは失敗します。このチェックを無効にするには、spark.sql.legacy.setCommandRejectsSparkCoreConfs
をfalse
に設定します。 -
キャッシュされたテーブルを更新すると、テーブルのキャッシュ解除操作がトリガーされ、次にテーブルのキャッシュ (遅延) 操作がトリガーされます。Spark バージョン 2.4 以前では、キャッシュ名とストレージレベルはキャッシュ解除操作の前に保持されません。したがって、キャッシュ名とストレージレベルが予期せず変更される可能性があります。Spark 3.0 では、キャッシュ名とストレージレベルがキャッシュ再作成のために最初に保持されます。これにより、テーブルの更新時に一貫したキャッシュ動作を維持できます。
-
Spark 3.0 では、以下に示すプロパティが予約されます。
CREATE DATABASE ... WITH DBPROPERTIES
やALTER TABLE ... SET TBLPROPERTIES
のような場所で予約されたプロパティを指定すると、コマンドは失敗します。それらのプロパティを指定するには、例えばCREATE DATABASE test COMMENT '任意のコメント' LOCATION '任意のパス'
のように、特定の句が必要です。spark.sql.legacy.notReserveProperties
をtrue
に設定してParseException
を無視できます。この場合、これらのプロパティは黙って削除されます。例えば、SET DBPROPERTIES('location'='/tmp')
は効果がありません。Spark バージョン 2.4 以前では、これらのプロパティは予約されておらず、副作用もありません。例えば、SET DBPROPERTIES('location'='/tmp')
はデータベースの場所を変更せず、'a'='b'
と同じようにヘッドレスプロパティを作成するだけです。プロパティ (大文字と小文字を区別) データベース予約 テーブル予約 備考 provider いいえ はい テーブルの場合は、それを指定するために USING
句を使用します。一度設定すると、変更することはできません。location はい はい データベースとテーブルの場合は、それを指定するために LOCATION
句を使用します。owner はい はい データベースとテーブルの場合は、spark を実行してテーブルを作成するユーザーによって決定されます。 -
Spark 3.0 では、
ADD FILE
を使用してファイルディレクトリも追加できます。以前は、このコマンドを使用して単一のファイルのみを追加できました。以前のバージョンの動作を復元するには、spark.sql.legacy.addSingleFileInAddFile
をtrue
に設定します。 -
Spark 3.0 では、テーブルが存在しない場合、
SHOW TBLPROPERTIES
はAnalysisException
をスローします。Spark バージョン 2.4 以前では、このシナリオはNoSuchTableException
を引き起こしていました。 -
Spark 3.0 では、
SHOW CREATE TABLE table_identifier
は、指定されたテーブルが Hive SerDe テーブルであっても、常に Spark DDL を返します。Hive DDL を生成するには、代わりにSHOW CREATE TABLE table_identifier AS SERDE
コマンドを使用します。 -
Spark 3.0 では、CHAR 型の列は Hive-Serde 以外のテーブルでは許可されておらず、CHAR 型が検出されると CREATE/ALTER TABLE コマンドは失敗します。代わりに STRING 型を使用してください。Spark バージョン 2.4 以前では、CHAR 型は STRING 型として扱われ、長さパラメーターは単に無視されます。
UDF と組み込み関数
-
Spark 3.0 では、
date_add
およびdate_sub
関数は、2 番目の引数として int, smallint, tinyint のみを受け入れます。小数や非リテラル文字列は無効になりました。例えば、date_add(cast('1964-05-23' as date), '12.34')
はAnalysisException
を引き起こします。文字列リテラルは引き続き許可されますが、文字列の内容が有効な整数でない場合、Spark はAnalysisException
をスローします。Spark バージョン 2.4 以前では、2 番目の引数が小数または文字列値の場合、int 値に強制変換され、結果は1964-06-04
の日付値になります。 -
Spark 3.0 では、関数
percentile_approx
およびそのエイリアスapprox_percentile
は、3 番目の引数accuracy
として[1, 2147483647]
の範囲の整数値のみを受け入れます。小数および文字列型は許可されていません。例えば、percentile_approx(10.0, 0.2, 1.8D)
はAnalysisException
を引き起こします。Spark バージョン 2.4 以前では、accuracy
が小数または文字列値の場合、int 値に強制変換されます。percentile_approx(10.0, 0.2, 1.8D)
はpercentile_approx(10.0, 0.2, 1)
として操作され、結果は10.0
になります。 -
Spark 3.0 では、ハッシュ式が
MapType
の要素に適用されると、分析例外がスローされます。Spark 3.0 より前の動作を復元するには、spark.sql.legacy.allowHashOnMapType
をtrue
に設定します。 -
Spark 3.0 では、
array
/map
関数がパラメータなしで呼び出されると、要素型がNullType
の空のコレクションが返されます。Spark バージョン 2.4 以前では、要素型がStringType
の空のコレクションが返されます。Spark 3.0 より前の動作を復元するには、spark.sql.legacy.createEmptyCollectionUsingStringType
をtrue
に設定できます。 -
Spark 3.0 では、
from_json
関数は、PERMISSIVE
およびFAILFAST
の 2 つのモードをサポートします。モードはmode
オプションを介して設定できます。デフォルトモードはPERMISSIVE
になりました。以前のバージョンでは、from_json
の動作は、特に不正な形式の JSON レコードの処理において、PERMISSIVE
にもFAILFAST
にも準拠していませんでした。例えば、スキーマa INT
の JSON 文字列{"a" 1}
は、以前のバージョンではnull
に変換されていましたが、Spark 3.0 ではRow(null)
に変換されます。 -
Sparkバージョン2.4以前では、
CreateMap
、MapFromArrays
などの組み込み関数を使用して、マップ型のキーを持つマップ値を作成できました。Spark 3.0では、これらの組み込み関数を使用してマップ型のキーを持つマップ値を作成することは許可されていません。ユーザーは、map_entries
関数を使用して、マップをarray<struct<key, value»に変換することで回避できます。さらに、データソースやJava/Scalaコレクションからマップ型のキーを持つマップ値を読み込むことはできますが、推奨されません。 -
Sparkバージョン2.4以前では、
CreateMap
、StringToMap
などの組み込み関数を使用して、重複したキーを持つマップを作成できました。重複したキーを持つマップの動作は未定義です。例えば、マップの検索では最初に現れる重複キーが尊重され、Dataset.collect
では最後に現れる重複キーのみが保持され、MapKeys
は重複したキーを返します。Spark 3.0では、重複したキーが見つかるとSparkはRuntimeException
をスローします。spark.sql.mapKeyDedupPolicy
をLAST_WIN
に設定することで、最後の勝ちポリシーでマップキーを重複排除できます。ユーザーは、重複を強制しないデータソース(例えば、Parquet)から重複したキーを持つマップ値を読み込むことができますが、動作は未定義です。 -
Spark 3.0では、
org.apache.spark.sql.functions.udf(AnyRef, DataType)
の使用はデフォルトでは許可されていません。型付きScala UDFに自動的に切り替えるためには、戻り値の型パラメータを削除することが推奨されます。または、spark.sql.legacy.allowUntypedScalaUDF
をtrueに設定して、引き続き使用することもできます。Sparkバージョン2.4以前では、org.apache.spark.sql.functions.udf(AnyRef, DataType)
がプリミティブ型の引数を持つScalaクロージャを取得した場合、入力値がnullの場合、返されるUDFはnullを返します。しかし、Spark 3.0では、入力値がnullの場合、UDFはJava型のデフォルト値を返します。例えば、val f = udf((x: Int) => x, IntegerType)
の場合、f($"x")
は、列x
がnullの場合、Spark 2.4以前ではnullを返し、Spark 3.0では0を返します。この動作の変更は、Spark 3.0がデフォルトでScala 2.12でビルドされているために導入されました。 -
Spark 3.0では、高階関数
exists
は三値論理に従います。つまり、predicate
がnull
を返し、true
が得られない場合、exists
はfalse
の代わりにnull
を返します。例えば、exists(array(1, null, 3), x -> x % 2 == 0)
はnull
です。以前の動作は、spark.sql.legacy.followThreeValuedLogicInArrayExists
をfalse
に設定することで復元できます。 -
Spark 3.0では、
add_months
関数は、元の日にちが月の最終日の場合でも、結果の日付を月の最終日に調整しません。例えば、select add_months(DATE'2019-02-28', 1)
の結果は2019-03-28
になります。Sparkバージョン2.4以前では、元の日にちが月の最終日の場合、結果の日付が調整されます。例えば、2019-02-28
に1ヶ月を加算すると、2019-03-31
になります。 -
Sparkバージョン2.4以前では、
current_timestamp
関数はミリ秒の精度を持つタイムスタンプのみを返します。Spark 3.0では、システムの基盤となるクロックがそのような精度を提供する場合、関数はマイクロ秒の精度を持つ結果を返すことができます。 -
Spark 3.0では、引数なしのJava UDFは、他のUDFと同一に、executor側で実行されます。Sparkバージョン2.4以前では、引数なしのJava UDFのみがdriver側で実行され、結果がexecutorに伝播されていました。これにより、一部のケースではパフォーマンスが向上しましたが、一部のケースでは正確性の問題との不整合を引き起こしました。
-
java.lang.Math
のlog
、log1p
、exp
、expm1
、およびpow
の結果は、プラットフォームによって異なる場合があります。Spark 3.0では、同等のSQL関数(LOG10
などの関連するSQL関数を含む)の結果は、java.lang.StrictMath
と一貫した値を返します。実際には、ほとんどすべての場合で戻り値に違いはなく、違いは非常に小さいものですが、例えば、log(3.0)
のような場合、x86プラットフォームではMath.log()
とStrictMath.log()
の間で値が異なる場合があります。 -
Spark 3.0では、
cast
関数は、Double
型またはFloat
型にリテラルをキャストする場合、他のデータベースシステムとの互換性を高めるために、「Infinity」、「+Infinity」、「-Infinity」、「NaN」、「Inf」、「+Inf」、「-Inf」などの文字列リテラルを大文字と小文字を区別せずに処理します。この動作の変更を以下の表に示します。操作 Spark 3.0以前の結果 Spark 3.0での結果 CAST(‘infinity’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘+infinity’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘inf’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘inf’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘-infinity’ AS DOUBLE) NULL Double.NegativeInfinity CAST(‘-inf’ AS DOUBLE) NULL Double.NegativeInfinity CAST(‘infinity’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘+infinity’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘inf’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘+inf’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘-infinity’ AS FLOAT) NULL Float.NegativeInfinity CAST(‘-inf’ AS FLOAT) NULL Float.NegativeInfinity CAST(‘nan’ AS DOUBLE) NULL Double.NaN CAST(‘nan’ AS FLOAT) NULL Float.NaN -
Spark 3.0では、interval値を文字列型にキャストする場合、「interval」プレフィックスは付きません。例えば、
1 days 2 hours
のようになります。Sparkバージョン2.4以前では、文字列にはinterval 1 days 2 hours
のような「interval」プレフィックスが含まれていました。 -
Spark 3.0では、文字列値を整数型(tinyint、smallint、int、bigint)、日付時刻型(date、timestamp、interval)、およびboolean型にキャストする場合、これらの型値に変換する前に先頭と末尾の空白(<= ASCII 32)がトリミングされます。例えば、
cast(' 1\t' as int)
の結果は1
、cast(' 1\t' as boolean)
の結果はtrue
、cast('2019-10-10\t as date)
の結果は日付値2019-10-10
になります。Sparkバージョン2.4以前では、文字列を整数型とboolean型にキャストする場合、両端の空白はトリミングされません。前述の結果はnull
になります。一方、日付時刻型では、末尾の空白(= ASCII 32)のみが削除されます。
クエリエンジン
-
Sparkバージョン2.4以前では、
FROM <table>
やFROM <table> UNION ALL FROM <table>
のようなSQLクエリが偶然サポートされていました。hiveスタイルのFROM <table> SELECT <expr>
では、SELECT
句は無視できません。HiveもPrestoもこの構文をサポートしていません。これらのクエリは、Spark 3.0では無効として扱われます。 -
Spark 3.0では、intervalリテラルの構文で、複数のfrom-toユニットが許可されなくなりました。例えば、
SELECT INTERVAL '1-1' YEAR TO MONTH '2-2' YEAR TO MONTH'
はパーサー例外をスローします。 -
Spark 3.0では、科学的記法で書かれた数値(例えば、
1E2
)はDoubleとして解析されます。Sparkバージョン2.4以前では、Decimalとして解析されていました。Spark 3.0以前の動作を復元するには、spark.sql.legacy.exponentLiteralAsDecimal.enabled
をtrue
に設定できます。 -
Spark 3.0では、日時のinterval文字列は、
from
とto
の境界に関してintervalに変換されます。入力文字列が指定された境界で定義されたパターンに一致しない場合、ParseException
例外がスローされます。例えば、interval '2 10:20' hour to minute
は、期待される形式が[+|-]h[h]:[m]m
であるため、例外を発生させます。Sparkバージョン2.4では、from
境界は考慮されず、to
境界を使用して、結果のintervalが切り捨てられていました。例えば、示した例の日時のinterval文字列はinterval 10 hours 20 minutes
に変換されます。Spark 3.0以前の動作を復元するには、spark.sql.legacy.fromDayTimeString.enabled
をtrue
に設定できます。 -
Spark 3.0では、10進数の負のスケールはデフォルトでは許可されていません。例えば、
1E10BD
のようなリテラルのデータ型はDecimalType(11, 0)
です。Sparkバージョン2.4以前では、DecimalType(2, -9)
でした。Spark 3.0以前の動作を復元するには、spark.sql.legacy.allowNegativeScaleOfDecimal
をtrue
に設定できます。 -
Spark 3.0では、単項算術演算子プラス(
+
)は、入力として文字列、数値、およびinterval型の値のみを受け入れます。さらに、整数の文字列表現を持つ+
はdouble値に強制変換されます。例えば、+'1'
は1.0
を返します。Sparkバージョン2.4以前では、この演算子は無視されます。それに対する型チェックはなく、したがって、+
プレフィックスを持つすべての型値は有効です。例えば、+ array(1, 2)
は有効で、結果は[1, 2]
になります。さらに、それに対する型強制はまったくありません。例えば、Spark 2.4では、+'1'
の結果は文字列1
です。 -
Spark 3.0では、自己結合によって引き起こされるあいまいな列参照が含まれる場合、Datasetクエリは失敗します。典型的な例:
val df1 = ...; val df2 = df1.filter(...);
の場合、df1.join(df2, df1("a") > df2("a"))
は、非常に紛らわしい空の結果を返します。これは、Sparkが自己結合されているテーブルを指すDataset列参照を解決できず、Sparkではdf1("a")
がdf2("a")
とまったく同じであるためです。Spark 3.0以前の動作を復元するには、spark.sql.analyzer.failAmbiguousSelfJoin
をfalse
に設定できます。 -
Spark 3.0では、ネストされたWITH句における名前の競合の挙動を制御するために、
spark.sql.legacy.ctePrecedencePolicy
が導入されました。デフォルト値のEXCEPTION
の場合、SparkはAnalysisExceptionをスローし、ユーザーが意図する具体的な置換順序を選択することを強制します。CORRECTED
(推奨)に設定すると、内側のCTE定義が外側の定義よりも優先されます。例えば、この設定をfalse
にすると、WITH t AS (SELECT 1), t2 AS (WITH t AS (SELECT 2) SELECT * FROM t) SELECT * FROM t2
は2
を返しますが、LEGACY
に設定すると、バージョン2.4以前の挙動である1
が返されます。 -
Spark 3.0では、設定
spark.sql.crossJoin.enabled
は内部設定となり、デフォルトでtrueになりました。そのため、デフォルトでは暗黙的なクロスジョインを含むSQLで例外が発生することはありません。 -
Spark バージョン2.4以前では、float/double型の -0.0 は意味的に 0.0 と等価でしたが、集計のグループ化キー、ウィンドウのパーティションキー、および結合キーで使用される場合は、-0.0 と 0.0 は異なる値と見なされていました。Spark 3.0 では、このバグが修正されました。例えば、
Seq(-0.0, 0.0).toDF("d").groupBy("d").count()
は Spark 3.0 では[(0.0, 2)]
を返しますが、Spark 2.4 以前では[(0.0, 1), (-0.0, 1)]
を返します。 -
Spark バージョン2.4以前では、無効なタイムゾーンIDは暗黙的に無視され、GMTタイムゾーンに置き換えられていました(例:from_utc_timestamp関数)。Spark 3.0では、そのようなタイムゾーンIDは拒否され、Sparkは
java.time.DateTimeException
をスローします。 -
Spark 3.0では、日付とタイムスタンプの解析、フォーマット、変換、および年、日などのサブコンポーネントの抽出に、先発グレゴリオ暦が使用されます。Spark 3.0では、ISO暦 に基づいた
java.time
パッケージの Java 8 API クラスが使用されます。Spark バージョン2.4以前では、これらの操作はハイブリッド暦 (ユリウス暦 + グレゴリオ暦) を使用して実行されていました。この変更は、1582年10月15日(グレゴリオ暦)以前の日付の結果に影響を与え、次の Spark 3.0 API に影響します。-
タイムスタンプ/日付文字列の解析/フォーマット。これはCSV/JSONデータソース、およびユーザーが指定したパターンが解析とフォーマットに使用される場合の
unix_timestamp
,date_format
,to_unix_timestamp
,from_unixtime
,to_date
,to_timestamp
関数に影響します。Spark 3.0では、フォーマットおよび解析のための日時パターン で独自のパターン文字列を定義しており、これは内部的には DateTimeFormatter を使用して実装されています。新しい実装では、入力の厳密なチェックが行われます。例えば、パーサーが入力全体を消費しないため、2015-07-22 10:00:00
タイムスタンプは、パターンがyyyy-MM-dd
の場合は解析できません。別の例として、31/01/2015 00:00
入力は、hh
が1-12
の範囲の時間を想定しているため、dd/MM/yyyy hh:mm
パターンで解析できません。Spark バージョン2.4以前では、タイムスタンプ/日付文字列の変換にjava.text.SimpleDateFormat
が使用され、サポートされるパターンは SimpleDateFormat に記述されています。以前の挙動は、spark.sql.legacy.timeParserPolicy
をLEGACY
に設定することで復元できます。 -
weekofyear
,weekday
,dayofweek
,date_trunc
,from_utc_timestamp
,to_utc_timestamp
, およびunix_timestamp
関数は、年の週番号、曜日の日番号の計算、およびUTCタイムゾーンのTimestampType値との変換にjava.time APIを使用します。 -
JDBCオプションの
lowerBound
およびupperBound
は、文字列をTimestampType/DateType値にキャストするのと同じ方法でTimestampType/DateType値に変換されます。変換は先発グレゴリオ暦、およびSQL設定spark.sql.session.timeZone
で定義されたタイムゾーンに基づいています。Spark バージョン2.4以前では、変換はハイブリッド暦(ユリウス暦 + グレゴリオ暦)およびデフォルトのシステムタイムゾーンに基づいていました。 -
TIMESTAMP
およびDATE
リテラルのフォーマット。 -
文字列から型付き
TIMESTAMP
およびDATE
リテラルを作成します。Spark 3.0では、型付きTIMESTAMP
/DATE
リテラルへの文字列変換は、TIMESTAMP
/DATE
値へのキャストを介して実行されます。例えば、TIMESTAMP '2019-12-23 12:59:30'
は意味的にCAST('2019-12-23 12:59:30' AS TIMESTAMP)
と等価です。入力文字列にタイムゾーンに関する情報が含まれていない場合、その場合はSQL設定spark.sql.session.timeZone
のタイムゾーンが使用されます。Spark バージョン2.4以前では、変換はJVMシステムタイムゾーンに基づいていました。デフォルトタイムゾーンの異なるソースは、型付きTIMESTAMP
およびDATE
リテラルの挙動を変更する可能性があります。
-
-
Spark 3.0では、
TIMESTAMP
リテラルはSQL設定spark.sql.session.timeZone
を使用して文字列に変換されます。Spark バージョン2.4以前では、変換はJava仮想マシンのデフォルトタイムゾーンを使用します。 -
Spark 3.0では、日付/タイムスタンプとのバイナリ比較において、Sparkは
String
をDate/Timestamp
にキャストします。Date/Timestamp
をString
にキャストする以前の挙動は、spark.sql.legacy.typeCoercion.datetimeToString.enabled
をtrue
に設定することで復元できます。 - Spark 3.0では、文字列から日付とタイムスタンプへの変換で特別な値がサポートされています。これらの値は単に表記上の省略形で、読み取り時に通常の日付またはタイムスタンプ値に変換されます。次の文字列値が日付でサポートされています。
epoch [zoneId]
- 1970-01-01today [zoneId]
-spark.sql.session.timeZone
で指定されたタイムゾーンの現在の日付yesterday [zoneId]
- 現在の日付 - 1tomorrow [zoneId]
- 現在の日付 + 1now
- 現在のクエリを実行する日付。todayと同じ概念を持ちます
例えば
SELECT date 'tomorrow' - date 'yesterday';
は2
を出力する必要があります。以下は特別なタイムスタンプ値です。epoch [zoneId]
- 1970-01-01 00:00:00+00 (Unixシステム時間のゼロ)today [zoneId]
- 今日の深夜yesterday [zoneId]
- 昨日の深夜tomorrow [zoneId]
- 明日の深夜now
- 現在のクエリ開始時間
例えば
SELECT timestamp 'tomorrow';
のようにします。 -
Spark 3.0以降では、
EXTRACT
式を使用して日付/タイムスタンプ値から秒フィールドを抽出する場合、結果は秒の部分に2桁、マイクロ秒の精度で小数部分に6桁を持つDecimalType(8, 6)
値になります。例えば、extract(second from to_timestamp('2019-09-20 10:10:10.1'))
は10.100000
を返します。Spark バージョン2.4以前では、IntegerType
値が返され、前述の例の結果は10
になります。 -
Spark 3.0では、日時パターン文字
F
は、月の中の整列された曜日であり、週が月の開始に整列する週の期間内の日数のカウントの概念を表します。Spark バージョン2.4以前では、月の週であり、週が固定の曜日から始まる月内の週数のカウントの概念を表します。例えば、2020-07-30
は月の最初の日から30日(4週間と2日)後なので、date_format(date '2020-07-30', 'F')
は Spark 3.0 では 2 を返しますが、Spark 2.x の週数として、7月2020年の5週目に位置しているため 5 を返します。ここで1週目は 2020-07-01 から 07-04 です。 -
Spark 3.0では、Sparkは
CTAS
でHive serdeの代わりに組み込みのデータソースライターを使用しようとします。この挙動は、ParquetおよびORC形式でそれぞれspark.sql.hive.convertMetastoreParquet
またはspark.sql.hive.convertMetastoreOrc
が有効になっている場合にのみ有効です。Spark 3.0以前の挙動を復元するには、spark.sql.hive.convertMetastoreCtas
をfalse
に設定できます。 - Spark 3.0では、SparkはHiveSQL構文を使用して作成されたパーティション化されたORC/Parquetテーブルへの挿入処理に、Hive serdeの代わりに組み込みのデータソースライターを使用しようとします。この挙動は、ParquetおよびORC形式でそれぞれ
spark.sql.hive.convertMetastoreParquet
またはspark.sql.hive.convertMetastoreOrc
が有効になっている場合にのみ有効です。Spark 3.0以前の挙動を復元するには、spark.sql.hive.convertInsertingPartitionedTable
をfalse
に設定できます。
データソース
-
Sparkバージョン2.4以前では、Sparkネイティブデータソース(parquet/orc)でHive SerDeテーブルを読み込む際に、Sparkは実際のファイルスキーマを推論し、メタストアのテーブルスキーマを更新していました。Spark 3.0では、Sparkはスキーマを推論しなくなりました。これはエンドユーザーに問題を引き起こすことはありませんが、問題が発生した場合は、
spark.sql.hive.caseSensitiveInferenceMode
をINFER_AND_SAVE
に設定してください。 -
Sparkバージョン2.4以前では、パーティション列の値は、対応するユーザー指定のスキーマにキャストできない場合、nullに変換されていました。3.0では、パーティション列の値はユーザー指定のスキーマで検証されます。検証に失敗すると例外がスローされます。この検証を無効にするには、
spark.sql.sources.validatePartitionColumns
をfalse
に設定します。 -
Spark 3.0では、再帰的なディレクトリリスト中にファイルまたはサブディレクトリが消失した場合(つまり、中間リストには表示されるが、同時ファイル削除またはオブジェクトストアの整合性の問題により、再帰的なディレクトリリストの後の段階で読み取りまたはリスト表示できない場合)、
spark.sql.files.ignoreMissingFiles
がtrue
(デフォルトはfalse
)でない限り、リストは例外で失敗します。以前のバージョンでは、これらの欠落したファイルまたはサブディレクトリは無視されていました。この動作の変更は、初期のテーブルファイルリスト(またはREFRESH TABLE
中)にのみ適用され、クエリの実行中には適用されません。つまり、spark.sql.files.ignoreMissingFiles
は、クエリ実行時だけでなく、テーブルファイルリスト/クエリプランニング中にも遵守されるようになりました。 -
Sparkバージョン2.4以前では、JSONデータソースのパーサーは、
IntegerType
などの一部のデータ型に対して空文字列をnullとして扱っていました。FloatType
、DoubleType
、DateType
、TimestampType
の場合は、空文字列で失敗し、例外をスローしていました。Spark 3.0では、空文字列は許可されず、StringType
およびBinaryType
を除くデータ型に対して例外がスローされます。空文字列を許可するという以前の動作は、spark.sql.legacy.json.allowEmptyString.enabled
をtrue
に設定することで復元できます。 -
Sparkバージョン2.4以前では、JSONデータソースおよび
from_json
などのJSON関数は、指定されたスキーマがStructType
の場合、PERMISSIVEモードで不正なJSONレコードをすべてnull
の行に変換していました。Spark 3.0では、一部のJSON列の値が解析され、目的の型に正常に変換された場合、返される行に非null
フィールドを含めることができます。 -
Spark 3.0では、JSONデータソースおよびJSON関数
schema_of_json
は、文字列値がJSONオプションtimestampFormat
で定義されたパターンに一致する場合、文字列値からTimestampTypeを推論します。このような型推論を無効にするには、JSONオプションinferTimestamp
をfalse
に設定します。 -
Sparkバージョン2.4以前では、CSVデータソースは、PERMISSIVEモードで不正なCSV文字列をすべて
null
の行に変換していました。Spark 3.0では、一部のCSV列の値が解析され、目的の型に正常に変換された場合、返される行に非null
フィールドを含めることができます。 -
Spark 3.0では、ユーザー指定のスキーマでAvroファイルが書き込まれる場合、フィールドは位置ではなく、CatalystスキーマとAvroスキーマの間でフィールド名によって照合されます。
-
Spark 3.0では、ユーザー指定の非nullスキーマでAvroファイルが書き込まれる場合、Catalystスキーマがnull可能であっても、Sparkはファイルを書き込むことができます。ただし、レコードにnullが含まれている場合、Sparkは実行時にNullPointerExceptionをスローします。
-
Sparkバージョン2.4以前では、CSVデータソースは、ファイルの先頭にBOMがある場合、入力ファイルのエンコーディングを自動的に検出できました。たとえば、CSVデータソースは、マルチラインモード(CSVオプション
multiLine
がtrue
に設定されている場合)でUTF-8、UTF-16BE、UTF-16LE、UTF-32BE、UTF-32LEを認識できました。Spark 3.0では、CSVデータソースは、デフォルト値がUTF-8であるCSVオプションencoding
で指定されたエンコーディングで入力ファイルを読み取ります。このため、ファイルのエンコーディングがCSVオプションで指定されたエンコーディングと一致しない場合、Sparkはファイルを正しくロードしません。この問題を解決するには、ユーザーはCSVオプションencoding
で正しいエンコーディングを設定するか、3.0より前のSparkバージョンと同様にエンコーディングの自動検出にフォールバックするnull
にオプションを設定する必要があります。
その他
-
Sparkバージョン2.4では、
cloneSession()
を介してSparkセッションが作成されると、新しく作成されたSparkセッションは、親のSparkセッションに異なる値で同じ構成が存在する場合でも、親のSparkContext
から構成を継承します。Spark 3.0では、親のSparkSession
の構成は、親のSparkContext
よりも優先度が高くなります。この古い動作を復元するには、spark.sql.legacy.sessionInitWithConfigDefaults
をtrue
に設定します。 -
Spark 3.0では、
hive.default.fileformat
がSpark SQL configuration
で見つからない場合、SparkContext
のHadoop configuration
に存在するhive-site.xml
ファイルにフォールバックします。 -
Spark 3.0では、
spark-sql
インターフェースの場合、小数点以下の桁数を列のスケールに合わせて後続のゼロで埋めます。例:クエリ Spark 2.4 Spark 3.0 SELECT CAST(1 AS decimal(38, 18));
1 1.000000000000000000 -
Spark 3.0では、組み込みのHiveを1.2から2.3にアップグレードし、これにより以下の影響が生じます。
-
接続先のHiveメタストアのバージョンに応じて、
spark.sql.hive.metastore.version
およびspark.sql.hive.metastore.jars
を設定する必要がある場合があります。たとえば、Hiveメタストアのバージョンが1.2.1の場合は、spark.sql.hive.metastore.version
を1.2.1
に、spark.sql.hive.metastore.jars
をmaven
に設定します。 -
カスタムSerDesをHive 2.3に移行するか、
hive-1.2
プロファイルで独自のSparkをビルドする必要があります。詳細については、HIVE-15167 を参照してください。 -
SQLでのスクリプト変換に
TRANSFORM
演算子を使用する場合、10進数の文字列表現は、Hiveの動作に応じて、Hive 1.2とHive 2.3で異なる場合があります。Hive 1.2では、文字列表現は後続のゼロを省略します。しかし、Hive 2.3では、必要に応じて常に後続のゼロで18桁に埋められます。
-
Spark SQL 2.4.7 から 2.4.8 へのアップグレード
- Spark 2.4.8では、
AnalysisException
は、以下の状況でHive外部カタログのテーブルに対してスローされるサブクラスに置き換えられています。ALTER TABLE .. ADD PARTITION
は、新しいパーティションがすでに存在する場合、PartitionsAlreadyExistException
をスローします。ALTER TABLE .. DROP PARTITION
は、存在しないパーティションに対してNoSuchPartitionsException
をスローします。
Spark SQL 2.4.5 から 2.4.6 へのアップグレード
- Spark 2.4.6では、
RESET
コマンドは、静的なSQL構成値をデフォルトにリセットしません。ランタイムSQL構成値のみをクリアします。
Spark SQL 2.4.4 から 2.4.5 へのアップグレード
-
Spark 2.4.5以降では、
TRUNCATE TABLE
コマンドは、テーブル/パーティションパスの再作成中に元のアクセス許可とACLを復元しようとします。以前のバージョンの動作を復元するには、spark.sql.truncateTable.ignorePermissionAcl.enabled
をtrue
に設定します。 -
Spark 2.4.5以降では、SMALLINTおよびREAL JDBC型にそれぞれIntegerTypeおよびDoubleTypeを使用する従来のMsSQLServer方言マッピング動作をサポートするために、
spark.sql.legacy.mssqlserver.numericMapping.enabled
構成が追加されました。2.4.3以前のバージョンの動作を復元するには、spark.sql.legacy.mssqlserver.numericMapping.enabled
をtrue
に設定します。
Spark SQL 2.4.3 から 2.4.4 へのアップグレード
- Spark 2.4.4以降では、MsSqlServer Guide によると、MsSQLServer JDBC方言は、SMALLINTおよびREALにそれぞれShortTypeおよびFloatTypeを使用します。以前は、IntegerTypeおよびDoubleTypeが使用されていました。
Spark SQL 2.4 から 2.4.1 へのアップグレード
- 「30s」ではなく「30」のように単位なしで指定された場合の
spark.executor.heartbeatInterval
の値は、Spark 2.4.0ではコードの異なる部分で秒とミリ秒の両方として一貫性なく解釈されていました。単位のない値は、現在では一貫してミリ秒として解釈されます。「30」のような値を設定するアプリケーションは、ミリ秒として解釈されるのを避けるために、「30s」のような単位付きの値を指定する必要があります。そうしないと、結果として非常に短い間隔となり、アプリケーションが失敗する可能性があります。
Spark SQL 2.3 から 2.4 へのアップグレード
- Sparkバージョン2.3以前では、array_contains関数の2番目のパラメーターは、最初の配列型パラメーターの要素型に暗黙的に昇格されていました。この型の昇格は損失を伴う可能性があり、
array_contains
関数が間違った結果を返す可能性があります。この問題は、より安全な型昇格メカニズムを採用することで2.4で対処されました。これにより、動作が多少変更される可能性があり、以下の表で説明します。クエリ Spark 2.3以前 Spark 2.4 備考 SELECT array_contains(array(1), 1.34D);
true
false
Spark 2.4では、左側と右側のパラメーターは、それぞれdouble型の配列型とdouble型に昇格されます。 SELECT array_contains(array(1), '1');
true
AnalysisException
がスローされます。引数で明示的なキャストを使用すると、例外を回避できます。Spark 2.4では、整数型は損失のない方法で文字列型に昇格できないため、 AnalysisException
がスローされます。SELECT array_contains(array(1), 'anystring');
null
AnalysisException
がスローされます。引数で明示的なキャストを使用すると、例外を回避できます。Spark 2.4では、整数型は損失のない方法で文字列型に昇格できないため、 AnalysisException
がスローされます。 -
Spark 2.4以降では、サブクエリの前のIN演算子の前に構造体フィールドがある場合、内部クエリにも構造体フィールドが含まれている必要があります。以前のバージョンでは、代わりに構造体のフィールドが内部クエリの出力と比較されていました。たとえば、
a
がstruct(a string, b int)
の場合、Spark 2.4ではa in (select (1 as a, 'a' as b) from range(1))
は有効なクエリですが、a in (select 1, 'a' from range(1))
は無効です。以前のバージョンでは逆でした。 -
バージョン2.2.1+および2.3では、
spark.sql.caseSensitive
がtrueに設定されている場合、CURRENT_DATE
およびCURRENT_TIMESTAMP
関数が誤って大文字と小文字を区別するようになり、列として解決されていました(小文字で入力されていない場合)。Spark 2.4では、これが修正され、関数は大文字と小文字を区別しなくなりました。 -
Spark 2.4 以降、Spark はクエリ内で参照される集合演算を、SQL 標準に従った優先順位規則に従って評価します。括弧で順序が指定されていない場合、集合演算は左から右に実行されます。ただし、すべての INTERSECT 演算は、UNION、EXCEPT、または MINUS 演算よりも先に実行されます。すべての集合演算に同じ優先順位を与えるという従来の動作は、新しく追加された設定
spark.sql.legacy.setopsPrecedence.enabled
(デフォルト値はfalse
) の下で保持されます。このプロパティがtrue
に設定されている場合、Spark は括弧の使用によって明示的な順序付けが強制されていない場合、クエリに表示される順に左から右へ集合演算子を評価します。 -
Spark 2.4 以降、Spark はテーブルの説明の [Last Access] 列の値が 1970 年 1 月 1 日である場合、UNKNOWN と表示するようになりました。
-
Spark 2.4 以降、Spark はデフォルトで ORC ファイル用のベクトル化された ORC リーダーの使用を最大化します。そのため、
spark.sql.orc.impl
とspark.sql.orc.filterPushdown
は、それぞれのデフォルト値をnative
とtrue
に変更します。ネイティブ ORC ライターによって作成された ORC ファイルは、一部の古い Apache Hive リリースでは読み取れません。spark.sql.orc.impl=hive
を使用して、Hive 2.1.1 以前と共有するファイルを作成してください。 -
Spark 2.4 以降、空のデータフレームをディレクトリに書き込むと、データフレームが物理的にパーティションを持っていなくても、少なくとも 1 つの書き込みタスクが起動します。これにより、Parquet や ORC などの自己記述型ファイル形式の場合、Spark が 0 パーティションのデータフレームを書き込むときにターゲットディレクトリにメタデータのみのファイルを作成し、ユーザーが後でそのディレクトリを読み込む場合にスキーマ推論が機能するという小さな動作変更が導入されます。この新しい動作は、空のデータフレームの書き込みに関してより合理的で一貫性があります。
-
Spark 2.4 以降、UDF 引数の式 ID は列名に表示されなくなりました。たとえば、Spark 2.4 の列名は
UDF:f(col0 AS colA#28)
ではなくUDF:f(col0 AS `colA`)
になります。 -
Spark 2.4 以降、ファイル形式(parquet、orc、json、text、csv など)を使用して、空またはネストされた空のスキーマを持つデータフレームを書き込むことは許可されません。空のスキーマを持つデータフレームを書き込もうとすると、例外がスローされます。
-
Spark 2.4 以降、Spark は DATE 型を TIMESTAMP 型と比較する際、両側を TIMESTAMP に昇格させてから比較を行います。
spark.sql.legacy.compareDateTimestampInTimestamp
をfalse
に設定すると、以前の動作に戻ります。このオプションは Spark 3.0 で削除されます。 -
Spark 2.4 以降、空でない場所を持つマネージドテーブルの作成は許可されません。空でない場所を持つマネージドテーブルを作成しようとすると、例外がスローされます。
spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation
をtrue
に設定すると、以前の動作に戻ります。このオプションは Spark 3.0 で削除されます。 -
Spark 2.4 以降、既存の場所へのマネージドテーブルの名前変更は許可されません。既存の場所へマネージドテーブルの名前を変更しようとすると、例外がスローされます。
-
Spark 2.4 以降、型の強制変換ルールは、可変長の SQL 関数 (IN/COALESCE など) の引数の型を、入力引数の順序に関係なく、最も広い共通の型に自動的に昇格させることができます。以前の Spark バージョンでは、一部の特定の順序 (例: TimestampType、IntegerType、StringType) で昇格に失敗し、例外がスローされる可能性がありました。
-
Spark 2.4 以降、Spark は従来のキャッシュ無効化メカニズムに加えて、非カスケード SQL キャッシュ無効化を有効にしました。非カスケード キャッシュ無効化メカニズムを使用すると、依存キャッシュに影響を与えることなくキャッシュを削除できます。この新しいキャッシュ無効化メカニズムは、削除するキャッシュのデータがまだ有効なシナリオ (例: データセットで unpersist() を呼び出す、または一時ビューをドロップする) で使用されます。これにより、ユーザーはメモリを解放し、目的のキャッシュを同時に有効に保つことができます。
-
バージョン 2.3 以前では、Spark は Parquet Hive テーブルをデフォルトで変換しますが、
TBLPROPERTIES (parquet.compression 'NONE')
のようなテーブルプロパティを無視します。これは、spark.sql.hive.convertMetastoreOrc=true
の場合、TBLPROPERTIES (orc.compress 'NONE')
のような ORC Hive テーブルプロパティにも発生します。Spark 2.4 以降、Spark は Parquet/ORC Hive テーブルを変換する際、Parquet/ORC 固有のテーブルプロパティを尊重します。例として、CREATE TABLE t(id int) STORED AS PARQUET TBLPROPERTIES (parquet.compression 'NONE')
は、Spark 2.3 での挿入中に Snappy parquet ファイルを生成し、Spark 2.4 では、結果は圧縮されていない parquet ファイルになります。 -
Spark 2.0 以降、Spark はパフォーマンス向上のため、Parquet Hive テーブルをデフォルトで変換します。Spark 2.4 以降、Spark は ORC Hive テーブルもデフォルトで変換します。つまり、Spark は Hive SerDe の代わりに独自の ORC サポートをデフォルトで使用します。例として、
CREATE TABLE t(id int) STORED AS ORC
は Spark 2.3 では Hive SerDe で処理されますが、Spark 2.4 では、Spark の ORC データソーステーブルに変換され、ORC ベクトル化が適用されます。spark.sql.hive.convertMetastoreOrc
をfalse
に設定すると、以前の動作に戻ります。 -
バージョン 2.3 以前では、CSV 行に少なくとも 1 つの列値が不正である場合、CSV 行は不正であると見なされます。CSV パーサーは、DROPMALFORMED モードでそのような行をドロップするか、FAILFAST モードでエラーを出力します。Spark 2.4 以降、CSV 行は、CSV データソースから要求された不正な列値が含まれている場合にのみ不正と見なされ、その他の値は無視できます。たとえば、CSV ファイルに「id,name」ヘッダーと 1 行の「1234」が含まれている場合、Spark 2.4 では、id 列の選択は 1 つの列値 1234 を含む行で構成されますが、Spark 2.3 以前では DROPMALFORMED モードで空になります。以前の動作を復元するには、
spark.sql.csv.parser.columnPruning.enabled
をfalse
に設定します。 -
Spark 2.4 以降、統計計算のためのファイルリストはデフォルトで並行して行われます。これは、
spark.sql.statistics.parallelFileListingInStatsComputation.enabled
をFalse
に設定することで無効にできます。 -
Spark 2.4 以降、メタデータファイル(例:Parquet サマリーファイル)と一時ファイルは、統計計算中にテーブルサイズを計算する際にデータファイルとしてカウントされません。
-
Spark 2.4 以降、空の文字列は引用符付きの空の文字列
""
として保存されます。バージョン 2.3 以前では、空の文字列はnull
値と等しく、保存された CSV ファイルに文字として反映されません。たとえば、"a", null, "", 1
の行はa,,,1
として書き込まれていました。Spark 2.4 以降、同じ行はa,,"",1
として保存されます。以前の動作を復元するには、CSV オプションemptyValue
を空 (引用符なし) の文字列に設定します。 -
Spark 2.4 以降、LOAD DATA コマンドはワイルドカード
?
と*
をサポートします。これらは、それぞれ任意の 1 文字と 0 文字以上の文字に一致します。例:LOAD DATA INPATH '/tmp/folder*/'
またはLOAD DATA INPATH '/tmp/part-?'
。space
のような特殊文字もパスで機能するようになりました。例:LOAD DATA INPATH '/tmp/folder name/'
。 -
Spark バージョン 2.3 以前では、GROUP BY なしの HAVING は WHERE として扱われます。これは、
SELECT 1 FROM range(10) HAVING true
がSELECT 1 FROM range(10) WHERE true
として実行され、10 行が返されることを意味します。これは SQL 標準に違反しており、Spark 2.4 で修正されました。Spark 2.4 以降、GROUP BY なしの HAVING はグローバル集計として扱われます。つまり、SELECT 1 FROM range(10) HAVING true
は 1 行のみを返します。以前の動作を復元するには、spark.sql.legacy.parser.havingWithoutGroupByAsWhere
をtrue
に設定します。 - バージョン 2.3 以前では、Parquet データソーステーブルから読み取る場合、Hive メタストアスキーマと Parquet スキーマの列名が異なる大文字と小文字の場合、
spark.sql.caseSensitive
がtrue
またはfalse
に設定されているかどうかに関係なく、Spark は常に任意の列に対して null を返します。2.4 以降、spark.sql.caseSensitive
がfalse
に設定されている場合、Spark は Hive メタストアスキーマと Parquet スキーマ間で大文字と小文字を区別しない列名解決を行うため、列名が異なる大文字と小文字の場合でも、Spark は対応する列値を返します。あいまいさがある場合、つまり、複数の Parquet 列が一致する場合は例外がスローされます。この変更は、spark.sql.hive.convertMetastoreParquet
がtrue
に設定されている場合、Parquet Hive テーブルにも適用されます。
Spark SQL 2.2 から 2.3 へのアップグレード
-
Spark 2.3 以降、参照される列が内部の破損レコード列(デフォルトでは
_corrupt_record
という名前)のみを含む場合、生の JSON/CSV ファイルからのクエリは許可されません。例:spark.read.schema(schema).json(file).filter($"_corrupt_record".isNotNull).count()
およびspark.read.schema(schema).json(file).select("_corrupt_record").show()
。代わりに、解析された結果をキャッシュまたは保存してから、同じクエリを送信できます。例:val df = spark.read.schema(schema).json(file).cache()
そしてdf.filter($"_corrupt_record".isNotNull).count()
。 -
percentile_approx
関数は、以前は数値型入力を受け入れ、double 型の結果を出力していました。現在、入力型として日付型、タイムスタンプ型、および数値型をサポートしています。結果の型も入力型と同じになるように変更され、これはパーセンタイルにとってより合理的です。 -
Spark 2.3 以降、最初の非決定性述語の後の結合/フィルターの決定性述語も、可能であれば子演算子にプッシュダウン/スルーされます。以前の Spark バージョンでは、これらのフィルターは述語プッシュダウンの対象ではありません。
-
以前のパーティション列推論では、異なる推論型に対して誤った共通型を見つけていました。たとえば、以前は double 型と date 型の共通型として double 型になっていました。現在、そのような競合に対して正しい共通型を見つけます。競合の解決は、以下の表に従います。
InputA \ InputB NullType IntegerType LongType DecimalType(38,0)* DoubleType DateType TimestampType StringType
</thead> <tr> <td> NullType </td> <td>NullType</td> <td>IntegerType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>DoubleType</td> <td>DateType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> IntegerType </td> <td>IntegerType</td> <td>IntegerType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> LongType </td> <td>LongType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DecimalType(38,0)* </td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DoubleType </td> <td>DoubleType</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DateType </td> <td>DateType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>DateType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> TimestampType </td> <td>TimestampType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>TimestampType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> StringType </td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> </table>
Note that, for <b>DecimalType(38,0)*</b>, the table above intentionally does not cover all other combinations of scales and precisions because currently we only infer decimal type like `BigInteger`/`BigInt`. For example, 1.1 is inferred as double type.
-
Spark 2.3 以降、ブロードキャストハッシュ結合またはブロードキャストネストループ結合が適用可能な場合、ブロードキャストヒントで明示的に指定されたテーブルをブロードキャストすることを優先します。詳細については、「SQLクエリの結合戦略ヒント」および「SPARK-22489」セクションを参照してください。
-
Spark 2.3 以降、すべての入力がバイナリの場合、
functions.concat()
はバイナリとして出力します。それ以外の場合は、文字列として返します。Spark 2.3 までは、入力型に関係なく常に文字列として返していました。以前の動作を維持するには、spark.sql.function.concatBinaryAsString
をtrue
に設定します。 -
Spark 2.3 以降、すべての入力がバイナリの場合、SQL
elt()
はバイナリとして出力します。それ以外の場合は、文字列として返します。Spark 2.3 までは、入力型に関係なく常に文字列として返していました。以前の動作を維持するには、spark.sql.function.eltOutputAsString
をtrue
に設定します。 -
Spark 2.3 以降、デフォルトでは、10進数間の算術演算は、正確な表現が不可能な場合(NULLを返す代わりに)丸められた値を返します。これは、SQL ANSI 2011 仕様と、Hive 2.2 (HIVE-15331) で導入された Hive の新しい動作に準拠しています。これには、以下の変更が含まれます。
-
算術演算の結果型を決定するルールが更新されました。特に、必要な精度/スケールが使用可能な値の範囲外である場合、10進数の整数部分の切り捨てを防ぐために、スケールは最大6まで縮小されます。すべての算術演算がこの変更の影響を受けます。つまり、加算 (
+
)、減算 (-
)、乗算 (*
)、除算 (/
)、剰余 (%
)、および正のモジュロ (pmod
) です。 -
SQL演算で使用されるリテラル値は、必要な正確な精度とスケールでDECIMALに変換されます。
-
構成
spark.sql.decimalOperations.allowPrecisionLoss
が導入されました。デフォルトはtrue
で、これはここで説明した新しい動作を意味します。false
に設定すると、Spark は以前のルールを使用します。つまり、値を表現するために必要なスケールを調整せず、値の正確な表現が不可能な場合は NULL を返します。
-
-
エイリアス化されていないサブクエリのセマンティクスは、混乱を招く動作ではうまく定義されていませんでした。Spark 2.3 以降、このような混乱を招くケースは無効になります。たとえば、
SELECT v.i from (SELECT i FROM v)
の場合、ユーザーはサブクエリ内で修飾子を使用できないため、Spark はこのケースで分析例外をスローします。詳細については、SPARK-20690 および SPARK-21335 を参照してください。 -
SparkSession.builder.getOrCreate()
を使用してSparkSession
を作成するときに、既存のSparkContext
がある場合、ビルダーは既存のSparkContext
のSparkConf
をビルダーに指定された構成で更新しようとしましたが、SparkContext
はすべてのSparkSession
で共有されるため、更新しないでください。2.3 以降、ビルダーは構成を更新しなくなりました。更新する場合は、SparkSession
を作成する前に更新する必要があります。
Spark SQL 2.1 から 2.2 へのアップグレード
-
Spark 2.1.1 で、新しい構成キー
spark.sql.hive.caseSensitiveInferenceMode
が導入されました。デフォルト設定はNEVER_INFER
で、これは 2.1.0 と同じ動作を維持していました。ただし、Spark 2.2.0 では、この設定のデフォルト値をINFER_AND_SAVE
に変更し、基になるファイルスキーマに大文字と小文字が混在した列名を持つ Hive メタストアテーブルの読み取りとの互換性を復元しました。INFER_AND_SAVE
構成値を使用すると、最初にアクセスしたときに、Spark は、まだ推論されたスキーマが保存されていない Hive メタストアテーブルに対してスキーマ推論を実行します。スキーマ推論は、何千ものパーティションを持つテーブルの場合、非常に時間のかかる操作になる可能性があることに注意してください。大文字と小文字が混在した列名との互換性が問題にならない場合は、spark.sql.hive.caseSensitiveInferenceMode
をNEVER_INFER
に設定して、スキーマ推論の初期オーバーヘッドを回避できます。新しいデフォルトのINFER_AND_SAVE
設定では、スキーマ推論の結果はメタストアキーとして保存され、将来使用できるようになります。したがって、初期スキーマ推論は、テーブルの最初のアクセス時にのみ発生します。 -
Spark 2.2.1 および 2.3.0 以降、データソーステーブルにパーティションスキーマとデータスキーマの両方に存在する列がある場合、スキーマは常に実行時に推論されます。推論されたスキーマには、パーティション化された列はありません。テーブルを読み取るとき、Spark は、データソースファイルに格納された値の代わりに、これらの重複する列のパーティション値を優先します。2.2.0 および 2.1.x リリースでは、推論されたスキーマはパーティション化されていますが、テーブルのデータはユーザーには表示されません(つまり、結果セットは空です)。
-
Spark 2.2 以降、ビュー定義は以前のバージョンとは異なる方法で格納されます。これにより、Spark が以前のバージョンで作成されたビューを読み取ることができなくなる場合があります。このような場合は、新しい Spark バージョンで
ALTER VIEW AS
またはCREATE OR REPLACE VIEW AS
を使用してビューを再作成する必要があります。
Spark SQL 2.0 から 2.1 へのアップグレード
-
データソーステーブルは、パーティションメタデータを Hive メタストアに格納するようになりました。これは、
ALTER TABLE PARTITION ... SET LOCATION
などの Hive DDL が、データソース API で作成されたテーブルで使用できるようになったことを意味します。-
レガシーデータソーステーブルは、
MSCK REPAIR TABLE
コマンドを使用してこの形式に移行できます。Hive DDL サポートと計画パフォーマンスの向上を利用するには、レガシーテーブルの移行が推奨されます。 -
テーブルが移行されたかどうかを判断するには、テーブルで
DESCRIBE FORMATTED
を発行するときに、PartitionProvider: Catalog
属性を探します。
-
-
データソーステーブルの
INSERT OVERWRITE TABLE ... PARTITION ...
の動作の変更。-
以前の Spark バージョンでは、
INSERT OVERWRITE
は、パーティション指定が与えられた場合でも、データソーステーブル全体を上書きしていました。現在は、指定に一致するパーティションのみが上書きされます。 -
これは、新しく挿入されたデータと重複するパーティションのみを上書きする Hive テーブルの動作とは異なることに注意してください。
-
Spark SQL 1.6 から 2.0 へのアップグレード
-
SparkSession
は、古いSQLContext
およびHiveContext
に代わる新しい Spark のエントリポイントになりました。古い SQLContext と HiveContext は下位互換性のために保持されていることに注意してください。SparkSession
からアクセスできる新しいcatalog
インターフェイスがあります。listTables
、createExternalTable
、dropTempView
、cacheTable
など、データベースとテーブルアクセスに関する既存の API はここに移動されます。 -
Dataset API と DataFrame API が統合されました。Scala では、
DataFrame
はDataset[Row]
の型エイリアスになり、Java API ユーザーはDataFrame
をDataset<Row>
で置き換える必要があります。型付き変換(例:map
、filter
、およびgroupByKey
)と型なし変換(例:select
およびgroupBy
)の両方が Dataset クラスで使用できます。Python と R ではコンパイル時の型安全性が言語機能ではないため、Dataset の概念はこれらの言語の API には適用されません。代わりに、DataFrame
は主要なプログラミング抽象化のままになります。これは、これらの言語の単一ノードのデータフレームの概念に似ています。 -
Dataset および DataFrame API
unionAll
は非推奨となり、union
に置き換えられました。 -
Dataset および DataFrame API
explode
は非推奨になりました。代わりに、select
またはflatMap
でfunctions.explode()
を使用してください。 -
Dataset および DataFrame API
registerTempTable
は非推奨となり、createOrReplaceTempView
に置き換えられました。 -
Hive テーブルの
CREATE TABLE ... LOCATION
の動作の変更。-
Spark 2.0以降、
CREATE TABLE ... LOCATION
は、ユーザーが指定した場所に既存のデータが誤って削除されるのを防ぐため、CREATE EXTERNAL TABLE ... LOCATION
と同等になりました。つまり、Spark SQLでユーザーが指定した場所を使って作成されたHiveテーブルは、常にHive外部テーブルとなります。外部テーブルを削除してもデータは削除されません。ユーザーはHiveマネージドテーブルの場所を指定することはできません。これはHiveの動作とは異なる点に注意してください。 -
その結果、これらのテーブルに対する
DROP TABLE
ステートメントはデータを削除しません。
-
-
spark.sql.parquet.cacheMetadata
は使用されなくなりました。詳細については、SPARK-13664を参照してください。
Spark SQL 1.5 から 1.6 へのアップグレード
- Spark 1.6以降、Thriftサーバーはデフォルトでマルチセッションモードで実行されます。つまり、JDBC/ODBC接続ごとに独自のSQL構成と一時関数レジストリのコピーを所有します。ただし、キャッシュされたテーブルは共有されます。Thriftサーバーを以前のシングルセッションモードで実行したい場合は、
spark.sql.hive.thriftServer.singleSession
オプションをtrue
に設定してください。このオプションは、spark-defaults.conf
に追加するか、start-thriftserver.sh
に--conf
を介して渡すことができます。
./sbin/start-thriftserver.sh \
--conf spark.sql.hive.thriftServer.singleSession=true \
...
- Spark 1.6以降、LongTypeからTimestampTypeへのキャストでは、マイクロ秒ではなく秒数が期待されるようになりました。この変更は、数値型からTimestampTypeへのより一貫した型キャストのために、Hive 1.2の動作に合わせるために行われました。詳細については、SPARK-11724を参照してください。
Spark SQL 1.4 から 1.5 へのアップグレード
-
手動で管理されたメモリ(Tungsten)を使用した最適化された実行が、式評価のためのコード生成とともにデフォルトで有効になりました。これらの機能は両方とも、
spark.sql.tungsten.enabled
をfalse
に設定することで無効にできます。 -
Parquetスキーマのマージは、デフォルトで有効ではなくなりました。
spark.sql.parquet.mergeSchema
をtrue
に設定することで再度有効にできます。 -
インメモリの列形式ストレージのパーティションプルーニングは、デフォルトでオンになっています。
spark.sql.inMemoryColumnarStorage.partitionPruning
をfalse
に設定することで無効にできます。 -
無制限精度の10進数カラムはサポートされなくなり、代わりにSpark SQLは最大精度38を強制します。
BigDecimal
オブジェクトからスキーマを推論する場合、精度 (38, 18) が使用されるようになりました。DDLで精度が指定されていない場合、デフォルトはDecimal(10, 0)
のままです。 -
タイムスタンプは、1nsではなく1usの精度で保存されるようになりました。
-
sql
方言では、浮動小数点数は10進数として解析されるようになりました。HiveQLの解析は変更されていません。 -
SQL/DataFrame関数の正規名は小文字になりました(例:sum vs SUM)。
-
JSONデータソースは、他のアプリケーションによって作成された新しいファイル(つまり、Spark SQLを通じてデータセットに挿入されなかったファイル)を自動的にロードしません。JSON永続テーブル(つまり、テーブルのメタデータがHive Metastoreに格納されている)の場合、ユーザーは
REFRESH TABLE
SQLコマンドまたはHiveContext
のrefreshTable
メソッドを使用して、これらの新しいファイルをテーブルに含めることができます。JSONデータセットを表すDataFrameの場合、ユーザーはDataFrameを再作成する必要があり、新しいDataFrameには新しいファイルが含まれます。
Spark SQL 1.3 から 1.4 へのアップグレード
DataFrameデータリーダー/ライターインターフェイス
ユーザーからのフィードバックに基づいて、データの読み込み(SQLContext.read
)とデータの書き出し(DataFrame.write
)のための、より流動的な新しいAPIを作成し、古いAPI(例:SQLContext.parquetFile
、SQLContext.jsonFile
)を非推奨にしました。
詳細については、SQLContext.read
(Scala、Java、Python)と DataFrame.write
(Scala、Java、Python)のAPIドキュメントを参照してください。
DataFrame.groupByはグループ化カラムを保持します。
ユーザーからのフィードバックに基づいて、DataFrame.groupBy().agg()
のデフォルトの動作を変更し、結果のDataFrame
にグループ化カラムを保持するようにしました。1.3の動作を維持するには、spark.sql.retainGroupColumns
をfalse
に設定します。
import pyspark.sql.functions as func
# In 1.3.x, in order for the grouping column "department" to show up,
# it must be included explicitly as part of the agg function call.
df.groupBy("department").agg(df["department"], func.max("age"), func.sum("expense"))
# In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(func.max("age"), func.sum("expense"))
# Revert to 1.3.x behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false")
// In 1.3.x, in order for the grouping column "department" to show up,
// it must be included explicitly as part of the agg function call.
df.groupBy("department").agg($"department", max("age"), sum("expense"))
// In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(max("age"), sum("expense"))
// Revert to 1.3 behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false")
// In 1.3.x, in order for the grouping column "department" to show up,
// it must be included explicitly as part of the agg function call.
df.groupBy("department").agg(col("department"), max("age"), sum("expense"));
// In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(max("age"), sum("expense"));
// Revert to 1.3 behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false");
DataFrame.withColumnの動作変更
1.4より前は、DataFrame.withColumn()はカラムの追加のみをサポートしていました。同じ名前の既存のカラムがある場合でも、カラムは常に指定された名前の新しいカラムとして結果のDataFrameに追加されます。1.4以降、DataFrame.withColumn()は、すべての既存のカラムの名前と異なる名前のカラムを追加するか、同じ名前の既存のカラムを置き換えることをサポートしています。
この変更はScala APIのみであり、PySparkおよびSparkRには適用されないことに注意してください。
Spark SQL 1.0-1.2 から 1.3 へのアップグレード
Spark 1.3では、Spark SQLから「Alpha」ラベルを削除し、その一環として利用可能なAPIを整理しました。Spark 1.3以降、Spark SQLは1.Xシリーズの他のリリースとのバイナリ互換性を提供します。この互換性保証は、明示的に不安定(つまり、DeveloperAPIまたはExperimental)としてマークされているAPIを除外します。
SchemaRDDからDataFrameへの名前変更
Spark SQL 1.3にアップグレードする際にユーザーが最も気づく大きな変更は、SchemaRDD
が DataFrame
に名前変更されたことです。これは主に、DataFrameがRDDから直接継承するのではなく、独自の実装を通じてRDDが提供する機能のほとんどを提供するためです。DataFrameは、.rdd
メソッドを呼び出すことで、引き続きRDDに変換できます。
Scalaでは、一部のユースケースでソースコードの互換性を提供するために、SchemaRDD
から DataFrame
への型エイリアスがあります。それでも、ユーザーはコードを DataFrame
を使用するように更新することを推奨します。JavaおよびPythonユーザーは、コードを更新する必要があります。
JavaとScala APIの統一
Spark 1.3より前には、Scala APIをミラーリングする個別のJava互換クラス(JavaSQLContext
および JavaSchemaRDD
)がありました。Spark 1.3では、Java APIとScala APIが統合されました。どちらの言語のユーザーも、SQLContext
と DataFrame
を使用する必要があります。一般に、これらのクラスは両方の言語で使用可能な型(つまり、言語固有のコレクションの代わりに Array
など)を使用しようとします。共通の型が存在しない場合(たとえば、クロージャまたはマップを渡す場合)、代わりに関数オーバーロードが使用されます。
さらに、Java固有の型APIは削除されました。ScalaとJavaの両方のユーザーは、org.apache.spark.sql.types
に存在するクラスを使用して、プログラムでスキーマを記述する必要があります。
暗黙的な変換の分離とdslパッケージの削除(Scalaのみ)
Spark 1.3より前のコード例の多くは、import sqlContext._
で始まり、これによりsqlContextのすべての関数がスコープに取り込まれていました。Spark 1.3では、RDD
を DataFrame
に変換するための暗黙的な変換を、SQLContext
内のオブジェクトに分離しました。ユーザーは import sqlContext.implicits._
と記述する必要があります。
さらに、暗黙的な変換は、自動的に適用されるのではなく、Product
(つまり、ケースクラスまたはタプル)で構成されるRDDにのみ toDF
メソッドで拡張するようになりました。
DSL内で関数を使用する場合(現在はDataFrame
APIに置き換えられています)、ユーザーは org.apache.spark.sql.catalyst.dsl
をインポートしていました。代わりに、公開されているdataframe関数APIを使用する必要があります:import org.apache.spark.sql.functions._
。
org.apache.spark.sqlのDataTypeの型エイリアスの削除(Scalaのみ)
Spark 1.3では、DataType
の基本sqlパッケージに存在していた型エイリアスが削除されます。代わりに、org.apache.spark.sql.types
のクラスをインポートする必要があります。
UDF登録がsqlContext.udf
に移動(JavaおよびScala)
DataFrame DSLまたはSQLでの使用のためにUDFを登録するために使用される関数は、SQLContext
の udf オブジェクトに移動されました。
sqlContext.udf.register("strLen", (s: String) => s.length())
sqlContext.udf().register("strLen", (String s) -> s.length(), DataTypes.IntegerType);
Python UDFの登録は変更されていません。
Apache Hive との互換性
Spark SQLは、Hive Metastore、SerDe、およびUDFとの互換性を持つように設計されています。現在、Hive SerDeとUDFは組み込みのHiveに基づいており、Spark SQLはさまざまなバージョンのHive Metastore(0.12.0から2.3.9、および3.0.0から3.1.3)に接続できます。また、異なるバージョンのHive Metastoreとの対話を参照してください。
既存のHiveウェアハウスへのデプロイ
Spark SQL Thrift JDBCサーバーは、既存のHiveインストールとの「すぐに使える」互換性を持つように設計されています。既存のHive Metastoreを変更したり、テーブルのデータ配置やパーティショニングを変更したりする必要はありません。
サポートされているHive機能
Spark SQLは、次のようなHive機能の大部分をサポートしています。
- 以下を含むHiveクエリステートメント
SELECT
GROUP BY
ORDER BY
DISTRIBUTE BY
CLUSTER BY
SORT BY
- 以下を含むすべてのHive演算子
- 関係演算子(
=
、<=>
、==
、<>
、<
、>
、>=
、<=
など) - 算術演算子(
+
、-
、*
、/
、%
など) - 論理演算子(
AND
、OR
など) - 複合型コンストラクター
- 数学関数(
sign
、ln
、cos
など) - 文字列関数(
instr
、length
、printf
など)
- 関係演算子(
- ユーザー定義関数(UDF)
- ユーザー定義集計関数(UDAF)
- ユーザー定義シリアル化形式(SerDes)
- ウィンドウ関数
- 結合
JOIN
{LEFT|RIGHT|FULL} OUTER JOIN
LEFT SEMI JOIN
LEFT ANTI JOIN
CROSS JOIN
- ユニオン
- サブクエリ
-
FROM句のサブクエリ
SELECT col FROM (SELECT a + b AS col FROM t1) t2
-
WHERE句のサブクエリ
-
WHERE句の相関または非相関INおよびNOT INステートメント
SELECT col FROM t1 WHERE col IN (SELECT a FROM t2 WHERE t1.a = t2.a) SELECT col FROM t1 WHERE col IN (SELECT a FROM t2)
-
WHERE句の相関または非相関EXISTSおよびNOT EXISTSステートメント
SELECT col FROM t1 WHERE EXISTS (SELECT t2.a FROM t2 WHERE t1.a = t2.a AND t2.a > 10) SELECT col FROM t1 WHERE EXISTS (SELECT t2.a FROM t2 WHERE t2.a > 10)
-
JOIN条件の非相関INおよびNOT INステートメント
SELECT t1.col FROM t1 JOIN t2 ON t1.a = t2.a AND t1.a IN (SELECT a FROM t3)
-
JOIN条件の非相関EXISTSおよびNOT EXISTSステートメント
SELECT t1.col FROM t1 JOIN t2 ON t1.a = t2.a AND EXISTS (SELECT * FROM t3 WHERE t3.a > 10)
-
-
- サンプリング
- Explain
- 動的パーティション挿入を含むパーティションテーブル
- ビュー
-
ビュー定義クエリで列エイリアスが指定されていない場合、SparkとHiveの両方がエイリアス名を生成しますが、その方法は異なります。SparkがHiveで作成されたビューを読み取れるようにするため、ユーザーはビュー定義クエリで明示的に列エイリアスを指定する必要があります。例えば、SparkはHiveによって以下のように作成された
v1
を読み取ることができません。CREATE VIEW v1 AS SELECT * FROM (SELECT c + 1 FROM (SELECT 1 c) t1) t2;
代わりに、以下のように列エイリアスを明示的に指定して
v1
を作成する必要があります。CREATE VIEW v1 AS SELECT * FROM (SELECT c + 1 AS inc_c FROM (SELECT 1 c) t1) t2;
-
- 以下を含むすべてのHive DDL関数
CREATE TABLE
CREATE TABLE AS SELECT
CREATE TABLE LIKE
ALTER TABLE
- 以下を含むほとんどのHiveデータ型
TINYINT
SMALLINT
INT
BIGINT
BOOLEAN
FLOAT
DOUBLE
STRING
BINARY
TIMESTAMP
DATE
ARRAY<>
MAP<>
STRUCT<>
サポートされていないHive機能
以下は、現在サポートしていないHive機能のリストです。これらの機能のほとんどは、Hiveのデプロイではめったに使用されません。
難解なHive機能
UNION
型- ユニーク結合
- 列統計の収集:Spark SQLは現在、列統計を収集するためのスキャンをピギーバックせず、HiveメタストアのsizeInBytesフィールドへのデータの投入のみをサポートしています。
Hive入出力フォーマット
- CLIのファイル形式:CLIに結果を表示する場合、Spark SQLはTextOutputFormatのみをサポートします。
- Hadoopアーカイブ
Hiveの最適化
いくつかのHiveの最適化はまだSparkには含まれていません。これらのいくつか(インデックスなど)は、Spark SQLのインメモリ計算モデルのため重要性が低くなっています。その他は、今後のSpark SQLのリリースで対応予定です。
- ブロックレベルのビットマップインデックスと(インデックスの作成に使用される)仮想列
- 結合とグループ化のリデューサーの数を自動的に決定する:現在、Spark SQLでは、"
SET spark.sql.shuffle.partitions=[num_tasks];
"を使用して、シャッフル後の並列処理の程度を制御する必要があります。 - メタデータのみのクエリ:メタデータのみを使用して回答できるクエリの場合、Spark SQLは結果を計算するためのタスクをまだ起動します。
- スキューデータフラグ:Spark SQLはHiveのスキューデータフラグに従いません。
- 結合の
STREAMTABLE
ヒント:Spark SQLはSTREAMTABLE
ヒントに従いません。 - クエリ結果のために複数の小さいファイルをマージする:結果の出力に複数の小さいファイルが含まれている場合、Hiveはオプションで小さいファイルをより少ない大きなファイルにマージして、HDFSメタデータがオーバーフローするのを防ぐことができます。Spark SQLはこれをサポートしていません。
Hive UDF/UDTF/UDAF
Hive UDF/UDTF/UDAFのすべてのAPIがSpark SQLでサポートされているわけではありません。以下は、サポートされていないAPIです。
getRequiredJars
およびgetRequiredFiles
(UDF
およびGenericUDF
)は、このUDFに必要な追加リソースを自動的に含めるための関数です。GenericUDTF
のinitialize(StructObjectInspector)
はまだサポートされていません。Spark SQLは現在、非推奨のインターフェースinitialize(ObjectInspector[])
のみを使用しています。configure
(GenericUDF
、GenericUDTF
、およびGenericUDAFEvaluator
)は、Sparkには適用できないMapredContext
を使用して関数を初期化するための関数です。close
(GenericUDF
およびGenericUDAFEvaluator
)は、関連するリソースを解放するための関数です。Spark SQLは、タスクが終了してもこの関数を呼び出しません。reset
(GenericUDAFEvaluator
)は、同じ集計を再利用するための集計を再初期化する関数です。Spark SQLは現在、集計の再利用をサポートしていません。getWindowingEvaluator
(GenericUDAFEvaluator
)は、固定ウィンドウで集計を評価することにより、集計を最適化する関数です。
互換性のないHive UDF
以下は、HiveとSparkが異なる結果を生成するシナリオです。
SQRT(n)
n < 0の場合、Hiveはnullを返し、Spark SQLはNaNを返します。ACOS(n)
n < -1またはn > 1の場合、Hiveはnullを返し、Spark SQLはNaNを返します。ASIN(n)
n < -1またはn > 1の場合、Hiveはnullを返し、Spark SQLはNaNを返します。CAST(n AS TIMESTAMP)
nが整数値の場合、Hiveはnをミリ秒として扱い、Spark SQLはnを秒として扱います。