- All Implemented Interfaces:
AutoCloseable
EventListener. A Detector is stateful, single-use and not thread-safe: use one per
data stream.-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionvoidadvanceTo(long timestamp) Tells this Detector that time has passed up totimestampwithout new Samples.static Detector.Builderbuilder()voidclose()Ends running Events as truncated and makes this Detector reject further Samples.Runs a whole recorded series through this unused Detector and closes it.detectValues(Iterable<Map<Channel, Double>> series) Likedetect(java.lang.Iterable<io.github.romanhaendler.rbed.Sample>), for a regularly sampled series without timestamps.longThe number of entries dropped because a window was full (seeDetector.Builder.retentionLimit) since this Detector was built.How far back this Detector's configuration makes it look: the longest time window and the largest Sample count used by its Rules and watched Expressions, computed when it was built.voidProcesses one Sample.voidProcesses one Sample of a regularly sampled series; its timestamp is derived from the sampling rate asround(index * 1000 / hz).The earliest timestamp from which replaying this Detector's input into a fresh Detector (same Rules and options), with the Events that Ended before that timestamp supplied asHistory, reproduces this Detector exactly: the replay then continues with the same Events, callbacks, values and exceptions as this Detector.longThe number of entries this Detector currently holds: one per Channel a Rule or watched Expression uses, one per value in each moving-average window and one per timestamp kept forcount(...).within(...)(timestamps older than the window are dropped at every moment).byte[]snapshot()Returns this Detector's complete state at the latest moment processed, as a byte array thatDetector.Builder.restoreturns back into a Detector.value(Expression expression) The value of a watched Expression at the latest moment processed (Sample or time advance), also afterclose().
-
Method Details
-
snapshot
public byte[] snapshot()Returns this Detector's complete state at the latest moment processed, as a byte array thatDetector.Builder.restoreturns back into a Detector.The guarantee: a Detector restored from a Snapshot is indistinguishable from the one the Snapshot was taken from. For every input that follows, the callbacks (kind, order and the complete Event, every Aggregate bit for bit), the values read through
value(io.github.romanhaendler.rbed.Expression),retainedValues(),droppedValues(), the warnings logged and the exceptions thrown are identical. The Snapshot also works afterclose()(it restores a closed Detector), and before the first Sample. It does not contain the listener; the restored Detector reports to the Builder's listener. Taking a Snapshot does not change this Detector. Its size is bounded by the Retention Limit.The array starts with a magic header and a format version, followed by a fingerprint of the Rules and options;
Detector.Builder.build()rejects a Snapshot that does not match.- Throws:
IllegalStateException- if called from within anEventListenercallback, where a moment is only half processed
-
value
The value of a watched Expression at the latest moment processed (Sample or time advance), also afterclose(). Empty while the value is undefined, for example a Channel before its first value, a moving average during its warm-up, a Pulse Channel absent in that moment orlatest(...)before the first such Event. Expressions about Events are defined from the start: before the first Sample,count(...)andtotalDuration(...)are 0, or what the History gives. Reading only looks the value up.From an EventListener callback, it reads the moment being processed. Rules are evaluated in the order they were added, so for a Rule added later than the Rule whose callback runs,
count,totalDurationandlatestshow its Events as of the previous moment: an Event of it Confirmed or Ended in this moment is not reflected yet, nor is this moment in its Aggregates; a running Event's duration counts up to this moment.- Throws:
IllegalArgumentException- if the Expression was not registered withDetector.Builder.watch(io.github.romanhaendler.rbed.Expression...); a Channel matches by name, every other Expression by identityNullPointerException- ifexpressionis null
-
memoryHorizon
How far back this Detector's configuration makes it look: the longest time window and the largest Sample count used by its Rules and watched Expressions, computed when it was built. This is a configuration bound, not a guarantee. An Event in progress, a Rule waiting for itswhenCondition to stop holding, andlatest(...)can depend on Samples further back; the Replay Point is the exact answer to how far back a replay must start. -
replayPoint
The earliest timestamp from which replaying this Detector's input into a fresh Detector (same Rules and options), with the Events that Ended before that timestamp supplied asHistory, reproduces this Detector exactly: the replay then continues with the same Events, callbacks, values and exceptions as this Detector. Empty before the first Sample, and with a sampling rate (a fresh Detector cannot continue the Sample index). Read it after each moment, store it with the stream position, and the stream has to be kept back to the oldest Replay Point still needed.Replay all moments (Samples, time advances, and
close()if it was called) with a timestamp from the Replay Point on, in order, with the listener's side effects suppressed up to the position where the replay catches up with this Detector. The History is every Event that Ended before the Replay Point, including those supplied to this Detector as History; Events that Ended later are produced again by the replay.The Replay Point reaches back to what the state of this Detector depends on, value by value: the Events in progress, including the End Condition's duration; a Rule that has not seen its
whenCondition stop holding since its last Event ended on an End Condition, so a fresh Rule would start another Event; the momentwhenwas last seen false, which decides whether the next Event is Truncated at its start; the oldest Sample in each moving-average window; the latest and previous values read byrate(),age(),rising(),falling()and the previous Sample behindmaxGap; the Channel values the Rules read; and the start of the latest Event of every Rule whose Aggregates are read throughlatest(...). It is not inside the span of an Event that another Rule reads or that ended on an End Condition, so such an Event is never split. On a steady input it keeps up with the stop, within what the constructs in use need. Reading it takes time proportional to the number of Channels, moving averages, Rules and finished runs kept, not to the history, and allocates only the result.Preconditions: the replay gets the same input, Rules and options, and its listener's side effects are suppressed up to the stop; the Detector has not dropped entries because of the Retention Limit (
droppedValues()is 0), which would make windows depend on the dropped entries; anddroppedValues(), a count since the Detector was built, and the warning logged with the first drop are not reproduced by a replay. A moving average depends only on the values in its window, so a replay reproduces it bit for bit. -
retainedValues
public long retainedValues()The number of entries this Detector currently holds: one per Channel a Rule or watched Expression uses, one per value in each moving-average window and one per timestamp kept forcount(...).within(...)(timestamps older than the window are dropped at every moment). A plain counter read, cheap to poll between pushes. -
droppedValues
public long droppedValues()The number of entries dropped because a window was full (seeDetector.Builder.retentionLimit) since this Detector was built. Entries that left a window by time are not counted. -
builder
-
push
Processes one Sample.- Parameters:
timestamp- milliseconds; must be strictly greater than the previous Sample's and than the end of every History Eventvalues- values of any subset of Channels; must be finite- Throws:
IllegalStateException- if a sampling rate was configured, or afterclose()
-
push
Processes one Sample of a regularly sampled series; its timestamp is derived from the sampling rate asround(index * 1000 / hz).- Throws:
IllegalStateException- if no sampling rate was configured, or afterclose()
-
detect
Runs a whole recorded series through this unused Detector and closes it. The listener is still called.- Returns:
- all Ended Events in the order they Ended
-
detectValues
Likedetect(java.lang.Iterable<io.github.romanhaendler.rbed.Sample>), for a regularly sampled series without timestamps. -
close
public void close()Ends running Events as truncated and makes this Detector reject further Samples.- Specified by:
closein interfaceAutoCloseable
-
advanceTo
public void advanceTo(long timestamp) Tells this Detector that time has passed up totimestampwithout new Samples. Rules are evaluated at that moment with every Channel holding its value (Pulse Channels are absent): durations can be reached, max gaps noticed, andage()grows. An advance is not a Sample, so it does not count forforSamplesor Sample-based Aggregates.- Parameters:
timestamp- milliseconds; must be strictly greater than the previous Sample or advance- Throws:
IllegalStateException- if a sampling rate was configured, or afterclose()
-