Fast-Forward to Iceberg
This example generates a day of a shop's orders at factor=0.0 and appends them to an Apache Iceberg table through an Iceberg REST catalog. Egress shows the other catalogs. Each tab shows the example written one way: as a YAML blueprint, with the builder API, or with the low-level API. Ways to write a simulation compares the three.
ParquetStorageEgress writes files and leaves registering them as a table to you. IcebergStorageEgress appends into an Iceberg table instead, so one run ends with a table another engine can query. Look for the day's events as rows of simulation.events, and for the few snapshots that hold them.
Each flush of the buffer is one Iceberg commit. Every commit writes a manifest, a manifest list and a new metadata.json, so query planning slows down as snapshots build up. This example therefore gives the Iceberg egress a large batch_size of its own. At factor=0.0 the buffer is flushed each time it holds 200,000 records, and once more at the end of the run. Each flush adds one snapshot to the table.
Before You Start
The example needs Docker and the odctl profile catalog, which each Quick Start below starts and stops. Services for the Examples shows how to install odctl.
Steps
Run It
This example builds the simulation of the builder example in the Builder tab from a YAML blueprint, with no Python. A day of shop orders is generated at factor: 0.0, and each flush of the buffer becomes one Iceberg commit.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
What It Does
The run appends a day of lifecycle events to the simulation.events table and ends on its own. With batch_size: 200000 on the egress, the buffer is flushed once per 200,000 records, and each flush is one commit. The day therefore lands in a few snapshots. Without a router, each event is written to default_table as one flat row, and telemetry is left out.
The catalog is contacted on the first write, not when the blueprint is loaded, so a blueprint with a wrong catalog address still loads and fails when the first batch is written.
ICEBERG_URI, ICEBERG_WAREHOUSE, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY and S3_REGION override the catalog and credentials.
This version builds the simulation with the builder API (SimulationContext) and writes with IcebergStorageEgress.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
ICEBERG_URI, ICEBERG_WAREHOUSE, ICEBERG_NAMESPACE, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY and S3_REGION override the catalog and credentials.
A second run appends to the same table rather than replacing it, because IcebergStorageEgress appends every record by default. Use odctl down catalog --volumes to start again with an empty catalog.
This version wires the simulation by hand on DynamicRealtimeEnvironment, the low-level API, and writes with IcebergStorageEgress.
Quick Start
desflow examples get downloads the example at the release you install, into a folder of its own. Pick uv or pip:
ICEBERG_URI, ICEBERG_WAREHOUSE, ICEBERG_NAMESPACE, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY and S3_REGION override the catalog and credentials.
A second run appends to the same table rather than replacing it, because IcebergStorageEgress appends every record by default. Use odctl down catalog --volumes to start again with an empty catalog.
Check the Result
The three tabs write the same records, which a test checks by running each version unpaced. A real run appends them as rows of the simulation.events table. desflow run iceberg.yaml --sample 4 --stdout prints the first four events as JSON lines instead, and contacts no catalog:
Each event becomes one row of the table, and the two fields of value, path_id and status, become columns of their own.
Full Files
Full files
catalog is a mapping of PyIceberg catalog properties, passed to PyIceberg's load_catalog. schemas names a type for each column, so timestamp is created as a timestamp rather than inferred as a string. The ISO time each record carries is converted to a timestamp before the write.
Files live in the examples/yaml/ folder of the repository, and the label on each block below is its path there.
This script simulates the shop over a 1-day period. It routes lifecycle events into one Iceberg table. It pins the schema, so the event time is stored as a timestamp. Without the schema, the column would be inferred as a string.
Scripts live in the examples/ folder of the repository, and the label on the block below is this one's path there.
| examples/builder/iceberg_example.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
This script simulates the shop over a 1-day period. It routes lifecycle events into one Iceberg table. It pins the schema, so the event time is stored as a timestamp. Without the schema, the column would be inferred as a string.
Scripts live in the examples/ folder of the repository, and the label on the block below is this one's path there.
| examples/low-level/iceberg_example.py | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |