Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] listReduce on a single row input with an empty list generates a zero row output #10556

Closed
gerashegalov opened this issue Mar 31, 2022 · 5 comments · Fixed by #10876
Closed
Assignees
Labels
bug Something isn't working libcudf Affects libcudf (C++/CUDA) code. Spark Functionality that helps Spark RAPIDS

Comments

@gerashegalov
Copy link
Contributor

gerashegalov commented Mar 31, 2022

Describe the bug
While testing ArrayExists in spark-rapids we hit an exception when a partition consists of a single row with an empty list. The root cause is somewhere behind the fact that listReduce produces an empty output instead of maintaining the invariant: output row count equals input row count

Steps/Code to reproduce bug

The repro via JVM in Scala REPL is as follows.

val dt = new HostColumnVector.ListType(true, new HostColumnVector.BasicType(true, DType.BOOL8))
val singleEmptyListCV = ColumnVector.fromLists(dt, java.util.Arrays.asList())
// singleEmptyListCV: ai.rapids.cudf.ColumnVector = ColumnVector{rows=1, type=LIST, nullCount=Optional.empty, offHeap=(ID: 5 7fb64ad20650)}
val singleEmptyListReducedCV = singleEmptyListCV.listReduce(SegmentedReductionAggregation.any(), NullPolicy.INCLUDE, DType.BOOL8)
// singleEmptyListReducedCV: ai.rapids.cudf.ColumnVector = ColumnVector{rows=0, type=BOOL8, nullCount=Optional.empty, offHeap=(ID: 6 7fb5b2469d20)}
val gpuCVClz = ShimLoader.loadClass("com.nvidia.spark.rapids.GpuColumnVector")
MethodUtils.invokeStaticMethod(gpuCVClz, "debug", "bad", singleEmptyListReducedCV)
// GPU COLUMN bad - NC: 0 DATA: null VAL: null
// COLUMN bad - BOOL8

The output is as expected if the input includes another row with a non-empty list

val emptyAndNonEmptyListCV = ColumnVector.fromLists(dt, java.util.Arrays.asList(), java.util.Arrays.asList(false))
// emptyAndNonEmptyListCV: ai.rapids.cudf.ColumnVector = ColumnVector{rows=2, type=LIST, nullCount=Optional.empty, offHeap=(ID: 13 7fb5a8171ce0)}
val emptyAndNonEmptyListReducedCV = emptyAndNonEmptyListCV.listReduce(SegmentedReductionAggregation.any(), NullPolicy.INCLUDE, DType.BOOL8)
// emptyAndNonEmptyListReducedCV: ai.rapids.cudf.ColumnVector = ColumnVector{rows=2, type=BOOL8, nullCount=Optional.empty, offHeap=(ID: 14 7fb5b6de1020)}
MethodUtils.invokeStaticMethod(gpuCVClz, "debug", "good", emptyAndNonEmptyListReducedCV)
// GPU COLUMN good - NC: 1 DATA: DeviceMemoryBufferView{address=0x7fb5bfc01000, length=2, id=-1} VAL: DeviceMemoryBufferView{address=0x7fb5bfc01400, length=64, id=-1}
// COLUMN good - BOOL8
// 0 NULL
// 1 false

Expected behavior
Reduction of a single row with an empty list should produce a single row output

Environment overview (please complete the following information)

  • Environment location: any
  • Method of cuDF install: from source

Environment details
TBD

Additional context
NVIDIA/spark-rapids#5108

@gerashegalov gerashegalov added bug Something isn't working Needs Triage Need team to review and classify Java Affects Java cuDF API. labels Mar 31, 2022
@gerashegalov gerashegalov added the Spark Functionality that helps Spark RAPIDS label Mar 31, 2022
@gerashegalov gerashegalov self-assigned this Apr 4, 2022
@github-actions
Copy link

github-actions bot commented May 4, 2022

This issue has been labeled inactive-30d due to no recent activity in the past 30 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed. This issue will be labeled inactive-90d if there is no activity in the next 60 days.

@jlowe jlowe added libcudf Affects libcudf (C++/CUDA) code. and removed Java Affects Java cuDF API. labels May 13, 2022
@jlowe
Copy link
Member

jlowe commented May 13, 2022

This appears to be a bug in libcudf rather than the cudf Java/JNI layer.

@jlowe
Copy link
Member

jlowe commented May 13, 2022

Apply the following patch and build gtests/REDUCTION_TEST to reproduce the issue in C++:

diff --git a/cpp/tests/reductions/segmented_reduction_tests.cpp b/cpp/tests/reductions/segmented_reduction_tests.cpp
index 8a9a8fb549..2f3044ea4f 100644
--- a/cpp/tests/reductions/segmented_reduction_tests.cpp
+++ b/cpp/tests/reductions/segmented_reduction_tests.cpp
@@ -107,6 +107,27 @@ TYPED_TEST(SegmentedReductionTest, MaxExcludeNulls)
   CUDF_TEST_EXPECT_COLUMNS_EQUAL(*res, expect);
 }
 
+TYPED_TEST(SegmentedReductionTest, MaxExcludeNullsAllNull)
+{
+  // [null]
+  // values:    {}
+  // offsets:   {0, 0}
+  // nullmask:  {1}
+  // outputs:   {XXX}
+  // output nullmask: {1}
+  auto input     = fixed_width_column_wrapper<TypeParam>{};
+  auto offsets   = std::vector<size_type>{0,0};
+  auto d_offsets = thrust::device_vector<size_type>(offsets);
+  auto expect = fixed_width_column_wrapper<TypeParam>{{XXX}, {1}};
+
+  auto res = segmented_reduce(input,
+                              d_offsets,
+                              *make_max_aggregation<segmented_reduce_aggregation>(),
+                              data_type{type_to_id<TypeParam>()},
+                              null_policy::EXCLUDE);
+  CUDF_TEST_EXPECT_COLUMNS_EQUAL(*res, expect);
+}
+
 TYPED_TEST(SegmentedReductionTest, MinExcludeNulls)
 {
   // [1, 2, 3], [1, null, 3], [1], [null], [null, null], []

The problem occurs when the lists column is all nulls and the child column is empty (because there is no need for backing values in a list of all nulls).

@jrhemstad jrhemstad removed the Needs Triage Need team to review and classify label May 16, 2022
@davidwendt davidwendt self-assigned this May 17, 2022
@davidwendt
Copy link
Contributor

davidwendt commented May 17, 2022

I just want to verify that the expected result is a single row column (size()==1) where row 0 is null.
So the above test case should actually have the expect column initialized as:

auto expect = fixed_width_column_wrapper<TypeParam>{{XXX}, {0}};

@jlowe

@jlowe
Copy link
Member

jlowe commented May 17, 2022

the expected result is a single row column (size()==1) where row 0 is null.

Yes, apologies for the bug in the test.

rapids-bot bot pushed a commit that referenced this issue May 18, 2022
Fixes `cudf::segmented_reduce` where the input `values` column is empty but the `offsets` are not. In this case, the `offsets` vector `{0,0}` specifies an empty segment which should result in a single null row. The logic has been fixed and new gtest cases have been added.

Closes #10556

Authors:
  - David Wendt (https://github.com/davidwendt)

Approvers:
  - Bradley Dice (https://github.com/bdice)
  - Jason Lowe (https://github.com/jlowe)
  - Nghia Truong (https://github.com/ttnghia)

URL: #10876
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working libcudf Affects libcudf (C++/CUDA) code. Spark Functionality that helps Spark RAPIDS
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants