Skip to content

Commit 0f3ee92

Browse files
author
Sameer Raheja
committed
Merge branch 'cudf-spark-rename-1' of https://github.com/sameerz/spark-rapids into cudf-spark-rename-1
2 parents 72cf2d1 + bb1738b commit 0f3ee92

17 files changed

Lines changed: 1113 additions & 225 deletions

File tree

integration_tests/src/main/python/hash_aggregate_test.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,33 @@ def doit(spark):
890890
conf={'spark.sql.execution.useObjectHashAggregateExec': str(use_obj_hash_agg).lower()})
891891

892892

893+
@pytest.mark.skipif(not is_spark_420_or_later(),
894+
reason='collect_set RESPECT NULLS is introduced in Spark 4.2')
895+
@allow_non_gpu("ProjectExec")
896+
@ignore_order(local=True)
897+
@pytest.mark.parametrize('use_obj_hash_agg', [True, False], ids=idfn)
898+
def test_hash_groupby_collect_set_respect_nulls(use_obj_hash_agg):
899+
def doit(spark):
900+
return spark.sql("""
901+
SELECT a,
902+
sort_array(collect_set(b) IGNORE NULLS) AS ignore_set,
903+
sort_array(collect_set(b) RESPECT NULLS) AS respect_set
904+
FROM VALUES
905+
(1, 1),
906+
(1, NULL),
907+
(1, 1),
908+
(1, NULL),
909+
(2, NULL),
910+
(2, 5)
911+
AS tab(a, b)
912+
GROUP BY a
913+
""")
914+
915+
assert_gpu_and_cpu_are_equal_collect(
916+
doit,
917+
conf={'spark.sql.execution.useObjectHashAggregateExec': str(use_obj_hash_agg).lower()})
918+
919+
893920
@ignore_order(local=True)
894921
@pytest.mark.parametrize('use_obj_hash_agg', [True, False], ids=idfn)
895922
def test_hash_groupby_collect_list_of_maps(use_obj_hash_agg):
@@ -954,6 +981,33 @@ def test_hash_reduction_collect_set(data_gen):
954981
lambda spark: gen_df(spark, data_gen, length=100)
955982
.agg(f.sort_array(f.collect_set('b')), f.count('b')))
956983

984+
985+
@pytest.mark.skipif(not is_spark_420_or_later(),
986+
reason='collect_set RESPECT NULLS is introduced in Spark 4.2')
987+
@allow_non_gpu("ProjectExec")
988+
@ignore_order(local=True)
989+
def test_hash_reduction_collect_set_respect_nulls():
990+
def doit(spark):
991+
return spark.sql("""
992+
SELECT
993+
sort_array(collect_set(i) IGNORE NULLS) AS ignore_int,
994+
sort_array(collect_set(i) RESPECT NULLS) AS respect_int,
995+
sort_array(collect_set(d) IGNORE NULLS) AS ignore_double,
996+
sort_array(collect_set(d) RESPECT NULLS) AS respect_double,
997+
sort_array(collect_set(CAST(NULL AS INT)) IGNORE NULLS) AS ignore_all_null,
998+
sort_array(collect_set(CAST(NULL AS INT)) RESPECT NULLS) AS respect_all_null
999+
FROM VALUES
1000+
(CAST(1 AS INT), CAST(1.0 AS DOUBLE)),
1001+
(CAST(NULL AS INT), CAST(NULL AS DOUBLE)),
1002+
(CAST(1 AS INT), CAST('NaN' AS DOUBLE)),
1003+
(CAST(NULL AS INT), CAST('NaN' AS DOUBLE)),
1004+
(CAST(2 AS INT), CAST(2.0 AS DOUBLE))
1005+
AS tab(i, d)
1006+
""")
1007+
1008+
assert_gpu_and_cpu_are_equal_collect(doit)
1009+
1010+
9571011
@ignore_order(local=True)
9581012
@pytest.mark.parametrize('data_gen', _gen_data_for_collect_set_op, ids=idfn)
9591013
@allow_non_gpu(*non_utc_allow)

integration_tests/src/main/python/orc_test.py

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ def test_basic_read(std_input_path, name, read_func, v1_enabled_list, orc_impl,
158158
MapGen(StructGen([['child0', byte_gen], ['child1', long_gen]], nullable=False),
159159
StructGen([['child0', byte_gen], ['child1', long_gen]]))]
160160

