-
Notifications
You must be signed in to change notification settings - Fork 240
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
Fix from_json
function failure when input contains empty or null strings
#8526
Fix from_json
function failure when input contains empty or null strings
#8526
Conversation
Signed-off-by: Cindy Jiang <[email protected]>
build |
val res = struct.fields.foldRight ("") ((field, acc) => | ||
field.dataType match { | ||
case IntegerType => "\"" + field.name + "\": 0, " + acc | ||
case _ => "\"" + field.name + "\": \"\", " + acc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to take care of a nested StructType
here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really inefficient fix in terms of memory usage on the GPU. I fixed most of this in CUDF with rapidsai/cudf#13477 except for the one use case that you are testing in the python code.
Can we have a follow on issue to only do this if all of the strings are empty strings or '{}' in 23.08? We technically only need one row to have this in it and the rest can be empty, but trying to make that happen feels more expensive than just expanding this out everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@firestarman Yes, thank you! I will update this to take care of nested StructType
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@revans2 I will file a follow up issue in 23.08. Thank you for pointing this out!
sql-plugin/src/main/scala/org/apache/spark/sql/rapids/GpuJsonToStructs.scala
Outdated
Show resolved
Hide resolved
sql-plugin/src/main/scala/org/apache/spark/sql/rapids/GpuJsonToStructs.scala
Outdated
Show resolved
Hide resolved
val res = struct.fields.foldRight ("") ((field, acc) => | ||
field.dataType match { | ||
case IntegerType => "\"" + field.name + "\": 0, " + acc | ||
case _ => "\"" + field.name + "\": \"\", " + acc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really inefficient fix in terms of memory usage on the GPU. I fixed most of this in CUDF with rapidsai/cudf#13477 except for the one use case that you are testing in the python code.
Can we have a follow on issue to only do this if all of the strings are empty strings or '{}' in 23.08? We technically only need one row to have this in it and the rest can be empty, but trying to make that happen feels more expensive than just expanding this out everywhere.
input.incRefCount | ||
} else { | ||
withResource(cudf.Scalar.fromString(" ")) { space => | ||
input.strip(space) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we look for other places that strip, rstrip, and lstrip are called? I did a quick look and I think we might get the same problem on
col.rstrip() |
spark-rapids/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/stringFunctions.scala
Line 306 in e3b9517
GpuColumnVector.from(column.getBase.rstrip(t), dataType) |
spark-rapids/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/stringFunctions.scala
Line 286 in e3b9517
GpuColumnVector.from(column.getBase.lstrip(t), dataType) |
But there may be others.
At a minimum we need to test these too and fix them if they are also broken
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@revans2 Thanks! I tested GpuStringTrim[Left, Right]
implementation above. The same problem comes up. I added integration tests and fixes for them.
col.rstrip() |
I didn't find tests for the above
rstrip()
call site, and haven't added a fix yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is fine. That is specifically for a special case ORC char type. We should file an issue for it just so it is not missed, but it should be really rare.
Signed-off-by: Cindy Jiang <[email protected]>
Signed-off-by: Cindy Jiang <[email protected]>
Signed-off-by: Cindy Jiang <[email protected]>
Signed-off-by: Cindy Jiang <[email protected]>
Added fix and tests for the following spark-rapids/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/stringFunctions.scala Line 266 in e3b9517
|
Signed-off-by: Cindy Jiang <[email protected]>
build |
Signed-off-by: Cindy Jiang <[email protected]>
build |
case struct: StructType if (struct.fields.length > 0) => { | ||
val jsonFields: Array[String] = struct.fields.map { field => | ||
field.dataType match { | ||
case IntegerType => s""""${field.name}": 0""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, does Spark really return a 0 and not a null for an empty int column???
What happens if a field name has odd characters in it? Can it have a " for example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not certain about Spark side. I will investigate more. For odd characters, I think it would fail at readJSON
parsing step. I will follow up with this in #8542. Thank you so much!
Fixes #8522.
During testing, we found
from_json
function throws ajava.lang.ArrayIndexOutOfBoundsException
(fromai.rapids.cudf.TableWithMeta.releaseTable
) when the input column contains empty or null strings. When pre-processing the input columns, we have replaced all empty string or null rows in the input column with "{}", but callingai.rapids.cudf.Table.readJSON
on the input column (containing other valid json strings) would result in tables with different number of columns, resulting in future ArrayIndexOutOfBoundsException since rows contain tables of different sizes.=> To fix this issue, instead of replacing empty strings/nulls with "{}", we replace them with a dummy json string based on the input
schema
. For example, ifschema
isStructType([StructField("a", StringType), StructField("b", IntegerType)])
, then we will replace empty strings and nulls with "{"a": "", "b": 0}". This ensures that all rows contain tables with the same number of columns afterreadJSON
.When testing the above solution, we encountered another issue with
strip
function: rapidsai/cudf#13529. The problem only occurs when the input column contains only empty strings and nulls. Our approach is to first check the data buffer for the input string column, and if it is empty, we do not callstrip
and just callincRefCount
on the origin column.Follow-up issue tracked: #8542