Data Sets
Seven data sets, each generated by one blueprint: a retail set written to three sinks, a film rental store, auction streams, a group-by table, taxi rides, labelled text and a point-in-time training set. Each entry is a complete file in three forms, so you can run it, read how it is built and change it.
Before You Start
The commands run from the root of a clone of the repository, where the files are in examples/gallery/:
An entry that needs a service or an extra says so. Services for the Examples shows how to start the services. A file with a fixed random_seed and factor: 0 prints the same records on every run, and each output block below holds the first events of the YAML file. The Builder and Low-level files publish the same records.
Entries
Retail records go to PostgreSQL, Kafka and Parquet
A shop has 20 customers and 10 products at the start and takes about one order every two seconds. Each order picks a customer and a product at random and is followed by its invoice. The reference data goes to PostgreSQL tables, the orders to a Kafka topic and the invoices to a Parquet file, each sink taking the records of its own tasks (the when expression of the entry).
It needs a broker and a database, started with odctl up kafka-lite and odctl up postgres, and the kafka, postgres, parquet and fake extras. KAFKA_BOOTSTRAP_SERVERS sets the broker address and DEST_PATH the folder of the Parquet file (data by default), so this entry shows no output block here.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
| examples/gallery/retail_records_to_three_sinks_builder.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 | |
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.customer.payload.name, tasks.customer.payload.country and tasks.product.payload.title and 4 more. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.orders, the sequence the blueprint uses for its arrivals.
| examples/gallery/retail_records_to_three_sinks_low_level.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 185 186 187 | |
A film rental store: films, customers, rentals, payments and returns
The tables have the shape of the Sakila sample database. A store has 20 films and 15 customers at the start. About one rental starts every 8 minutes, for a week. A rental names a film and a customer that exist, is paid for at once at the film's rental rate, and is returned 1 to 7 days later.
It needs the fake extra: pip install "desflow[fake]".
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
| examples/gallery/film_rental_store_builder.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 | |
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.film.payload.title.names.adjective, tasks.film.payload.title.names.noun and tasks.film.payload.rating and 6 more. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.rentals, the sequence the blueprint uses for its arrivals.
| examples/gallery/film_rental_store_low_level.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 | |
Auction streams: people, auctions and bids
The three streams have the shape of the Nexmark benchmark, with about 1 new person for 3 new auctions and 46 bids. Each auction names a seller who exists and each bid names an auction and a bidder who exist. Ten people and five auctions exist at the start, so a bid always has something to name. The run lasts 10 minutes.
It needs the fake extra: pip install "desflow[fake]".
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.person.payload.name, tasks.person.payload.city and tasks.person.payload.state and 6 more. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.<name>, the sequence the blueprint uses for its arrivals.
| examples/gallery/auction_streams_low_level.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 | |
A table for group-by benchmarks
Each row has three keys that are text (id1 to id3, with 100, 100 and 100,000 values), three that are whole numbers (id4 to id6) and three measures (v1, v2 and v3). A group-by on a key and a sum of a measure is the usual test of a data frame library. One row a second, 1,000 rows.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as {place}.id1.names.n with the place of the task filled in. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The file waits 1 simulation second between rows, as the blueprint's constant arrival does.
Taxi rides with a pickup, a drop-off, a distance and a fare
A ride starts about every 10 seconds. Its distance is 0.5 to 20 km, its duration is 3 to 40 minutes, and the fare is 3 plus 2.2 for each km and 0.4 for each minute. The pickup is in a box about 10 km across. Each ride is one record, written at the pickup with the drop-off time that follows from the duration.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as {place}.payload.passengers with the place of the task filled in. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.rides, the sequence the blueprint uses for its arrivals.
Messages and reviews with a known intent or sentiment
Each message has an intent and each review a sentiment, drawn first by weight. The text is then written from one of the templates for that label, so the label is known for every record, and can be used to check a classifier, a retrieval system or a language model against what it should find.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
| examples/gallery/labelled_text_builder.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 | |
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.message.vars.intent, tasks.review.vars.sentiment and tasks.review.vars.product. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The gaps between arrivals come from Sampler.sample on a DistributionConfig whose stream is arrival.<name>, the sequence the blueprint uses for its arrivals.
| examples/gallery/labelled_text_low_level.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 | |
A point-in-time training set: feature records and the label that follows each
Five customers each get a feature record every day (sessions and spend over the last 30 days). Seven days after each one a label record says whether the customer left, with a high chance when the sessions were few. The label carries as_of, the time of the feature record it follows. To build the training set, join each label to the newest feature record of the same customer whose sim_ts is at or before the label's sim_ts less 7 days, so no feature that came after the start of the label's window reaches it.
Run it with the sample option, which stops after the first events and prints them:
The Builder file builds the same model with the builder API and prints every record of its run:
The Low-level file builds the model on DynamicRealtimeEnvironment, with plain Python processes, and prints every record of its run:
The Low-level file draws each value with Sampler.generator(<place>), where the place is the key path of the blueprint's generator that makes the same value, such as tasks.features.payload.sessions_30d, tasks.features.payload.spend_30d and tasks.label.payload.churned.then and 1 more. Each draw therefore comes from the random sequence the blueprint uses at the same place, so the draws are the blueprint's. The file waits one day between the feature records and seven days before each label, as the blueprint's constant arrival and wait do.