161-
non_utc_allow_orc_scan=['ColumnarToRowExec', 'FileSourceScanExec', 'BatchScanExec'] if is_not_utc() else []
162-
163161
orc_gens_list = [orc_basic_gens,
164162
orc_array_gens_sample,
165163
orc_struct_gens_sample,
@@ -195,7 +193,6 @@ def test_orc_fallback(spark_tmp_path, read_func, disable_conf):
195193
@pytest.mark.parametrize('reader_confs', reader_opt_confs, ids=idfn)
196194
@pytest.mark.parametrize('v1_enabled_list', ['', 'orc'])
197195
@tz_sensitive_test
198-
@allow_non_gpu(*non_utc_allow_orc_scan)
199196
def test_read_round_trip(spark_tmp_path, orc_gens, read_func, reader_confs, v1_enabled_list):
200197
gen_list = [('_c' + str(i), gen) for i, gen in enumerate(orc_gens)]
201198
data_path = spark_tmp_path + '/ORC_DATA'
@@ -224,7 +221,6 @@ def test_read_round_trip(spark_tmp_path, orc_gens, read_func, reader_confs, v1_e
224221
@pytest.mark.parametrize('read_func', [read_orc_df, read_orc_sql])
225222
@pytest.mark.parametrize('v1_enabled_list', ["", "orc"])
226223
@pytest.mark.parametrize('reader_confs', reader_opt_confs, ids=idfn)
227-
@allow_non_gpu(*non_utc_allow_orc_scan)
228224
def test_pred_push_round_trip(spark_tmp_path, orc_gen, read_func, v1_enabled_list, reader_confs):
229225
data_path = spark_tmp_path + '/ORC_DATA'
230226
# Append two struct columns to verify nested predicate pushdown.
@@ -281,7 +277,6 @@ def test_compress_read_round_trip(spark_tmp_path, compress, v1_enabled_list, rea
281277

282278
@pytest.mark.parametrize('v1_enabled_list', ["", "orc"])
283279
@pytest.mark.parametrize('reader_confs', reader_opt_confs, ids=idfn)
284-
@allow_non_gpu(*non_utc_allow_orc_scan)
285280
def test_simple_partitioned_read(spark_tmp_path, v1_enabled_list, reader_confs):
286281
# Once https://github.com/NVIDIA/spark-rapids/issues/131 is fixed
287282
# we should go with a more standard set of generators
@@ -351,7 +346,6 @@ def test_partitioned_read_just_partitions(spark_tmp_path, v1_enabled_list, reade
351346

352347
@pytest.mark.parametrize('v1_enabled_list', ["", "orc"])
353348
@pytest.mark.parametrize('reader_confs', reader_opt_confs, ids=idfn)
354-
@allow_non_gpu(*non_utc_allow_orc_scan)
355349
def test_merge_schema_read(spark_tmp_path, v1_enabled_list, reader_confs):
356350
# Once https://github.com/NVIDIA/spark-rapids/issues/131 is fixed
357351
# we should go with a more standard set of generators
@@ -693,7 +687,6 @@ def test_read_struct_without_stream(spark_tmp_path):
693687
@pytest.mark.parametrize('reader_confs', reader_opt_confs, ids=idfn)
694688
@pytest.mark.parametrize('v1_enabled_list', ["", "orc"])
695689
@pytest.mark.parametrize('case_sensitive', ["false", "true"])
696-
@allow_non_gpu(*non_utc_allow_orc_scan)
697690
def test_read_with_more_columns(spark_tmp_path, orc_gen, reader_confs, v1_enabled_list, case_sensitive):
698691
struct_gen = StructGen([('nested_col', orc_gen)])
699692
# Map is not supported yet.
@@ -878,7 +871,6 @@ def test_orc_read_varchar_as_string(std_input_path):
878871
@pytest.mark.parametrize('gens', orc_gens_list, ids=idfn)
879872
@pytest.mark.parametrize('keep_order', [True, pytest.param(False, marks=pytest.mark.ignore_order(local=True))])
880873
@tz_sensitive_test
881-
@allow_non_gpu(*non_utc_allow_orc_scan)
882874
def test_read_round_trip_for_multithreaded_combining(spark_tmp_path, gens, keep_order):
883875
gen_list = [('_c' + str(i), gen) for i, gen in enumerate(gens)]
884876
data_path = spark_tmp_path + '/ORC_DATA'
@@ -893,7 +885,6 @@ def test_read_round_trip_for_multithreaded_combining(spark_tmp_path, gens, keep_
893885

894886

895887
@pytest.mark.parametrize('keep_order', [True, pytest.param(False, marks=pytest.mark.ignore_order(local=True))])
896-
@allow_non_gpu(*non_utc_allow_orc_scan)
897888
def test_simple_partitioned_read_for_multithreaded_combining(spark_tmp_path, keep_order):
898889
# Use every type except boolean, see https://github.com/NVIDIA/spark-rapids/issues/11762 and
899890
# https://github.com/rapidsai/cudf/issues/6763 .
@@ -1129,17 +1120,39 @@ def test_orc_not_support_timestamp_ltz(std_input_path):
11291120
conf={},
11301121
error_message=expected_error_message)
11311122

1123+
# Timestamp writes: in UTC the GPU writes on the GPU; in a non-UTC JVM the GPU write must fall
1124+
# back to CPU. cuDF's ORC writer always stamps writerTimezone="UTC" in the stripe footer and
1125+
# cannot record the JVM writer timezone (https://github.com/rapidsai/cudf/issues/23422), so a
1126+
# GPU-written non-UTC file would be read back shifted by the zone offset by a CPU ORC reader.
1127+
# The `tz_sensitive_test` mark runs this in both UTC and non-UTC JVM timezones.
1128+
non_utc_orc_write_allow = ['DataWritingCommandExec'] if is_not_utc() else []
1129+
1130+
@tz_sensitive_test
1131+
@ignore_order(local=True)
1132+
@allow_non_gpu(*non_utc_orc_write_allow)
1133+
def test_orc_gpu_write_cpu_read_timestamp_in_non_utc_timezone(spark_tmp_path):
1134+
data_path = spark_tmp_path + "/ORC_GPU_WRITE_TZ"
1135+
write_func = lambda spark, path: (
1136+
spark.range(3)
1137+
.selectExpr("CAST(1593604800 + id AS TIMESTAMP) AS ts")
1138+
.write.orc(path))
1139+
read_func = lambda spark, path: spark.read.orc(path)
1140+
if is_not_utc():
1141+
# Non-UTC: the timestamp write must fall back to CPU (DataWritingCommandExec).
1142+
assert_gpu_fallback_write(write_func, read_func, data_path, 'DataWritingCommandExec')
1143+
else:
1144+
assert_gpu_and_cpu_writes_are_equal_collect(write_func, read_func, data_path)
1145+
1146+
11321147
@pytest.mark.parametrize("reader_confs", reader_opt_confs, ids=idfn)
1133-
# Setting end timestamp as None almost always generate ts >= 2200 year.
1134-
# Setting end timestamp < 2200 to test running columnarly on GPU;
1135-
@pytest.mark.parametrize('end_timestamp', [None, datetime(2199, 1, 1, tzinfo=timezone.utc)], ids=idfn)
11361148
@pytest.mark.parametrize('v1_enabled_list', ["", "orc"])
11371149
@pytest.mark.parametrize("timezone_pair", [("UTC", "Asia/Shanghai"), ("Asia/Shanghai", "UTC"), ("Asia/Shanghai", "America/Los_Angeles")], ids=idfn)
11381150
@tz_sensitive_test
1139-
def test_orc_non_utc_timezone(reader_confs, end_timestamp, spark_tmp_path, v1_enabled_list, timezone_pair):
1151+
def test_orc_reader_writer_the_same_timezone(reader_confs, spark_tmp_path, v1_enabled_list, timezone_pair):
11401152
d_gen = DateGen(start=date(1590, 1, 1))
11411153
# Update start year to 1590 when https://github.com/NVIDIA/spark-rapids/issues/13272 is fixed.
1142-
ts_gen = TimestampGen(start=datetime(1970, 1, 1, tzinfo=timezone.utc), end=end_timestamp, nullable=True)
1154+
# The default end covers the full timestamp range through year 9999, including years > 2200.
1155+
ts_gen = TimestampGen(start=datetime(1970, 1, 2, tzinfo=timezone.utc), nullable=True)
11431156
date_timestamp_gens = [('c1', d_gen), ('c2', ts_gen)]
11441157

11451158
(write_timezone, read_timezone) = timezone_pair
@@ -1154,14 +1167,13 @@ def test_orc_non_utc_timezone(reader_confs, end_timestamp, spark_tmp_path, v1_en
11541167
'spark.rapids.sql.format.orc.enabled': True,
11551168
'spark.rapids.sql.format.orc.read.enabled': True,
11561169
'spark.sql.session.timeZone': read_timezone,
1157-
# ignore write timezone when reading, this is for test purpose only
1158-
# The `tz_sensitive_test` mark guarantees the write and read are in the same timezone
1159-
'spark.rapids.sql.orc.read.ignore.write.timezone': True
11601170
})
11611171

11621172
# write on CPU
11631173
cpu_write_path = spark_tmp_path + "/ORC_DATA_CPU"
11641174
with_cpu_session(lambda spark: gen_df(spark, date_timestamp_gens).write.orc(cpu_write_path), conf=write_confs)
1175+
1176+
# read on GPU and CPU
11651177
assert_gpu_and_cpu_are_equal_collect(read_orc_df(cpu_write_path), conf=read_confs)
11661178

11671179
@pytest.mark.skip(reason='https://github.com/NVIDIA/spark-rapids/issues/13272: CPU can not read ORC file generated by GPU when timestamp is less than 1970 year')

integration_tests/src/main/python/window_function_test.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,59 @@ def test_window_aggs_for_rows_collect_set():
24512451
'spark.sql.adaptive.enabled': 'false'})
24522452

24532453

2454+
@pytest.mark.skipif(not is_spark_420_or_later(),
2455+
reason='collect_set RESPECT NULLS is introduced in Spark 4.2')
2456+
@allow_non_gpu("ShuffleExchangeExec")
2457+
@ignore_order(local=True)
2458+
@pytest.mark.parametrize('data_type', ['INT', 'FLOAT', 'DOUBLE'], ids=idfn)
2459+
def test_window_aggs_for_rows_collect_set_respect_nulls(data_type):
2460+
def do_it(spark):
2461+
if data_type == 'INT':
2462+
values = """
2463+
(1, 1, '1'),
2464+
(1, 2, NULL),
2465+
(1, 3, '1'),
2466+
(1, 4, NULL),
2467+
(2, 1, NULL),
2468+
(2, 2, '5')
2469+
"""
2470+
else:
2471+
values = """
2472+
(1, 1, '1.0'),
2473+
(1, 2, NULL),
2474+
(1, 3, 'NaN'),
2475+
(1, 4, 'NaN'),
2476+
(2, 1, NULL),
2477+
(2, 2, '5.0')
2478+
"""
2479+
spark.sql(f"""
2480+
SELECT a, b, CAST(c AS {data_type}) AS c
2481+
FROM VALUES
2482+
{values}
2483+
AS tab(a, b, c)
2484+
""").createOrReplaceTempView("window_collect_table")
2485+
return spark.sql("""
2486+
SELECT a, b,
2487+
sort_array(ignore_set) AS ignore_set,
2488+
sort_array(respect_set) AS respect_set
2489+
FROM (
2490+
SELECT a, b,
2491+
collect_set(c) IGNORE NULLS OVER
2492+
(PARTITION BY a ORDER BY b
2493+
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS ignore_set,
2494+
collect_set(c) RESPECT NULLS OVER
2495+
(PARTITION BY a ORDER BY b
2496+
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS respect_set
2497+
FROM window_collect_table
2498+
) t
2499+
""")
2500+
2501+
assert_gpu_and_cpu_are_equal_collect(
2502+
do_it,
2503+
conf={'spark.rapids.sql.window.collectSet.enabled': True,
2504+
'spark.sql.adaptive.enabled': 'false'})
2505+
2506+
24542507
@ignore_order(local=True)
24552508
@allow_non_gpu(*non_utc_allow)
24562509
def test_window_aggs_for_fully_unbounded_partitioned_collect_set():
@@ -2520,6 +2573,44 @@ def test_window_aggs_for_fully_unbounded_partitioned_collect_set():
25202573
validate_execs_in_gpu_plan=['GpuUnboundedToUnboundedAggWindowExec'])
25212574

