Events
Record and query operational events.
externalId is a correlation key, not an identityThis is the opposite of what it means on a resource, and it is deliberate. An event's
external id is the source system's key for the subject the event is about — an order, a
permit, a batch — so many events share one. "Everything that happened to PO-4500171"
is one indexed lookup, and that is what makes the log an audit trail.
No uniqueness is enforced, and none ever will be. Per-event identity is the event id
below. Naming policies do not apply to events either; only the
charset floor does, so 21-PT-1234 is accepted on an
event even when a snake_case policy is rejecting it on resources.
The two contracts →
Create
Every event must carry an event time — the moment it occurred at the source (sensor, PLC, upstream system). The SDK deliberately does not default it to "now": an event without it is rejected rather than silently mis-timestamped.
- Java
- Python
- Rust
EventModel event = new EventModel();
event.setExternalId("door_open");
event.setType("alarm");
event.setEventTime(ZonedDateTime.now()); // required: when the event occurred
client.events().create(List.of(event));
from datetime import datetime, timezone
import datahub_sdk
event = datahub_sdk.Event(
external_id="door_open",
type="alarm",
event_time=datetime.now(timezone.utc)) # required: when the event occurred
client.events.create([event])
use chrono::Utc;
use dataplatform_rust_sdk::events::Event;
let mut event = Event::new("door_open".into());
event.r#type = Some("alarm".into());
event.set_event_time(Utc::now()); // required: when the event occurred
api.events.create(&vec![event]).await?;
The ingestion paths stamp every event that has no id with a UUID v7 before sending —
create in the Python and Rust clients, ingest(...) in Java (a plain Java create sends
events as-is and lets the server assign ids). The server honors a client-supplied id, which is
what makes retries idempotent: the events table is a ReplacingMergeTree ordered by id, so
re-sending the same event (for example after a
buffered outage) collapses to one row instead of
duplicating. If you set the id yourself, use a time-ordered UUID v7 — a random v4 scatters
writes across that sort key and hurts insert/query performance. The created event (with its
id) is returned from create.
Query
- Java
- Python
- Rust
EventRetreiver retriever = new EventRetreiver();
retriever.setLimit(50);
retriever.getFilter().setType("alarm");
DataWrapper<EventModel> events = client.events().filter(retriever);
filter = datahub_sdk.EventFilter(
basic_filter=datahub_sdk.BasicEventFilter(type="alarm"),
limit=50)
events = client.events.filter(filter)
use dataplatform_rust_sdk::filters::{BasicEventFilter, EventFilter};
let filter = EventFilter::default()
.set_filter(BasicEventFilter { r#type: Some("alarm".into()), ..Default::default() })
.set_limit(50)
.build();
let events = api.events.filter(&filter).await?;
High-throughput ingestion
- Java
- Python
- Rust
ingest chunks, parallelises and retries events the same way as datapoints, returning
the same IngestResult tuned with the same
IngestOptions:
IngestResult result = client.events().ingest(events,
IngestOptions.builder().batchSize(1_000).parallelism(8).build());
create accepts a whole batch:
client.events.create(events) # list[Event]
create accepts a whole batch:
api.events.create(&events).await?; // Vec<Event>
Delete
- Java
- Python
- Rust
client.events().delete(List.of(IdCollection.createFromExternalId("door_open")));
client.events.delete(["door_open"])
api.events.delete(&vec![IdAndExtId::from_external_id("door_open")]).await?;