Upgrading From Spark SQL 1.6 to 2.0

· SparkSession is now the new entry point of Spark that replaces the old SQLContext and
HiveContext. Note that the old SQLContext and HiveContext are kept for backward compatibility. A new catalog interface is accessible from SparkSession - existing API on databases and tables access such as listTables, createExternalTable, dropTempView, cacheTable are moved here.
o Spark SQL 진입포인트가 바뀝니다. 기존 SQLContext, HiveContext에서 SparkSession 으로 변경됩니다. 이전 버전과의 호환성을 위해 기존 SQLContext, HiveContext는 유지됩니다.

· Dataset API and DataFrame API are unified. In Scala, DataFrame becomes a type alias forDataset[Row], while Java API users must replace DataFrame with Dataset<Row>. Both the typed transformations (e.g., map, filter, and groupByKey) and transformations (e.g., select and groupBy) are available on the Dataset class. Since compile-time type-safety in Python and R is not a language feature, the concept of Dataset does not apply to these languages’ APIs. Instead, DataFrameremains the primary programming abstraction, which is analogous to the single-node data frame notion in these languages.

o Dataset API and DataFrame API 통합됩니다. 각 언어별로 차이가 있는데,
(1) Scala에서는 DataFrame 은 Dataset[Row]의 ailas가 됩니다.
(2) Java 에서는 DataFrame 은 Dataset<Row>로 반드시 바꾸어야합니다.
( Dataset class에서 데이터 타입을 바꾸는(예 : map, filter,groupByKey) API와 데이터 타입을 바꾸지 않는(예 : select, gropuby) API 모두 사용 가능합니다.)
(3) Python (4) R에서는 컴파일 시점의 타입 안전(보장?)은 두 언어의 특성이 아니며, DataFrame과 기본적인 1차원 개념이 유사하게 적용된 DataCollection이 있으므로
위의 두 언어에서는 해당 API를 사용하지 않습니다.

“Spark2.0부터는 Dataset은 strong type의 API와 형식이 지정되지 않는 API두가지를 사용한다. 개념적으로 DataFrame은 Dataset[Row]로 간주되며 Dataset의 subset으로 볼 수 있다. 여기서 Row는 유형이 지정되지 않는 JVM객체이다. Dataset은 Scala 나 Java클래스에서 정의하는 case class를 통해 타입을 선언한 강력한 형식의 JVM객체의 모음이다. Datasets은 Scala와 Java만 지원하는데 Python과 R의 경우 컴파일 타임형 안정성이 없기 때문이다.”

