Uh oh!
There was an error while loading. Please reload this page.
[SPARK-16462][SPARK-16460][SPARK-15144][SQL] Make CSV cast null values properly - #14118
[SPARK-16462][SPARK-16460][SPARK-15144][SQL] Make CSV cast null values properly#14118lw-lin wants to merge 6 commits into
Conversation
shivaram
commented
Jul 9, 2016
cc @rxin |
Actually, #12921 includes duplicated changes with here but I will close mine since I like this one more than mine but it would be great if it has |
| if (datum == options.nullValue && nullable) { | ||
| null | ||
| } else { | ||
| if (datum == options.nullValue && nullable && (!castType.isInstanceOf[StringType])) { |
There was a problem hiding this comment.
Do you mind if I ask why StringType is excluded?
There was a problem hiding this comment.
It'd be great to document why string type is ignored here.
There was a problem hiding this comment.
... why StringType is excluded?
Hi @HyukjinKwon, it's just to keep consistency with we did in spark-csv for 1.6. Actually I don't have strong preference here -- maybe we should not ignore StringType? @rxin could you share some thoughts? Thanks!
SparkQA
commented
Jul 9, 2016
Test build #62025 has finished for PR 14118 at commit
|
rxin
commented
Jul 9, 2016
@shivaram did you review this? |
shivaram
commented
Jul 10, 2016
No - I just noticed a JIRA that said it was a regression, so I wanted to make sure you caught this in the RC cycle |
FYI, before SPARK-14143, null values had been handled this way: : if (datum == options.nullValue && nullable && (!castType.isInstanceOf[StringType])) {
null
} else {
castType match ...
}Then in SPARK-14143, it was first broken down into numeric data types in 93ac6bb to handle byte-specific null value, short-specific null value, int-specific null value, ... : castType matchcase_: ByteType=>if (datum == params.byteNullValue && nullable) nullelse datum.toByte
case_: ShortType=>if (datum == params.shortNullValue && nullable) nullelse datum.toShort
case_: IntegerType=>if (datum == params.integerNullValue && nullable) nullelse datum.toInt
...then in 698b4b4 byte-specific null value, short-specific null value, int-specific null value, ... were reduced back to one single null value: castType matchcase_: ByteType=>if (datum == params.nullValue && nullable) nullelse datum.toByte
case_: ShortType=>if (datum == params.nullValue && nullable) nullelse datum.toShort
case_: IntegerType=>if (datum == params.nullValue && nullable) nullelse datum.toInt
...Along with that change, we had introduced regression handling non-numeric data types like if (datum == options.nullValue && nullable && (!castType.isInstanceOf[StringType])) {
null
} else {
castType match ...
} |
I just wonder why string should be ignored in the case above. I mean, you just said "we don't need to handle type-specific null values" and it seems strings are okay to be handled together. |
lw-lin
commented
Jul 10, 2016
@HyukjinKwon hi. The explanation above intends to help reviewers better understand how we introduced the regression. Regarding whether |
rxin
commented
Jul 11, 2016
Thanks for the information. I'm still confused. From an end-user perspective, do we need to handle StringType there? |
IMHO, handling |
I think @HyukjinKwon has made a good point: it's kind of strange null strings can be written out, but can not be read back as nulls. So for
@HyukjinKwon and I are somewhat inclined to option(b) because it sounds reasonable to end-users. @rxin would you mind making a final decision? Thanks! |
deanchen
commented
Jul 31, 2016
Would be great to get a resolution to this. We're running into issues in production attempting to parse csv's with nullable dates. Personally prefer option b for our use case. |
Some findings as I dug a little:
Then after the above 1.2.3., in
However we don't have this |
falaki
commented
Aug 5, 2016
@lw-lin thanks a lot for the clear summary. |
SparkQA
commented
Aug 5, 2016
Test build #63260 has finished for PR 14118 at commit
|
@falaki could you take a look at the latest update: [bf01cea] StringType should also respect |
| assert( | ||
| CSVTypeCast.castTo(null, StringType, nullable = true, CSVOptions("nullValue", "null")) == | ||
| null) |
There was a problem hiding this comment.
Maybe we can use assertNull as you just did above?
There was a problem hiding this comment.
Oh thanks!I did this intentionally so that the diff is minimal and clear to reviewers. Maybe let's see what others think and I'm glad to change this if necessary. :)
nvm, this indeed should be assertNull
HyukjinKwon
commented
Aug 5, 2016
This change looks reasonable to me. |
djk121
commented
Aug 5, 2016
Is there a way to fall back to the old databricks csv library in spark 2.0 to work around this? Round-tripping worked there with .option("nullValue", "null"), but I don't see a way to get round-tripping working with any combo of options in 2.0. |
rxin
commented
Aug 5, 2016
You can specify "com.databricks.spark.csv" as the source. On Fri, Aug 5, 2016 at 11:58 PM, djk121 notifications@github.com wrote:
|
djk121
commented
Aug 6, 2016
I'm doing this: val dataframe = sparkSession.read I then take that dataframe and attempt to write it out to parquet like so: dataframe.write When the parquet writes go, I get the same traceback as above. I can see from that traceback that it's org.apache.spark.sql.execution.datasources.csv, so for whatever reason, com.databricks.spark.csv isn't being used. Do I need to do something different to force it to be used? |
BTW, this problem exists in the external CSV data source as well (but only for |
SparkQA
commented
Aug 10, 2016
Test build #63493 has finished for PR 14118 at commit
|
devmanhinton
commented
Aug 12, 2016
Just as a +1 would at least like the option to have |
SparkQA
commented
Aug 19, 2016
Test build #64040 has finished for PR 14118 at commit
|
@rxin yes all empty values become null values once they are read back! E.g. given
|
What if I am writing explicitly an empty string out? Does it become just 1,,2? Can you also clarify whether this is behavior changing, or something else? |
@rxin Please let me leave my though why I thought it looks good to me in case it is helpful. Yes, but we should set For example, if we have the dataframe as below: with Here, we ended up with no diff between I mean.. as far as I know, there is no (standard) expression for actual |
I re-editted this as I found this comment is super confusing. I meant suggesting |
Yes. It becomes
This patch behaves differently from 2.0 when reading @rxin ~ |
lw-lin
commented
Aug 29, 2016
Jenkins retest this please |
SparkQA
commented
Aug 29, 2016
Test build #64576 has finished for PR 14118 at commit
|
hvanhovell
commented
Sep 7, 2016
retest this please |
SparkQA
commented
Sep 7, 2016
Test build #65042 has finished for PR 14118 at commit
|
srowen
commented
Sep 12, 2016
@lw-lin just checking that you think this is still good to go? @HyukjinKwon do you have an opinion on the current state? |
I support this PR. But just to make sure, I'd like to bring a reference. It seems at least bt<-"A,B,C,D10,20,NaN30,,4040,30,20,NA,20"b<- read.csv(text=bt, na.strings=c("NA","NaN", ""))
bprints |
lw-lin
commented
Sep 14, 2016
@HyukjinKwon thanks for the information! @srowen yea I still think this is good to go. |
lw-lin
commented
Sep 14, 2016
Jenkins retest this please |
SparkQA
commented
Sep 14, 2016
Test build #65343 has finished for PR 14118 at commit
|
| the default value, ``false``. | ||
| :param nullValue: sets the string representation of a null value. If None is set, it uses | ||
| the default value, empty string. | ||
| the default value, empty string. Since 2.0.1, this ``nullValue`` param |
There was a problem hiding this comment.
I think you can omit the "since x.y.z" in this PR. The new text will be in the docs for the version it applies to and not earlier ones.
There was a problem hiding this comment.
This patch introduces a behavior change, i.e. how we deal with nullValue for the string type. So let's keep the "since x.y.z" thing for people to find a clue?
| // If it fails to parse, then tries the way used in 2.0 and 1.x for backwards | ||
| // compatibility. | ||
| DateTimeUtils.stringToTime(datum).getTime * 1000L | ||
| if (datum == options.nullValue && nullable) { |
There was a problem hiding this comment.
Is it possibly worth checking if (nullable && ...) to avoid the comparison if it's not nullable?
There was a problem hiding this comment.
yea let me do that. thanks.
| case _: IntegerType => datum.toInt | ||
| case _: LongType => datum.toLong | ||
| case _: FloatType => | ||
| if (datum == options.nanValue) { |
There was a problem hiding this comment.
Can these nested if-else statements be a match statement? or is there some overhead to it that is too significant?
There was a problem hiding this comment.
Yea they should be a match statement -- let me update this, thanks!
hvanhovell
commented
Sep 15, 2016
SparkQA
commented
Sep 16, 2016
Test build #65466 has finished for PR 14118 at commit
|
srowen
commented
Sep 18, 2016
Merged to master/2.0 |
…s properly ## Problem CSV in Spark 2.0.0: - does not read null values back correctly for certain data types such as `Boolean`, `TimestampType`, `DateType` -- this is a regression comparing to 1.6; - does not read empty values (specified by `options.nullValue`) as `null`s for `StringType` -- this is compatible with 1.6 but leads to problems like SPARK-16903. ## What changes were proposed in this pull request? This patch makes changes to read all empty values back as `null`s. ## How was this patch tested? New test cases. Author: Liwei Lin <lwlin7@gmail.com> Closes#14118 from lw-lin/csv-cast-null. (cherry picked from commit 1dbb725) Signed-off-by: Sean Owen <sowen@cloudera.com>
…s properly ## Problem CSV in Spark 2.0.0: - does not read null values back correctly for certain data types such as `Boolean`, `TimestampType`, `DateType` -- this is a regression comparing to 1.6; - does not read empty values (specified by `options.nullValue`) as `null`s for `StringType` -- this is compatible with 1.6 but leads to problems like SPARK-16903. ## What changes were proposed in this pull request? This patch makes changes to read all empty values back as `null`s. ## How was this patch tested? New test cases. Author: Liwei Lin <lwlin7@gmail.com> Closesapache#14118 from lw-lin/csv-cast-null.

Problem
CSV in Spark 2.0.0:
Boolean,TimestampType,DateType-- this is a regression comparing to 1.6;options.nullValue) asnulls forStringType-- this is compatible with 1.6 but leads to problems like SPARK-16903.What changes were proposed in this pull request?
This patch makes changes to read all empty values back as
nulls.How was this patch tested?
New test cases.