Jorge Molina created SPARK-58457:
------------------------------------
Summary: CSV and JSON docs claim PERMISSIVE drops corrupt records
when no columnNameOfCorruptRecord field is declared; it never does
Key: SPARK-58457
URL: https://issues.apache.org/jira/browse/SPARK-58457
Project: Spark
Issue Type: Documentation
Components: SQL
Affects Versions: 5.0.0
Reporter: Jorge Molina
`docs/sql-data-sources-csv.md` and `docs/sql-data-sources-json.md` both describe
`PERMISSIVE` mode with a character-identical pair of sentences:
{quote}
*To keep corrupt records*, an user can set a string type field named
`columnNameOfCorruptRecord` in an user-defined schema. *If a schema does not
have the
field, it drops corrupt records during parsing.*
{quote}
Neither sentence matches the behaviour of either data source.
`columnNameOfCorruptRecord` does not control whether a corrupt record is kept —
it is
always kept, with its malformed fields set to `null`. The field controls
whether the
*malformed string itself* is available.
This is the sentence a reader consults when deciding whether they need the
field, and
it points them the wrong way — it implies a schema *without* the field is the
safe
choice because bad records disappear. In fact they are admitted,
indistinguishable
from records that were genuinely null at the source, with no error and no
signal.
h3. The test suite on master already asserts the correct behaviour, in both
data sources
*CSV* — `CSVSuite`'s test {{SPARK-18699 put malformed records in a
`columnNameOfCorruptRecord` field}} reads `test-data/value-malformed.csv`,
whose two
records are `0,2013-111_11 12:13:14` (unparseable date) and `1,1983-08-04`. With
schema `a INT, b DATE` and *no* corrupt-record field it asserts:
{code:scala}
checkAnswer(df1, Row(0, null) :: Row(1, java.sql.Date.valueOf("1983-08-04")) ::
Nil)
{code}
Two rows — the corrupt record kept, its bad field nulled. Were the documented
sentence accurate, this assertion would expect one row.
*JSON* — `JsonSuite` is more direct still. The test is named {{Corrupt records:
PERMISSIVE mode, without designated column for malformed records}}, reads the
`corruptRecords` fixture with a three-column user-defined schema and no
corrupt-record
column, and asserts five rows — four entirely null — under Spark's own comment:
{code:scala}
// Corrupted records are replaced with null
Row(null, null, null),
{code}
So the correction is not a claim about behaviour that needs establishing; it is
alignment with what the project already asserts.
h3. Corroborated by direct measurement
`pyspark` 3.5.9, three source records per case, `PERMISSIVE`, user-defined
schema
`a INT, b STRING`:
|| format || bad record || rows without the field || rows with the field ||
flagged corrupt ||
| JSON | not parseable as JSON at all | 3 | 3 | 1 |
| JSON | valid JSON, wrong type for schema | 3 | 3 | 1 |
| CSV | wrong type for schema | 3 | 3 | 1 |
| CSV | unterminated quote | 3 | 3 | 0 |
Identical counts in every case. The JSON rows matter most: JSON is where the
sentence
would be most defensible, since a whole JSON record genuinely can be
unparseable —
and it is still retained.
Measured on `pyspark` 3.5.9 rather than on `master`, so this is corroboration;
the two
`master` assertions above are the load-bearing evidence.
h3. Proposed fix
Replace *both* sentences, in both files, with:
{quote}
To capture the malformed string, an user can set a string type field named
`columnNameOfCorruptRecord` in an user-defined schema. If a schema does not
have the
field, the corrupt record is still retained with its malformed fields set to
`null`,
but the malformed string is not available.
{quote}
Both sentences have to move together: correcting only the second would leave the
paragraph contradicting itself, since the first assigns retention to the field
while
the second would deny retention without it. One line per file. PR to follow.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]