· Dataset and DataFrame API unionAll has been deprecated and replaced by union
Dataset and DataFrame API registerTempTable has been deprecated and replaced by createOrReplaceTempView
Dataset and DataFrame API explode has been deprecated, alternatively, use functions.explode()with select or flatMap
· Dataset and DataFrame API 여러 기능들이 대체되어 사용되지 않습니다.
(1) unionAll은 union 으로 대체 됨
https://spark.apache.org/docs/1.6.3/api/scala/index.html#org.apache.spark.sql.DataFrame
https://spark.apache.org/docs/2.4.3/api/scala/#org.apache.spark.sql.Dataset
(2) registerTempTable 은 createOrReplaceTempView으로 대체 됨
(3) 기존explode 함수의 경우, explode 오퍼레이터로 대체되었고, functions.explode()with select or flatMap 사용 가능 함
(참고1. https://stackoverflow.com/questions/43582989/whats-the-difference-between-explode-function-and-operator?rq=1
참고 2. https://stackoverflow.com/questions/43551370/how-to-split-multi-value-column-into-separate-rows-using-typed-dataset
참고 3. https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-functions-collection.html

· Changes to CREATE TABLE ... LOCATION behavior for Hive tables.

From Spark 2.0, CREATE TABLE ... LOCATION is equivalent to CREATE EXTERNAL TABLE ... LOCATION in order to prevent accidental dropping the existing data in the user-provided locations. That means, a Hive table created in Spark SQL with the user-specified location is always a Hive external table. Dropping external tables will not remove the data. Users are not allowed to specify the location for Hive managed tables. Note that this is different from the Hive behavior.
o As a result, DROP TABLE statements on those tables will not remove the data.

Spark 2.0부터는 CREATE TABLE ... LOCATION 명령이 to CREATE EXTERNAL TABLE ... LOCATION 과 동일하기 때문에 사용자가 실수로 존재하는 데이터를 날리는 것을 방지합니다. 즉 Spark SQL에서 하이브 테이블을 만들면 항상 지정한 특정위치에 Hive external 테이블이 만들어 지기 때문에, 외부 테이블들을 dropping하는 것으로 데이터가 삭제되지는 않은 것입니다. 사용자들은 특정화된 위치의Hive managed 테이블들을 허용되지 않습니다. 이것은 Hive behavior와 다르다는 것을 참고하시기 바랍니다.

· spark.sql.parquet.cacheMetadata is no longer used. See SPARK-13664 for details.

o SPARK-13664 에 기술된 대로, spark.sql.parquet.cacheMetadata 더 이상 사용되지 않습니다.

https://www.quora.com/What-are-the-exact-features-of-Spark-2-x-compared-to-Spark-1-6-in-terms-of-optimization-to-migrate-codes-from-1-6-to-2-x

Upgrading From Spark SQL 2.0 to 2.1
· Datasource tables now store partition metadata in the Hive metastore. This means that Hive DDLs such as ALTER TABLE PARTITION ... SET LOCATION are now available for tables created with the Datasource API.

· Legacy datasource tables can be migrated to this format via the MSCK REPAIR TABLE command. Migrating legacy tables is recommended to take advantage of Hive DDL support and improved planning performance.

· To determine if a table has been migrated, look for the PartitionProvider: Catalog attribute when issuing DESCRIBE FORMATTED on the table.

o Datasource 테이블이 이제 Hive metastore에 partition metadata를 저장합니다. 따라서 Datasource API로 만들어진 테이블에도 ALTER TABLE PARTITION ... SET LOCATION 같은 Hive DDL 명령등이 사용가능합니다.

o MSCK REPAIR TABLE명령(MetaStore Check)을 통해 기존 데이터 소스의 테이블도 partition metadata포맷으로 통합시킬 수 있습니다. 통합된 기존 테이블은 Hive DDL과 향상된 planning performance의 이득을 볼 수 있습니다.

o 테이블이 마이그레이션되었는지 확인하려면 테이블에서 DESCRIBE FORMATTED를 명령으로 PartitionProvider: Catalog 속성을 확인하면 됩니다.

· Changes to INSERT OVERWRITE TABLE ... PARTITION ... behavior for Datasource tables.

· In prior Spark versions INSERT OVERWRITE overwrote the entire Datasource table, even when given a partition specification. Now only partitions matching the specification are overwritten.

· Note that this still differs from the behavior of Hive tables, which is to overwrite only partitions overlapping with newly inserted data.

o Datasource테이블의 INSERT OVERWRITE TABLE ... PARTITION ... 동작이 변경됩니다.

o 이전 버전의 Spark버전에서는 특정 파티션을 지정했을 때 조차, INSERT OVERWRITE 동작이 전체 Datasource테이블을 덮어썼습니다. 2.1 버전부터는 특정하게 저정된 파티션만 덮어쓰게 됩니다.

o 새로 insert된 데이터와 겹치는 partition만 덮어쓰는 Hive 테이블의 동작과는 여전히 다르다는 점은 유의해야합니다.

Upgrading From Spark SQL 2.1 to 2.2
· Spark 2.1.1 introduced a new configuration key: spark.sql.hive.caseSensitiveInferenceMode. It had a default setting of NEVER_INFER, which kept behavior identical to 2.1.0. However, Spark 2.2.0 changes this setting’s default value to INFER_AND_SAVE to restore compatibility with reading Hive metastore tables whose underlying file schema have mixed-case column names. With the INFER_AND_SAVEconfiguration value, on first access Spark will perform schema inference on any Hive metastore table for which it has not already saved an inferred schema. Note that schema inference can be a very time-consuming operation for tables with thousands of partitions. If compatibility with mixed-case column names is not a concern, you can safely set spark.sql.hive.caseSensitiveInferenceMode to NEVER_INFER to avoid the initial overhead of schema inference. Note that with the new default INFER_AND_SAVE setting, the results of the schema inference are saved as a metastore key for future use. Therefore, the initial schema inference occurs only at a table’s first access.

o spark.sql.hive.caseSensitiveInferenceMode 기본 설정이 NEVER_INFER(2.1.0. 버전)에서 INFER_AND_SAVE(2.2.0 버전)으로 바뀝니다.
해당 설정 값은 schema에 mixed-case column name을 가진 hive metastore table 읽기 호환성을 살리기 위해서 변경된 것입니다. INFER_AND_SAVE 구성값을 사용하여, 첫번째 엑세스에서 스파크가 (추론된 스키마를 아직까지 저장하지 않은 모든 hive metastore table에 대하여) 스키마 추론을 수행할 것입니다.
주의할 사항은 스키마 추론은 수천개의 파티션이 있는 테이블의 경우 시간이 아주 많이 소요될 수 있습니다.
만약 mixed-case column name과의 호환성의 문제가 고려사항이 아닌 경우, 스키마 추론으로 인한 오버헤드를 피하기 위해 해당 옵션을 NEVER_INFER로 설정할 수 있습니다.
새 디폴트 값 INFER_AND_SAVE은 스키마 추론의 결과가 나중에 사용할 수 있는 metastore key키로 저장됩니다. 따라서 초기 스키마 추론은 테이블을 첫번째 엑세스 시에만 발생합니다.

· Since Spark 2.2.1 and 2.3.0, the schema is always inferred at runtime when the data source tables have the columns that exist in both partition schema and data schema. The inferred schema does not have the partitioned columns. When reading the table, Spark respects the partition values of these overlapping columns instead of the values stored in the data source files. In 2.2.0 and 2.1.x release, the inferred schema is partitioned but the data of the table is invisible to users (i.e., the result set is empty).

o Spark 2.2.1과 2.3.0 버전부터 데이터 스키마와 파티션 스키마 둘 다 존재하는 column을 가진 data source스키마는 항상 런타임에 추론됩니다.

· Since Spark 2.2, view definitions are stored in a different way from prior versions. This may cause Spark unable to read views created by prior versions. In such cases, you need to recreate the views using ALTER VIEW AS or CREATE OR REPLACE VIEW AS with newer Spark versions.

o Spark 2.2 이후, VIEW 정의가 이전 버전과 다른 방식으로 저장됩니다. 이로 인해 이전 버전 스파크로 생성된 뷰를 읽지 못 할 수 있습니다. 이런 경우에는 ALTER VIEW AS 또는 CREATE 또는 REPLACE VIEW AS를 사용하여 보기를 재생성해야 합니다.

Upgrading From Spark SQL 2.2 to 2.3

· Since Spark 2.3, the queries from raw JSON/CSV files are disallowed when the referenced columns only include the internal corrupt record column (named _corrupt_record by default). For example, spark.read.schema(schema).json(file).filter($"_corrupt_record".isNotNull).count() and spark.read.schema(schema).json(file).select("_corrupt_record").show(). Instead, you can cache or save the parsed results and then send the same query. For example, val df = spark.read.schema(schema).json(file).cache() and then df.filter($"_corrupt_record".isNotNull).count().

o Spark 2.3버전부터 참조된 columns에 내부 손상된 레코드 columns (기본적으로_corrupt_record 으로 명명된)만 포함된 경우 raw 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()가 있습니다.

· The percentile_approx function previously accepted numeric type input and output double type results. Now it supports date type, timestamp type and numeric types as input types. The result type is also changed to be the same as the input type, which is more reasonable for percentiles.

o 이전까지 percentile_approx함수는 input은 numeric type으로만, output은 double type으로만 리턴 되도록 허용하였습니다. 이제 date, timestamp, numeric types들도 input type으로 지원합니다. result type도 input typ과 동일하게 변경되어, percentiles에 대해 더 합리적으로 바뀌었습니다.

· Since Spark 2.3, the Join/Filter’s deterministic predicates that are after the first non-deterministic predicates are also pushed down/through the child operators, if possible. In prior Spark versions, these filters are not eligible for predicate pushdown.

o 스파크 2.3 이후, Join/Filter는 첫번째 non-deterministic predicates이후에도 deterministic predicates가 하위 연산자를 통해 pushed down됩니다. 이전 Spark 버전에서는, 이러한 filters는 술어 pushdown에 적합하지 않았습니다.

· Partition column inference previously found incorrect common type for different inferred types, for example, previously it ended up with double type as the common type for double type and date type. Now it finds the correct common type for such conflicts. The conflict resolution follows the table below:

o 파티션 column 추론 이전에 서로 다른 추론된 유형에 대해 incorrect한 common type이 발견되었습니다, 예를 들어, 이전에 double type과 date type의 common type으로 double type으로 추론함. 이제 이런 충돌에 대한 올바른 common type을 찾아냅니다. 이러한 충돌의 해결은 아래표를 따릅니다.

InputA \ InputB

NullType

IntegerType

LongType

DecimalType(38,0)*

DoubleType

DateType

TimestampType

StringType

NullType

NullType

IntegerType

LongType

DecimalType(38,0)

DoubleType

DateType

TimestampType

StringType

IntegerType

IntegerType

IntegerType

LongType

DecimalType(38,0)

DoubleType

StringType

StringType

StringType

LongType

LongType

LongType

LongType

DecimalType(38,0)

StringType

StringType

StringType

StringType

DecimalType(38,0)*

DecimalType(38,0)

DecimalType(38,0)

DecimalType(38,0)

DecimalType(38,0)

StringType

StringType

StringType

StringType

DoubleType

DoubleType

DoubleType

StringType

StringType

DoubleType

StringType

StringType

StringType

DateType

DateType

StringType

StringType

StringType

StringType

DateType

TimestampType

StringType

TimestampType

TimestampType

StringType

StringType

StringType

StringType

TimestampType

TimestampType

StringType

StringType

StringType

StringType

StringType

StringType

StringType

StringType

StringType

StringType

· Note that, for DecimalType(38,0)*, 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.

o DecimalType(38,0)*의 경우, 현재 BigInteger/BigInt와 같은 십진수 유형만 추론하기 때문에 위의 표는 의도적으로 다른 모든 scales and precisions의 조합을 포함하지 않습는다. 예를 들어 1.1은 double type으로 추론됩니다

· In PySpark, now we need Pandas 0.19.2 or upper if you want to use Pandas related functionalities, such as toPandas, createDataFrame from Pandas DataFrame, etc.

o 이제 PySpark에서 ToPandas, CreateDataFrame from Pandas DataFrame 등과 같은 Pandas 관련 기능을 사용하려면 Pandas 0.19.2 혹은 그 이상의 버전이 필요합니다,

· In PySpark, the behavior of timestamp values for Pandas related functionalities was changed to respect session timezone. If you want to use the old behavior, you need to set a configuration spark.sql.execution.pandas.respectSessionTimeZone to False. See SPARK-22395 for details.

o PySpark에서 Pandas 관련 기능에 대한 타임스탬프 값의 동작이 세션의 timezone를 준수하도록 변경되었습니다. 이전 버전과 동일하게 사용하려면 sql.execution.pandas.ronteSessionTimeZone 구성 값을 False로 설정해야 합니다. 자세한 내용은 SPARK-22395를 참조하십시오.

· In PySpark, na.fill() or fillna also accepts boolean and replaces nulls with booleans. In prior Spark versions, PySpark just ignores it and returns the original Dataset/DataFrame.

o PySpark에서 na.fill() 혹은 fillna 함수도 boolean 타입을 받아들이고, null을 boolean으로 대체합니다. 이전 Spark 버전에서 PySpark는 이를 무시하고 Original Dataset/DataFrame을 반환했습니다..

· Since Spark 2.3, when either broadcast hash join or broadcast nested loop join is applicable, we prefer to broadcasting the table that is explicitly specified in a broadcast hint. For details, see the section Broadcast Hint and SPARK-22489.

o Spark 2.3버전부터 broadcast hash join이나 broadcast nested loop join을 적용가능한 경우, 브로드캐스트 힌트에 명시된 테이블에 브로드캐스팅하는 것이 좋습니다. 자세한 내용은 section Broadcast Hint and SPARK-22489을 참조하십시오.

· Since Spark 2.3, when all inputs are binary, functions.concat() returns an output as binary. Otherwise, it returns as a string. Until Spark 2.3, it always returns as a string despite of input types. To keep the old behavior, set spark.sql.function.concatBinaryAsString to true.

o Spark 2.3버전부터 모든 입력이 바이너리 이면, functions.concat()도 바이너리로 출력을 리턴합니다. 그렇지 않을 경우 string으로 출력합니다. 이전 버전에서는 input 타입에 상관없이 항상 string으로 출력하였습니다. 이전 설정을 유지하고자 할 경우 spark.sql.function. concatBinaryAsString 을 true로 설정하면 됩니다.

· Since Spark 2.3, when all inputs are binary, SQL elt() returns an output as binary. Otherwise, it returns as a string. Until Spark 2.3, it always returns as a string despite of input types. To keep the old behavior, set spark.sql.function.eltOutputAsString to true.

o Spark 2.3버전부터 모든 입력이 바이너리 이면, SQL elt()도 바이너리로 출력을 리턴합니다. 그렇지 않을 경우 string으로 출력합니다. 이전 버전에서는 input 타입에 상관없이 항상 string으로 출력하였습니다. 이전 설정을 유지하고자 할 경우 spark.sql.function.eltOutputAsString을 true로 설정하면 됩니다.

· Since Spark 2.3, by default arithmetic operations between decimals return a rounded value if an exact representation is not possible (instead of returning NULL). This is compliant with SQL ANSI 2011 specification and Hive’s new behavior introduced in Hive 2.2 (HIVE-15331). This involves the following changes

o Spark 2.3버전부터 기본적으로 십진수간의 산술연산에서 정확하게 표현하기 어려운 값들은 NULL값을 리턴 하는 것 대신, 반올림된 값을 도출합니다. 이는 SQL ANSI 2011과 Hive 2.2에서 새로 도입된 behavior (HIVE-15331)을 따른 것입니다. 아래의 세부 변경사항들을 동반합니다.

The rules to determine the result type of an arithmetic operation have been updated. In particular, if the precision / scale needed are out of the range of available values, the scale is reduced up to 6, in order to prevent the truncation of the integer part of the decimals. All the arithmetic operations are affected by the change, ie. addition (+), subtraction (-), multiplication (), division (/), remainder (%) and positive module (pmod).
산술 연산의 결과 타입을 결정하는 규칙이 업데이트되었습니다. 특히 필요한 precision / scale이 사용 가능한 값의 범위를 벗어나면 십진수의 정수 부분 절단을 방지하기 위해 scale을 최대 6자리까지 줄입니다. 모든 산술 연산은 이러한 규칙(덧셈(+), 뺄셈(-), 곱셈(
), 나눗셈(/), 나머지(%) 및 양의 모듈러 연산(pmod))의 영향을 받습니다.
Literal values used in SQL operations are converted to DECIMAL with the exact precision and scale needed by them.
SQL 작업에 사용되는 Literal 값은 DECIMAL로 변환되어 정확한 정밀도와 scale을 갖습니다.
The configuration spark.sql.decimalOperations.allowPrecisionLoss has been introduced. It defaults to true, which means the new behavior described here; if set to false, Spark uses previous rules, ie. it doesn’t adjust the needed scale to represent the values and it returns NULL if an exact representation of the value is not possible.
spark.sql.decimalOperations.allowPrecisionLoss 설정 새롭게 도입되었습니다. 이 설정값은 항상 true이며, SQL ANSI 2011과 (HIVE-15331) 이슈를 준수하게 하는 옵션입니다. 이를 false로 했을 때는 이전과 동일하게 scale을 조정하지 않고는 값을 표현할 수 없을 때 이전 버전들과 동일하게 NULL값으로 표현됩니다.
· In PySpark, df.replace does not allow to omit value when to_replace is not a dictionary. Previously, value could be omitted in the other cases and had None by default, which is counterintuitive and error-prone.

o PySpark에서 df.replace는 to_replace가 등록되지 않은 경우 value을 생략할 수 없습니다. 이전에 VALUE는 다른 경우 생략할 수 있었고 기본적으로 없음으로 표시됐었습니다. 이로인해 직관에 어긋나고 오류가 발생하기 쉬웠기 때문에 해당 내용이 적용되었습니다.

· Un-aliased subquery’s semantic has not been well defined with confusing behaviors. Since Spark 2.3, we invalidate such confusing cases, for example: SELECT v.i from (SELECT i FROM v), Spark will throw an analysis exception in this case because users should not be able to use the qualifier inside a subquery. See SPARK-20690 and SPARK-21335 for more details.

o aliased되지않은 subquery’s 의미가 잘 정의되지 않아 confusing되는 경우, 예를 들어 SELECT v.i from (SELECT i FROM v)쿼리를 수행할 경우 서브쿼리 내부의 qualifier를 사용 할 수 없으므로 분석 예외가 발생합니다.
자세한 정보는 SPARK-20690 and SPARK-21335에 기재되어 있습니다..

· When creating a SparkSession with SparkSession.builder.getOrCreate(), if there is an existing SparkContext, the builder was trying to update the SparkConf of the existing SparkContext with configurations specified to the builder, but the SparkContext is shared by all SparkSessions, so we should not update them. Since 2.3, the builder comes to not update the configurations. If you want to update them, you need to update them prior to creating a SparkSession.

o SparkContext존재할 때, SparkSession을 SparkSession.builder.getOrCreate()으로 생성하면, 빌더는 기존 SparkContext의 SparkConf 를 빌더에 지정된 구성으로 업데이트를 시도합니다. 하지만 SparkContext 기존에 존재하는 모든 SparkSessions에서 공유되기 때문에 이를 업데이트 하면 안됩니다.
따라서 Spark 2.3부터는 빌더는 환경설정을 업데이트 하지 않으며, 업데이트하길 원한다면 SparkSession을 생성하기 이전에 업데이트를 먼저하여야 합니다.

Upgrading From Spark SQL 2.3.0 to 2.3.1 and above

· As of version 2.3.1 Arrow functionality, including pandas_udf and toPandas()/createDataFrame() with spark.sql.execution.arrow.enabled set to True, has been marked as experimental. These are still evolving and not currently recommended for use in production.

o 버전 2.3.1에서는 Apache Arrow 기능이 실험용으로 도입되어, “Pandas_udf 및 ToPandas() / createDataFrame()”을 포함하여 sql.execution.arrow.enabled를 True로 설정됩니다..
해당 기능들은 개발 중이며 현재 버전에서 사용을 권장하지는 않습니다.

아파치 애로우 아파치 애로우(Apache Arrow)는 빅데이터의 속도를 높여주는 고속, 원주형, 교차 시스템 데이터 계층이다. 애로우를 사용해 메모리 내에 데이터를 저장함으로써, 애플리케이션은 오늘날 데이터 처리 파이프라인에 병목을 발생시키는 값비싼 직렬화/역직렬화 단계를 건너뛸 수 있다. 아파치 빅데이터 프로젝트(카산드라(Cassandra), 파르켓(Parquet), 쿠두(Kudu), 스파크(Spark), 스톰(Storm) 등의 여러 개발자들이 참가하는 아파치 애로우 프로젝트는 향후 오랜 기간 동안 전세계 데이터 중 큰 덩어리를 처리하게 될 것이다.

http://www.itworld.co.kr/print/106668

http://www.hanbit.co.kr/media/channel/view.html?cms_code=CMS9615655185

Upgrading From Spark SQL 2.3 to 2.4

· In Spark version 2.3 and earlier, the second parameter to array_contains function is implicitly promoted to the element type of first array type parameter. This type promotion can be lossy and may cause array_contains function to return wrong result. This problem has been addressed in 2.4 by employing a safer type promotion mechanism. This can cause some change in behavior and are illustrated in the table below.

o Spark 2.3버전과 그 이전 버전에서는 array_contains 함수의 두번째 parameter Spark 2.4 버전부터 1번째 parameter의 타입을 암시적으로 승계합니다. 이런 타입 프로모션은 lossy나 array_contains 함수가 잘못된 결과를 도출하게 할 수 있습니다. 이 문제는 Spark 2.4 버전에서 safer type promotion 메커니즘을 사용 하면서 해결 되었습니다. 이로 인해서 일부 변화가 있을 수 있으며 관련 내용은 아래 테이블에 설명되어있습니다.

Query

Result Spark 2.3 or Prior

Result Spark 2.4

Remarks

SELECT
array_contains(array(1), 1.34D);

True

False

In Spark 2.4, left and right parameters are promoted to array(double) and double type respectively.

SELECT
array_contains(array(1), '1');

True

AnalysisException is thrown since integer type can not be promoted to string type in a loss-less manner.

Users can use explicit cast

SELECT
array_contains(array(1), 'anystring');

null

AnalysisException is thrown since integer type can not be promoted to string type in a loss-less manner.

Users can use explicit cast

· Since Spark 2.4, when there is a struct field in front of the IN operator before a subquery, the inner query must contain a struct field as well. In previous versions, instead, the fields of the struct were compared to the output of the inner query. Eg. if a is a struct(a string, b int), in Spark 2.4 a in (select (1 as a, 'a' as b) from range(1)) is a valid query, while a in (select 1, 'a' from range(1)) is not. In previous version it was the opposite.

o Spark 2.4 버전부터 서브쿼리 이전 IN 오퍼레이터 앞에 struct field가 있을 때, inner query는 반드시 struct field를 포함하여야 합니다. 이전 버전에서는 struct field를 inner query의 출력값과 비교하였습니다. 예를 들어 a가 struct(a string, b int)일 때, in Spark 2.4 에서는 in (select (1 as a, 'a' as b) from range(1)) 이 적합한 쿼리이고 in (select 1, 'a' from range(1)) 는 적합하지 않습니다. 이전 버전에서는 이와 반대로 적용됐었습니다.

· In versions 2.2.1+ and 2.3, if spark.sql.caseSensitive is set to true, then the CURRENT_DATE and CURRENT_TIMESTAMP functions incorrectly became case-sensitive and would resolve to columns (unless typed in lower case). In Spark 2.4 this has been fixed and the functions are no longer case-sensitive.

o Spark 버전 2.2.1과 2.3에서 spark.sql.caseSensitive (대소문자 민감도) 설정을 true로 하면 CURRENT_DATE와 CURRENT_TIMESTAMP 함수가 대소문자를 구분하지 못하고 열로 분해됩니다. 스파크 2.4에서는 이 기능이 수정되었으며 더 이상 대소문자를 구분하지 않습니다.

· Since Spark 2.4, Spark will evaluate the set operations referenced in a query by following a precedence rule as per the SQL standard. If the order is not specified by parentheses, set operations are performed from left to right with the exception that all INTERSECT operations are performed before any UNION, EXCEPT or MINUS operations. The old behaviour of giving equal precedence to all the set operations are preserved under a newly added configuration spark.sql.legacy.setopsPrecedence.enabled with a default value of false. When this property is set to true, spark will evaluate the set operators from left to right as they appear in the query given no explicit ordering is enforced by usage of parenthesis.

o Spark 2.4 버전부터 Spark는 SQL 표준의 우선 순위 규칙에 따라 쿼리에서 참조된 set operations을 evaluate합니다. 괄호로 순서를 지정하지 않은 경우, UNION, EXCEPT 또는 MINUS 작업 전에 모든 INTERSECT 작업이 수행되는 것을 제외하고 set operations이 왼쪽에서 오른쪽으로 수행됩니다.

· Since Spark 2.4, Spark will display table description column Last Access value as UNKNOWN when the value was Jan 01 1970.

o Spark 2.4 버전부터 테이블 설명 컬럼에서 마지막 엑세스가 1970년1월01일이면 UNKNOWN으로 표시함.

· Since Spark 2.4, Spark maximizes the usage of a vectorized ORC reader for ORC files by default. To do that, spark.sql.orc.impl and spark.sql.orc.filterPushdown change their default values to native and true respectively. ORC files created by native ORC writer cannot be read by some old Apache Hive releases. Use spark.sql.orc.impl=hive to create the files shared with Hive 2.1.1 and older.

o Spark 2.4 버전부터 vectorized ORC reader활용도를 최대화 하기 위해 ORC files을 기본으로 해야합니다. 이를 위해 spark.sql.orc.impl and spark.sql.orc.filterPushdown 설정을 각각 native와 true로 설정해주어야 합니다. native ORC writer로 작성된 ORC files은 구 버전의 Apache Hive에서 읽히지 않을 수 있습니다.

· In PySpark, when Arrow optimization is enabled, previously toPandas just failed when Arrow optimization is unable to be used whereas createDataFrame from Pandas DataFrame allowed the fallback to non-optimization. Now, both toPandas and createDataFrame from Pandas DataFrame allow the fallback by default, which can be switched off by spark.sql.execution.arrow.fallback.enabled.

o 버전 2.3.1에서는 Apache Arrow 기능이 실험용으로 도입되어, “Pandas_udf 및 ToPandas() / createDataFrame()”을 포함하여 sql.execution.arrow.enabled를 True로 설정됩니다..
해당 기능들은 개발 중이며 현재 버전에서 사용을 권장하지는 않습니다.

· Since Spark 2.4, writing an empty dataframe to a directory launches at least one write task, even if physically the dataframe has no partition. This introduces a small behavior change that for self-describing file formats like Parquet and Orc, Spark creates a metadata-only file in the target directory when writing a 0-partition dataframe, so that schema inference can still work if users read that directory later. The new behavior is more reasonable and more consistent regarding writing empty dataframe.

o Spark 2.4 버전부터 물리적으로 dataframe가 파티션을 갖지 않는 경우에도, directory를 launches하여 dataframe를 쓸 때 최소 한번의 쓰기 작업이 수행됩니다.이것은 작은 behavior 변화인데, Parquet, Orc, 0파티션 데이터 프레임을 쓸 때, 타겟 directory에 Spark가 metadata-only file을 생성하는 등의 self-describing file 포맷을 나중에 사용자가 해당 directory를 읽을 때에도 스키마 추론이 가능해지게 합니다. 이러한 새로운 정책은 빈 데이터 dataframe을 쓸 때, 좀더 합리적이고, 짜임새 있는 인식이 됩니다.

· Since Spark 2.4, expression IDs in UDF arguments do not appear in column names. For example, a column name in Spark 2.4 is not UDF:f(col0 AS colA#28) but UDF:f(col0 AS colA).

o Spark 2.4 버전부터 UDF arguments의 expression IDs가 더 이상 컬럼명에 나타나지 않습니다. 예를 들어 UDF:f(col0 AS colA#28)이런식으로 나타나던 UDF argument가 UDF:f(col0 AS colA)로 표기됩니다.

· Since Spark 2.4, writing a dataframe with an empty or nested empty schema using any file formats (parquet, orc, json, text, csv etc.) is not allowed. An exception is thrown when attempting to write dataframes with empty schema.

o Spark 2.4 버전부터 어떤한 파일 포맷으로든 (parquet, orc, json, text, csv etc.) empty이거나 중첩된 empty 스키마인 dataframe를 write하는 것은 금지됩니다. 이를 시도할 경우 empty 스키마 데이터 프레임을 writeg하려한다고 예외가 발생합니다.

· Since Spark 2.4, Spark compares a DATE type with a TIMESTAMP type after promotes both sides to TIMESTAMP. To set false to spark.sql.legacy.compareDateTimestampInTimestamp restores the previous behavior. This option will be removed in Spark 3.0.

o Spark 2.4 버전부터 DATE타입과 TIMESTAMP타입을 비교할 때, 두 타입 모두 TIMESTAMP형으로 변환하여 서로 비교하였습니다. 이전 방식으로 사용하기 위해서는 spark.sql.legacy.compareDateTimestampInTimestamp 설정을 false 로 하면됩니다. 해당 옵션은 Spark 3.0부터 없어질 것입니다.

· Since Spark 2.4, creating a managed table with nonempty location is not allowed. An exception is thrown when attempting to create a managed table with nonempty location. To set true to spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation restores the previous behavior. This option will be removed in Spark 3.0.

o Spark 2.4 버전부터 비어 있지 않은 location에 managed table을 생성하는 것은 허용되지 않습니다. 이를 시도할 경우 예외가 발생합니다. 이전버전처럼 사용하기 위해서는 spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation 설정값을 true로 설정하여야 합니다. 해당 옵션은 Spark 3.0에서 제거될 예정입니다.

· Since Spark 2.4, renaming a managed table to existing location is not allowed. An exception is thrown when attempting to rename a managed table to existing location.

o Spark 2.4 버전부터 기존 위치로 관리 테이블을 renaming할 수 없습니다. 기존 위치로 관리 테이블을 renaming 할 때 예외가 발생합니다.

· Since Spark 2.4, the type coercion rules can automatically promote the argument types of the variadic SQL functions (e.g., IN/COALESCE) to the widest common type, no matter how the input arguments order. In prior Spark versions, the promotion could fail in some specific orders (e.g., TimestampType, IntegerType and StringType) and throw an exception.

o Spark 2.4 버전부터 input arguments의 순서가 어떻든 상관없이 type coercion rules이 자동적으로 variadic SQL functions(e.g., IN/COALESCE)의 specific 순서(e.g., TimestampType, IntegerType and StringType)는 실패할 수 있으며, 예외가 발생할 것입니다.

· Since Spark 2.4, Spark has enabled non-cascading SQL cache invalidation in addition to the traditional cache invalidation mechanism. The non-cascading cache invalidation mechanism allows users to remove a cache without impacting its dependent caches. This new cache invalidation mechanism is used in scenarios where the data of the cache to be removed is still valid, e.g., calling unpersist() on a Dataset, or dropping a temporary view. This allows users to free up memory and keep the desired caches valid at the same time.

o Spark 2.4 버전부터 기존 cache 무효화 매커니즘에 추가로 non-cascading SQL cache 무효화가 활성화됩니다. non-cascading SQL cache 매커니즘은 사용자가 의존하는 cache를 영향없이 제거할 수 있게 합니다. 이 매커니즘은 아직 유효한 cache의 data(예를 들어, Dataset에 unpersist()를 호출하거나, temporary view를 dropping하는 경우)를 지우는 상황에 사용됩니다. 이를 통해 사용자는 메모리를 확보하고 caches를 유효하게 유지할 수 있습니다.

· In version 2.3 and earlier, Spark converts Parquet Hive tables by default but ignores table properties like TBLPROPERTIES (parquet.compression 'NONE'). This happens for ORC Hive table properties like TBLPROPERTIES (orc.compress 'NONE') in case of spark.sql.hive.convertMetastoreOrc=true, too. Since Spark 2.4, Spark respects Parquet/ORC specific table properties while converting Parquet/ORC Hive tables. As an example, CREATE TABLE t(id int) STORED AS PARQUET TBLPROPERTIES (parquet.compression 'NONE') would generate Snappy parquet files during insertion in Spark 2.3, and in Spark 2.4, the result would be uncompressed parquet files.

o Spark 2.3버전과 그 이전 버전에서는 기본적으로 Parquet Hive tables을 변환하지만 TBLPROPERTIES (parquet.compression 'NONE')같은 테이블 속성은 무시합니다. spark.sql.hive.convertMetastoreOrc=true인 경우, ORC Hive table 속성 TBLPROPERTIES (orc.compress 'NONE') 에도 동일한 현상이 발생했습니다.
Spark 2.4 버전부터 스파크는 Parquet/ORC Hive 테이블을 변환하는 동안 Parquet/ORC별 테이블 특성을 respects합니다. 예를 들어, 각 버전에서 CREATE TABLE t(id int) STORED AS PARQUET TBLPROPERTIES (parquet.compression 'NONE')명령을 수행할 때, Spark 2.3에서는 Snappy로 압축된 parquet files을 생성하고, Spark 2.4에서는 압축되지 않은parquet files을 생성합니다..

· Since Spark 2.0, Spark converts Parquet Hive tables by default for better performance. Since Spark 2.4, Spark converts ORC Hive tables by default, too. It means Spark uses its own ORC support by default instead of Hive SerDe. As an example, CREATE TABLE t(id int) STORED AS ORC would be handled with Hive SerDe in Spark 2.3, and in Spark 2.4, it would be converted into Spark’s ORC data source table and ORC vectorization would be applied. To set false to spark.sql.hive.convertMetastoreOrc restores the previous behavior.

o Spark 2.0 버전부터 좀 더 나은 performance를 위해 Spark는 기본적으로 Parquet Hive tables을 변환합니다. Spark 2.4 버전부터 마찬가지로 ORC Hive tables또한 변환합니다. 이는 Spark이 Hive SerDe(직렬화,비직렬화) 대신 Spark 자체의 ORC support를 사용합니다. 예를 들어, CREATE TABLE t(id int) STORED AS ORC 명령은 Spark 2.3에선 Hive SerDe으로 처리되고, Spark 2.4에선 Spark의 ORC 데이터 소스 테이블로 변환되고 ORC 벡터화가 적용됩니다.

· In version 2.3 and earlier, CSV rows are considered as malformed if at least one column value in the row is malformed. CSV parser dropped such rows in the DROPMALFORMED mode or outputs an error in the FAILFAST mode. Since Spark 2.4, CSV row is considered as malformed only when it contains malformed column values requested from CSV datasource, other values can be ignored. As an example, CSV file contains the “id,name” header and one row “1234”. In Spark 2.4, selection of the id column consists of a row with one column value 1234 but in Spark 2.3 and earlier it is empty in the DROPMALFORMED mode. To restore the previous behavior, set spark.sql.csv.parser.columnPruning.enabled to false.

o Spark 2.3버전과 그 이전 버전에서는 행에서 하나 이상의 열 값이 잘못된 형식인 경우 CSV 행이 잘못된 형식으로 간주됩니다. CSV 파서가 DROPMALFORMED 모드에서 이러한 행을 삭제하거나 FAILFAST 모드에서 오류를 출력합니다. Spark 2.4 버전부터 CSV 행은 CSV 데이터 원본에서 요청한 잘못된 형식의 열 값을 포함하는 경우에만 잘못된 형식으로 간주되며, 다른 값은 무시할 수 있습니다. 예를 들어 CSV 파일에는 "id,name" 헤더와 한 행 "1234"가 포함되어 있습니다. 스파크 2.4에서 ID 열의 선택은 하나의 열 값 1234인 행으로 구성되지만 스파크 2.3 이전 버전에서는 DROPMALFORMED 모드에서 비어 있습니다.

· Since Spark 2.4, File listing for compute statistics is done in parallel by default. This can be disabled by setting spark.sql.statistics.parallelFileListingInStatsComputation.enabled to False.

o Spark 2.4 버전부터 통계적 연산을 위한 파일 목록은 기본적으로 병렬로 수행됩니다. spark.sql.statistics.parallelFileListingInStatsComputation.enabled를 False로 설정하면 이 기능을 비활성화할 수 있습니다.

· Since Spark 2.4, Metadata files (e.g. Parquet summary files) and temporary files are not counted as data files when calculating table size during Statistics computation.

o Spark 2.4 버전부터 Metadata 파일 (예: Parquet summary file)과 temporary파일은 통계적인 연산을 할 동안 테이블의 사이즈는 계산할때 데이터 파일로 count되지 않습니다.

· Since Spark 2.4, empty strings are saved as quoted empty strings "". In version 2.3 and earlier, empty strings are equal to null values and do not reflect to any characters in saved CSV files. For example, the row of "a", null, "", 1 was written as a,,,1. Since Spark 2.4, the same row is saved as a,,"",1. To restore the previous behavior, set the CSV option emptyValue to empty (not quoted) string.

o Spark 2.4 버전부터 빈 문자열은 "" 형식으로 저장됩니다. Spark 2.3버전과 그 이전 버전에서는 빈문자열은 null값과 동일하였고, CSV파일로 저장될 때 어떤 캐릭터로도 표시되지 않았습니다. 예를 들어, 한 행이 있고, 컬럼이 4개이며, 각 값은 "a", null, "", 1 일 때, CSV파일로 저장하면 a,,,1으로 저장되었습니다. 하지만 Spark 2.4버전부터는 a,,"",1 이런식으로 저장됩니다.
이전 버전과 동일하게 저장하려면, CSV 옵션에서 emptyValue 의 값을 empty (not quoted) string으로 설정하면 됩니다.

· Since Spark 2.4, The LOAD DATA command supports wildcard ? and , which match any one character, and zero or more characters, respectively. Example: LOAD DATA INPATH '/tmp/folder/' or LOAD DATA INPATH '/tmp/part-?'. Special Characters like space also now work in paths. Example: LOAD DATA INPATH '/tmp/folder name/'.

o Spark 2.4 버전부터 The LOAD DATA 명령이 와일드카드(정규표현식) ? 와 을 지원합니다. (각각 ?는 1개의 문자와, *은 0개 이상의 문자와 대응됨) Example: LOAD DATA INPATH '/tmp/folder/' or LOAD DATA INPATH '/tmp/part-?', 또 space 같은 특수문자도 경로에 사용할수 있게 됩니다. Example: LOAD DATA INPATH '/tmp/folder name/'.

· In Spark version 2.3 and earlier, HAVING without GROUP BY is treated as WHERE. This means, SELECT 1 FROM range(10) HAVING true is executed as SELECT 1 FROM range(10) WHERE true and returns 10 rows. This violates SQL standard, and has been fixed in Spark 2.4. Since Spark 2.4, HAVING without GROUP BY is treated as a global aggregate, which means SELECT 1 FROM range(10) HAVING true will return only one row. To restore the previous behavior, set spark.sql.legacy.parser.havingWithoutGroupByAsWhere to true.

o Spark 2.3버전과 그 이전 버전에서는 HAVING 절이 없는 GROUP BY는 WHERE절로 취급 되었습니다. 즉, SELECT 1 FROM range(10) HAVING true쿼리는 as SELECT 1 FROM range(10) WHERE true 쿼리로 수행되었고, 10개의 row를 리턴하였습니다. 이 것은 SQL 표준을 위반한 것으로 Spark 2.4 버전에서 수정 되었습니다. Spark 2.4 버전부터는 HAVING 절이 없는 GROUP BY는 global aggregate로 취급됩니다. 따라서 SELECT 1 FROM range(10) HAVING true쿼리는 오직 1개의 row만 리턴하게됩니다. 이전 설정대로 사용하기 위해서는 spark.sql.legacy.parser.havingWithoutGroupByAsWhere 설정 값을 true로 하면 됩니다.

· In version 2.3 and earlier, when reading from a Parquet data source table, Spark always returns null for any column whose column names in Hive metastore schema and Parquet schema are in different letter cases, no matter whether spark.sql.caseSensitive is set to true or false. Since 2.4, when spark.sql.caseSensitive is set to false, Spark does case insensitive column name resolution between Hive metastore schema and Parquet schema, so even column names are in different letter cases, Spark returns corresponding column values. An exception is thrown if there is ambiguity, i.e. more than one Parquet column is matched. This change also applies to Parquet Hive tables when spark.sql.hive.convertMetastoreParquet is set to true.

o Spark 2.3버전과 그 이전 버전에서는 Parquet data source 테이블을 읽을 때, spark.sql.caseSensitive 설정 값이 true 든 false든 상관없이 Hive metastore schema와 Parquet schema가 같은 단어여도 대소문자가 다른 경우, Spark 2.4 버전부터 spark.sql.caseSensitive 설정값이 false이면, Hive metastore schema와 Parquet schema가 같은 단어이고 대소문자가 다른 경우에도, 같은 값으로 컬럼 값으로 처리해줍니다. 해당 설정 값이 true이면, 둘 이상이 parquet 컬럼이 일치하고, 모호성이 있을 경우 예외를 발생시킵니다. 이 설정은 Parquet Hive tables에도 동일하게 적용됩니다.

Upgrading from Spark SQL 2.4 to 2.4.1

· The value of spark.executor.heartbeatInterval, when specified without units like “30” rather than “30s”, was inconsistently interpreted as both seconds and milliseconds in Spark 2.4.0 in different parts of the code. Unitless values are now consistently interpreted as milliseconds. Applications that set values like “30” need to specify a value with units like “30s” now, to avoid being interpreted as milliseconds; otherwise, the extremely short interval that results will likely cause applications to fail.

o Spark 2.4.0에서 spark.executor.heartbeatInterval 값을 '30s'처럼 단위를 사용해서 지정하는 것이 아닌 '30'과 같이 단위를 지정하지 않고 사용하는 경우, 코드의 서로 다른 부분에서 초와 밀리초가 모두 모순되게 해석됩니다. 그래서 단위 없는 값은 이제 일관성있게 밀리초로 해석됩니다. 따라서 "30"과 같은 값을 설정하는 애플리케이션은 밀리초 단위로 해석되지 않도록 "30s"와 같은 단위를 사용하여 값을 지정해야 합니다. 그렇지 않을 경우, 매우 짧은 간격으로 인해 애플리케이션이 실패할 수 있습니다.