fix: Add nulls in json reads if a line doesn't contain the field from the schema - #4993
Conversation
There was a problem hiding this comment.
Greptile Summary
This PR fixes a critical bug in Daft's JSON reading functionality to handle newline-delimited JSON (NDJSON) files where records have inconsistent schemas across lines. The core issue was that when a JSON record was missing a field that existed in the inferred schema, the deserializer would either throw an error or skip the field entirely, causing Arrow array length mismatches when constructing RecordBatches.
The fix implements a null-filling strategy across multiple components of the JSON reading pipeline:
-
Deserialization Logic (
decoding.rs): The fundamental change switches from iterating over record fields to iterating over schema fields. For each schema field, if the field exists in the JSON record, its value is deserialized; if missing, a null value is pushed instead. This ensures every record produces the same number of values per field. -
API Simplification (
read.rs): Theschema_is_projectionparameter is removed from thedeserialize_recordsfunction, simplifying the API since the new logic handles schema consistency internally. The change also updates fromRecordBatch::new_uncheckedtoRecordBatch::new_with_sizefor better validation. -
Local Processing (
local.rs): Similar null-filling logic is applied in three locations during JSON array reading, object reading within arrays, and chunked JSON parsing, replacing error-throwing behavior with null insertion. -
Test Coverage (
test_json_roundtrip.py): Comprehensive tests are added to verify the null-filling behavior works correctly for both single-file and multi-file scenarios, including support for gzip compression.
This change aligns Daft's JSON reader with standard JSON processing behavior where missing fields are treated as null values, enabling proper handling of real-world JSON data that often has heterogeneous schemas. The fix also enables support for compressed JSON files (.json.gz) as mentioned in the related issue.
Confidence score: 4/5
- This PR is safe to merge with minimal risk as it fixes a clear bug and follows standard JSON processing patterns
- Score reflects well-structured changes with comprehensive test coverage, though the complexity of multi-file JSON handling adds some risk
- Pay close attention to the core deserialization logic in
src/daft-json/src/decoding.rsto ensure the null-filling behavior works correctly across all JSON formats
4 files reviewed, no comments
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4993 +/- ##
==========================================
- Coverage 75.27% 75.19% -0.09%
==========================================
Files 949 949
Lines 132520 132523 +3
==========================================
- Hits 99761 99647 -114
- Misses 32759 32876 +117
🚀 New features to boost your workflow:
|
|
@universalmind303 could you give this a look? |
|
|
||
|
|
||
| @pytest.mark.parametrize("compression", [None, "gzip"]) | ||
| def test_roundtrip_ndjson_with_mismatched_schema_between_files(tmp_path, compression): |
There was a problem hiding this comment.
One other interesting case to test for is if path2 is read before path1. In this case we drop the city column (since it wasn't present during schema inference), which seems good enough to me.
… the schema (Eventual-Inc#4993) ## Changes Made If the schema of an nd-json differs across records, we should fill with null instead of skipping it, otherwise it causes a series length mismatch error down the line when we create or modify the record batch. ## Related Issues Closes Eventual-Inc#4602 ## Checklist - [ ] Documented in API Docs (if applicable) - [ ] Documented in User Guide (if applicable) - [ ] If adding a new documentation page, doc is added to `docs/mkdocs.yml` navigation - [ ] Documentation builds and is formatted properly (tag @/ccmao1130 for docs review)
Changes Made
If the schema of an nd-json differs across records, we should fill with null instead of skipping it, otherwise it causes a series length mismatch error down the line when we create or modify the record batch.
Related Issues
Closes #4602
Checklist
docs/mkdocs.ymlnavigation