25222575

2576+
@pytest.mark.skipif(not is_spark_420_or_later(),
2577+
reason='collect_set RESPECT NULLS is introduced in Spark 4.2')
2578+
@allow_non_gpu("ShuffleExchangeExec")
2579+
@ignore_order(local=True)
2580+
def test_window_aggs_for_fully_unbounded_partitioned_collect_set_respect_nulls():
2581+
assert_gpu_and_cpu_are_equal_sql(
2582+
lambda spark: spark.sql("""
2583+
SELECT * FROM VALUES
2584+
(1, 1, 1),
2585+
(1, 2, NULL),
2586+
(1, 3, 1),
2587+
(1, 4, NULL),
2588+
(2, 1, NULL),
2589+
(2, 2, 5)
2590+
AS tab(a, b, c)
2591+
"""),
2592+
"window_collect_table",
2593+
"""
2594+
SELECT a, b,
2595+
sort_array(ignore_set) AS ignore_set,
2596+
sort_array(respect_set) AS respect_set
2597+
FROM (
2598+
SELECT a, b,
2599+
collect_set(c) IGNORE NULLS OVER
2600+
(PARTITION BY a ORDER BY b
2601+
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ignore_set,
2602+
collect_set(c) RESPECT NULLS OVER
2603+
(PARTITION BY a ORDER BY b
2604+
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS respect_set
2605+
FROM window_collect_table
2606+
) t
2607+
""",
2608+
conf={'spark.rapids.sql.window.collectSet.enabled': True,
2609+
'spark.rapids.sql.window.unboundedAgg.enabled': True,
2610+
'spark.sql.adaptive.enabled': 'false'},
2611+
validate_execs_in_gpu_plan=['GpuUnboundedToUnboundedAggWindowExec'])
2612+
2613+
25232614
@ignore_order(local=True)
25242615
@allow_non_gpu(*non_utc_allow)
25252616
def test_window_aggs_for_fully_unbounded_unpartitioned_collect_set():

0 commit comments

Comments
 (0)