Repository navigation
TIMX 738 - Parquet IO - #281
Merged
Merged
Conversation
Why these changes are being introduced: * Re-transforming a subset of records and comparing before/after in Timmy requires reading source records from a Timmy parquet export, and writing transformed records Timmy can import. How this addresses that need: * Add CLI option --input-parquet, which streams source records from a parquet file or directory (e.g. a Timmy export), filtered by source and action='index', in sorted file order. Non-parquet files are ignored. * Treat parquet input as a 'patch' run, the same as dataset input. * Add CLI option --output-parquet, which writes parquet files matching the Timmy export schema and layout: transformed_record as string, run_record_offset as int64, no partitioning or metadata, 100k rows per file, 5k rows per row group, ZSTD compression, and rows in run order. * Require exactly one input option and exactly one output option; --output-dataset is no longer required on its own. * Add pyarrow as a direct dependency. Side effects of this change: * None for existing --input-file / --input-dataset / --output-dataset runs. Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/TIMX-738
Why these changes are being introduced: * A plain file of transformed records is handy for local debugging and quick inspection, without writing a TIMDEX dataset or parquet files. How this addresses that need: * Add CLI option --output-file, which writes transformed records to a local or S3 JSONLines file, one per line. * Only records with action 'index' are written; deleted, skipped, and errored records are still counted and logged. Side effects of this change: * None. Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/TIMX-738
Why these changes are being introduced: * The README CLI section still showed --output-location, and did not describe the parquet and file input/output options. How this addresses that need: * Add tables of input and output options, and refresh the transform --help output. Side effects of this change: * None. Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/TIMX-738
ghukill
commented
Nov 3, 2026
Comment on lines
+462
to
+470
| def write_to_file(self, output_file: str) -> int: | ||
| """Write transformed records to a JSONLines file, one record per line. | ||
|
|
||
| Only records with action 'index' are written. Deleted, skipped, and errored | ||
| records are counted and logged as usual, but not written. | ||
|
|
||
| Args: | ||
| output_file: Local or S3 filepath to write to. | ||
| """ |
Contributor
Author
There was a problem hiding this comment.
@jonavellecuerdo - here is the (re)introduction of Transmogrifier also supporting writing to a simple file. Again, may not get used much, but we almost get it for free and it provides nice parity I think at the input + output formats.
ehanson8
approved these changes
Nov 3, 2026
ehanson8
left a comment
Contributor
There was a problem hiding this comment.
Looks good and works as expected!
| raise ValueError( | ||
| "Exactly one input source is required: 'source_file' or 'source_dataset'" | ||
| ) | ||
| if len([i for i in (source_file, source_dataset, source_parquet) if i]) != 1: |
Contributor
There was a problem hiding this comment.
Interesting way for the agent to address this! 😆
Contributor
Author
There was a problem hiding this comment.
I thought the same! It's not what I would have written... but I'm growing to like it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
This is the first of three stacked PRs.
Purpose and background context
This PR updates Transmogrifier to accept parquet files as input and output. This builds on work from TIMX-700 that introduced the TIMDEX dataset as an input source.
Before that work, the only input source for Transmogrifier was individual files either locally or in S3. Dataset as input unlocked running a transformation job against a subset of records in the dataset (e.g. all current records for a source) without the need to re-harvest. Parquet as input allows transformation of a subset of records, where the subset is most likely created by Timmy.
The updated README shows the new CLI arguments, whichi also introduce an
--output-fileto provide some parity with--input-file.It is worth observing that in TIMDEX, Transmogrifier is the step/application that creates an ETL run in the datatset. Therefore, using parquet files as input extends the idea of a "patch" run -- as opposed to a "daily" or "full" -- because we are transforming source metadata records already in the dataset; they may not have come directly from the dataset like
--input-dataset, but the parquet files are likely a direct export of those records.There are two primary things we get from these new input/output options:
Creation of a subset in Timmy, exported to parquet, becomes a true "patch" ETL job of a subset of records.
Timmy exports a subset, Transmogrifier transforms and writes back to parquet, Timmy imports and analysis is performed showing what the transformation did to the records compared to the previous versions.
It is # 2 that drove this PR, as we now can run huge
almatransformations jobs using parquet as input and output, with the goal being analysis in Timmy. Once we are satisfied with the results of the transformation logic, we will likely use--input-datasetfor a "real" ETL job that also writes back to the TIMDEX dataset.How can a reviewer manually see the effects of these changes?
1- Set TIMDEX Dev1 AWS credentials
2- Perform a Transmogrifier run using parquet files from S3, and write them locally for quick analysis:
You should see some similar output:
3- Quick analysis of the output parquet using DuckDB. First, start a shell:
Then select some rows from the parquet data output by Transmogrifier:
You should see rows that contain columns
[timdex_record_id, source_record, transformed_record, source, run_date, run_type, action, run_id, run_record_offset, run_timestamp]. By no accident or coincidence, these are precisely what Transmogrifier would otherwise write to the TIMDEX dataset.We might start to consider this the most minimal "Submission Information Package" (SIP) for TIMDEX, as it includes the source + transformed record and metadata about the ETL run that produced it.
4- Lastly, we can demonstrate the roundtrip-ability of this data by using what Transmogrifier just output as input for another transformation:
Obviously the outputs will be the same, but it demonstrates the input + output schema is identical. This demonstrates how Timmy can either produce or consume the parquet "SIPs" as well.
Includes new or updated dependencies?
NO
Changes expectations for external applications?
YES: this opens the door to a "patch" ETL run consisting of a subset of records that came from the TIMDEX dataset.
What are the relevant tickets?
Code review