Hey Luke, here’s my take on it:
1. Data Contracts for Functional vs. Informative
- We use data contracts (like our _historian contract) to handle raw functional data, and then derive “informative” streams (e.g., _analytics or _OEE) from that.
- That means you can have a _historian stream with the raw values, and then you create derived streams when needed—but we don’t strictly separate them because sometimes you’ll subscribe to an informative stream to do further aggregation.
2. OEE Calculation
- Calculating OEE in real-time through a message broker is actually an anti-pattern. OEE is best processed as a batch because it needs to handle timeline corrections (e.g., if a shift is later classified as non-existent due to an operator’s absence).
- In short, OEE should be computed in batch mode and stored (or re-computed) in a database like Timescale rather than relying on the broker.
3. Metadata Handling
- For metadata, we recommend including a dedicated metadata field (an object with key/value pairs) in each _historian message. Later, when ingesting into Timescale, we de-duplicate this data to ensure a consistent reference set.
4. Last Order Data
- As for last order, if you use a data contract like _analytics/orders/add, you can always look back in time via Kafka. This means the last order info is available as part of the stream, but for permanent storage and queries, you’d rely on Timescale.
5. No Single Source of Truth (Tech-wise)
- There’s no one component that’s “the single source of truth” (i.e., it’s not just the broker or just the database). The UMH architecture combines multiple technologies: a broker for streaming and a persistent store (like Timescale) for historical data and reference info.
Hope that clears it up!