public interface TimeSeries extends Feature
A time series is a sequence of events. Each event contains a value
and has server-assigned metadata comprised of a sequence number, timestamp,
and author. Events in a time series are ordered by increasing sequence
number. Sequence numbers have values between 0
and
Long.MAX_VALUE
and are contiguous: an event with sequence number
n
will be followed by one with sequence number n + 1
. Two
events with the same sequence number will be equal – having the same
timestamp, author, and value.
A time series topic allows sessions to access a time series that is
maintained by the server. A time series topic has an associated
event data type
, such as Binary
, String
, or
JSON
, that determines the type of value associated with each event.
This feature provides a historic query API for time series topics, allowing a
session to query arbitrary sub-sequences of a time series. The
TopicControl
and Topics
features complete the API, providing
ways to create and subscribe to a time series topic.
The API presents a time series as an append-only data structure of immutable events that is only changed by adding new events.
Although a time series is append-only, an event can be overridden by appending an edit event. An edit event is a special type of event that overrides an earlier event in the time series (referred to as the original event) with a new value. When an edit event is added to a time series, the server retains both the original event and the edit event, allowing subscription and query results to reflect the edit.
For example, suppose a time series has two events with the values A
and B
, and the first event has been overridden by a later edit event
that provides a new value of X
. The server has the following
information about the time series.
Sequence | Value | Type | |
---|---|---|---|
0 | A | original event | |
1 | B | original event | |
2 | X | edit of sequence 0 |
The current value of the event with sequence number 0 is X
.
If an original event has several edit events, the latest edit event (the one with the highest sequence number) determines its current value. Each edit event refers to an original event, never to another edit event.
Extending the example by appending a further edit event to the time series:
Sequence | Value | Type | |
---|---|---|---|
3 | Y | second edit of sequence 0 |
The current value of the event with sequence number 0 is now Y
.
A time series topic retains a range of the most recent events. When a new
event is added to the time series, older events that fall outside of the
range are discarded. By default, this range includes the ten most recent
events. A different range can be configured by setting the
TIME_SERIES_RETAINED_RANGE
property.
A session can subscribe
to a time series
topic and
add a value stream
to receive updates about events appended to the time
series. Events are represented by TimeSeries.Event
instances. Each event has a
value and metadata
. An edit event has two sets of
metadata – its own metadata and that of the original event that it
replaces.
New subscribers are sent a range of events from the end of the time series. This is known as the subscription range. Configuring a subscription range is a convenient way to provide new subscribers with an appropriate subset of the latest events.
The default subscription range depends on whether the topic is configured to
publish delta streams. If delta streams are enabled, new subscribers are sent
the latest event if one exists. If delta streams are disabled, new
subscribers are sent no events. Delta streams are enabled by default and can
be disabled by setting the PUBLISH_VALUES_ONLY
property to "true".
A larger subscription range can be configured by setting the
TIME_SERIES_SUBSCRIPTION_RANGE
property. Regardless of the
TIME_SERIES_SUBSCRIPTION_RANGE
property, if delta streams are
enabled, new subscribers will be sent at least the latest event if one
exists.
If the range of events is insufficient, the subscribing session can use a
range query
to retrieve older events.
When configuring a non-default subscription range for a time series topic, register value streams before subscribing to the topic. The session only maintains a local cache of the latest value received for a topic, not the full subscription range. If a value stream is added after a session has subscribed to a matching time series topic, the new stream will only be notified of the latest value.
A session can use append
to submit a value to be added to a
time series. The server will add an event to the end of the time series based
on the supplied value, with a new sequence number, timestamp, and the author
set to the authenticated principal of the session.
Using append
allows a session
to submit a value and supplied Instant
. This provides control over
the timestamp of the event. The supplied instant must not be before the
latest event stored by the time series topic. There are no other
restrictions.
A session can use edit
to submit an edit to an original time
series event, identified by its sequence number. The server will add an edit
event to the end of the time series based on the supplied value, with a new
sequence number, timestamp, and the author set to the authenticated principal
of the session.
Time series topics can also be updated using the functionality provided by
the TopicUpdate
feature. This includes
set
,
TopicUpdate.addAndSet(java.lang.String, com.pushtechnology.diffusion.client.topics.details.TopicSpecification, java.lang.Class<T>, T)
, and UpdateStream
s. This usage performs
an append operation with the added benefits of UpdateConstraint
s,
topic creation when updating (upsert), and delta streams. When using methods
from TopicUpdate
, the sequence number, timestamp, and author metadata
will be generated using the same rules as
append(String, Class, Object)
but the associated
TimeSeries.EventMetadata
will not be returned to the caller.
A TimeSeries.Query
is a configured query that can be evaluated for a time series
topic using selectFrom(topicPath)
. Results are
provided as streams of Event
instances.
TimeSeries.RangeQuery
is a builder for configuring a Query that selects a range
of a time series. There are two types of range query that differ in how edits
are processed – value range queries and edit range queries.
A value range query returns a merged view of part of a time series. This is the most common time series query and appropriate for most applications.
The result of a value range query reflects the latest available edits and the
query result stream
is ordered by the original
event sequence number, presenting edit events instead of the original events
they replace. Original events that have no edit events are included verbatim.
Original events that have edit events are replaced by the latest edit event.
A value range query of the example time series, with no range constraints so the entire time series is selected, returns two events:
sequence=3, value=Y; original event sequence=0 sequence=1, value=B
The original value of the first event is not provided. It's apparent that the first event is an edit event because it provides the metadata of the original event it replaces.
Applications with auditing and other administrative requirements can access original event values using an edit range query. An edit range query returns an unmerged view of a time series that can include both original events and the edit events that replace them. Edit range queries are rarely needed – value range queries satisfy most use cases.
Edit range queries provide a detailed view of a time series. Because this is
potentially sensitive information, an edit range query can only be performed
by a session that has the QUERY_OBSOLETE_TIME_SERIES_EVENTS
permission for the target topic.
There are two sub-types of edit range query.
A full audit trail of edit events can be obtained using an all edits edit range query. The result contains all original events selected by the query, together with all subsequent edit events that affect the original events. The query result stream provides events in time series order. An all edits query of the example time series, with no range constraints so the entire time series is selected, returns four events:
sequence=0; value=A sequence=1; value=B sequence=2; value=X; original event sequence=0 sequence=3; value=Y; original event sequence=0
A latest edits edit range query returns a query result stream in time series order that contains all original events selected by the query, together with the latest edit events that affect the original events. A latest edits query of the example time series, with no range constraints so the entire time series is selected, returns three events:
sequence=0; value=A sequence=1; value=B sequence=3; value=Y; original event sequence=0
The initial range of events delivered for a subscription to a time series topic is derived from a latest edits edit range query. See Subscription Range.
When evaluated for a time series that has no edit events, an edit range query will return the same results as a similarly configured value range query.
The API presents a time series as an append-only data structure of immutable events that is only changed by adding new events. The API does not allow events to be deleted or edited.
There are circumstances in which events can be removed from a time series by server operations outside the API. For example, a time series topic can be configured to discard or archive older events to save storage space; or the time series may be held in memory and lost if the server restarts. Subscribed sessions are not notified when events are removed in this way, but a session can infer the removal of events that are no longer included in query results. Similarly, an event's value can be changed on the server. For example, if an administrator changes its value to redact sensitive data. Again, subscribed sessions are not notified when events are modified, but a session can infer this has happened from query results.
Whether such changes can happen for a particular time series topic depends on the topic specification, and the administrative actions that are allowed. To write a robust application, do not rely on two Event instances with the same sequence number but obtained though different API calls, being equal; nor that there are no sequence number gaps between events in query results.
The session must have the READ_TOPIC
permission for a topic to query a time series topic. The
QUERY_OBSOLETE_TIME_SERIES_EVENTS
permission is additionally required
to evaluate an edit range
query, or a
value range query
with an
edit range
.
The session must have the UPDATE_TOPIC
permission for a topic to append
a new event to a time series topic. The
EDIT_TIME_SERIES_EVENTS
permission is additionally required to
submit an edit
to any time series
topic event. The more restrictive
EDIT_OWN_TIME_SERIES_EVENTS
permission allows a session to submit edits to time series topic
events that are authored by the principal of the calling session.
Modifier and Type | Interface and Description |
---|---|
static interface |
TimeSeries.Event<V>
An event in a time series.
|
static interface |
TimeSeries.EventMetadata
Time series event metadata.
|
static class |
TimeSeries.InvalidQueryException
Exception used to report a query that is invalid for the time series.
|
static class |
TimeSeries.NoSuchEventException
Exception used to report a time series topic does not have an original
event with the sequence number provided by an
edit operation. |
static interface |
TimeSeries.Query<V>
A configured query.
|
static interface |
TimeSeries.QueryResult<V>
Query result providing a
stream of events . |
static interface |
TimeSeries.RangeQuery<V>
Builder for queries that select a range of events from a time series.
|
Modifier and Type | Method and Description |
---|---|
<V> CompletableFuture<TimeSeries.EventMetadata> |
append(String topicPath,
Class<V> valueClass,
V value)
Update a time series topic by appending a new value.
|
<V> CompletableFuture<TimeSeries.EventMetadata> |
append(String topicPath,
Class<V> valueClass,
V value,
Instant timestamp)
Update a time series topic by appending a new value with a supplied
timestamp.
|
<V> CompletableFuture<TimeSeries.EventMetadata> |
edit(String topicPath,
long originalSequence,
Class<V> valueClass,
V value)
Update a time series topic by appending a new value that overrides the
value of an existing event.
|
TimeSeries.RangeQuery<Bytes> |
rangeQuery()
Return a default range query that performs a value range query of an
entire time series.
|
getSession
<V> CompletableFuture<TimeSeries.EventMetadata> append(String topicPath, Class<V> valueClass, V value) throws IllegalArgumentException
The server will add an event to the end of the time series based on the supplied value, with a new sequence number, timestamp, and the author set to the authenticated principal of the session.
topicPath
- the path of the time series topic to updatevalueClass
- the type of the supplied value. This must match the
value type of the DataType
configured as the time series
topic's event value type
.value
- the event value
If the update was successful, the CompletableFuture will complete
successfully and provide the TimeSeries.EventMetadata
of the new
event.
Otherwise, the CompletableFuture will complete exceptionally with
a CompletionException
. Common reasons for failure, listed
by the exception reported as the
cause
, include:
NoSuchTopicException
– if there is no topic
bound to topicPath
;
IncompatibleTopicException
– if the topic bound
to topicPath
is not a time series topic;
IncompatibleTopicException
– if the
valueClass
does not match the event data type of the time
series topic bound to topicPath
;
UpdateFailedException
– if the update failed,
for example if the topic is set to
validate values
and
value
is not valid or the server generated timestamp is
before the most recent event;
PermissionsException
– if the calling
session does not have UPDATE_TOPIC
permission for
topicPath
;
SessionClosedException
– if the session is
closed.
IllegalArgumentException
- if there is no data type that supports
values of class valueClass
<V> CompletableFuture<TimeSeries.EventMetadata> append(String topicPath, Class<V> valueClass, V value, Instant timestamp) throws IllegalArgumentException
The server will add an event to the end of the time series based on the supplied value and timestamp, with a new sequence number, and the author set to the authenticated principal of the session.
topicPath
- the path of the time series topic to updatevalueClass
- the type of the supplied value. This must match the
value type of the DataType
configured as the time series
topic's event value type
.value
- the event valuetimestamp
- the supplied timestamp, must be greater or equal to that
of the most recent event appended to the topic
If the update was successful, the CompletableFuture will complete
successfully and provide the TimeSeries.EventMetadata
of the new
event.
Otherwise, the CompletableFuture will complete exceptionally with
a CompletionException
. Common reasons for failure, listed
by the exception reported as the
cause
, include:
NoSuchTopicException
– if there is no topic
bound to topicPath
;
IncompatibleTopicException
– if the topic bound
to topicPath
is not a time series topic;
IncompatibleTopicException
– if the
valueClass
does not match the event data type of the time
series topic bound to topicPath
;
UpdateFailedException
– if the update failed,
for example if the topic is set to
validate values
and
value
is not valid or the supplied instant is before the
most recent event;
PermissionsException
– if the calling
session does not have UPDATE_TOPIC
permission for
topicPath
;
SessionClosedException
– if the session is
closed.
IllegalArgumentException
- if there is no data type that supports
values of class valueClass
<V> CompletableFuture<TimeSeries.EventMetadata> edit(String topicPath, long originalSequence, Class<V> valueClass, V value) throws IllegalArgumentException
The existing event is identified by its sequence number and must be an original event.
The server will add an edit event to the end of the time series based on the supplied value, with a new sequence number, timestamp, and the author set to the authenticated principal of the session.
topicPath
- the path of the time series topic to updateoriginalSequence
- the sequence number of the original event to editvalueClass
- the type of the supplied value. This must match the
value type of the DataType
configured as the time series
topic's event value type
.value
- the event value
If the update was successful, the CompletableFuture will complete
successfully and provide the TimeSeries.EventMetadata
of the new
event.
Otherwise, the CompletableFuture will complete exceptionally with
a CompletionException
. Common reasons for failure, listed
by the exception reported as the
cause
, include:
NoSuchTopicException
– if there is no topic
bound to topicPath
;
IncompatibleTopicException
– if the topic bound
to topicPath
is not a time series topic;
IncompatibleTopicException
– if the
valueClass
does not match the event data type of the time
series topic bound to topicPath
;
TimeSeries.NoSuchEventException
– if the topic does not
have an original event with the sequence number sequence
,
perhaps because the original event has been discarded;
PermissionsException
– if the calling
session does not have the UPDATE_TOPIC
permission for
topicPath
or neither of the following is true:
EDIT_TIME_SERIES_EVENTS
permission for topicPath
;
EDIT_OWN_TIME_SERIES_EVENTS
permissions for
topicPath
and originalSequence
refers to an
event authored by the principal of the calling session.
SessionClosedException
– if the session is
closed.
IllegalArgumentException
- if there is no data type that supports
values of class valueClass
TimeSeries.RangeQuery<Bytes> rangeQuery()
Further queries with different parameters can be configured using the
TimeSeries.RangeQuery
methods.
The result provides Bytes
values, making it compatible with any
event data type supported by time series topics. A query with a more
specific value type can be configured using TimeSeries.RangeQuery.as(Class)
.
A RangeQuery equal to the one returned by this method can be created from an arbitrary RangeQuery as follows.
RangeQuery defaults = anyRangeQuery .forValues() .fromStart() .untilLast(0) .limit(Long.MAX_VALUE) .as(Bytes.class);
Copyright © 2024 DiffusionData Ltd. All Rights Reserved.