Condividi tramite


Modifiche dei timestamp

Negli esempi presenti in questo argomento verrà illustrato l'utilizzo degli operatori per modificare il timestamp di un evento. Effettuando tale operazione, è possibile modificare l'effetto degli eventi su operazioni successive come join, aggregazioni su finestre e così via. I metodi di estensione LINQ seguenti sono basati su questa funzionalità.

Variazione dell'ora di un evento

L'operatore ShiftEventTime() consente di modificare l'ora di inizio di ogni evento nel flusso in base all'espressione specificata.

Nell'esempio seguente l'ora di ogni evento viene spostata in avanti nel flusso di 15 minuti.

// shift events by 15 minutes into the future.
var shifted = inputStream.ShiftEventTime(e => TimeSpan.FromMinutes(15)); 

Nell'esempio seguente l'ora di ogni evento viene spostata indietro nel flusso di 1 ora.

// shift events by 1 hour into the past.
var shifted = inputStream.ShiftEventTime(e => TimeSpan.FromHours(-1));

L'espressione per specificare lo spostamento dell'ora può fare riferimento all'ora di inizio dell'evento corrente, ma non all'ora di fine o al payload. Lo spostamento non influisce sulla durata o sul payload dell'evento.

Si considera che il valore DateTime.MinValue codifichi un valore di ora meno infinito. Se l'ora di inizio dell'evento è associata a tale valore e costituisce il riferimento nell'espressione specificata, contrariamente a una costante, l'espressione non viene valutata e l'ora di inizio resta DateTime.MinValue. In caso contrario, l'espressione verrà valutata in fase di esecuzione e può comunque restituire un'eccezione di overflow.

Si noti che lo spostamento dell'ora specificato viene applicato anche a eventi CTI che passano tramite questo operatore perché ShiftEventTime influisce sulle ore di inizio di tutti gli eventi nel flusso.

Modifica della durata di un evento

L'operatore AlterEventDuration() modifica la durata dell'evento. La durata dell'evento specifica l'intervallo di tempo durante il quale l'evento è valido. La durata viene definita come funzione nell'evento, in modo che sia possibile calcolarla dall'ora di inizio, dall'ora di fine o dal payload dell'evento.

Nell'esempio seguente la durata dell'evento viene impostata su 1 ora.

// set event duration to 1 hour.
var onehour = inputStream.AlterEventDuration(e => TimeSpan.FromHours(1));

Nell'esempio seguente la durata dell'evento viene impostata su un valore pari a due volte la durata corrente.

// double event duration. 
var doubled = inputStream.AlterEventDuration(e => (e.EndTime - e.StartTime) * 2);

Si considera che il valore DateTime.MaxValue codifichi un valore di ora più infinito. Se l'ora di inizio dell'evento è associata a tale valore e costituisce il riferimento nell'espressione specificata, l'espressione non viene valutata e l'ora di fine resta DateTime.MaxValue.

Modifica dello spostamento e della durata di un evento

L'operatore AlterEventLifetime() combina le funzioni AlterEventDuration e ShiftEventTime per offrire la massima espressività.

Il primo parametro del metodo AlterEventLifeTime() specifica il nuovo timestamp di inizio e può fare riferimento all'ora di inizio dell'evento corrente. Questo parametro deve essere specificato come ora UTC. Il secondo parametro specifica la nuova durata e può fare riferimento all'ora di inizio o di fine e ai campi payload dell'evento corrente.

Nell'esempio seguente l'ora dell'evento vene spostata indietro di 1 minuto mentre l'ora di fine dell'evento viene lasciata invariata (aggiungendo un minuto alla durata originale) specificando la nuova durata come secondo parametro.

// shift event 1 minute into the past, but leave the end time (event duration) unchanged.
var newStream = inputStream.AlterEventLifetime(e => e.StartTime - TimeSpan.FromMinutes(1),
                                               e => e.EndTime - e.StartTime + TimeSpan.FromMinutes(1));]

Si noti che lo spostamento dell'ora di inizio specificato viene applicato anche a eventi CTI che passano tramite questo operatore.

Vedere anche i commenti precedenti relativi a DateTime.MinValue e DateTime.MaxValue in questo argomento.

Conversione di un flusso in un flusso di eventi punto

L'operatore ToPointEventStream è una pratica funzione che consente di convertire eventi Edge e intervallo in eventi punto, modificando le durate degli eventi in un singolo tick successivo all'ora di inizio dell'evento, come illustrato nell'esempio seguente.

var pointStream = inputStream.ToPointEventStream();

Solo l'ora di inizio degli eventi viene mantenuta quando gli eventi intervallo vengono convertiti in eventi punto.

Riduzione della durata di un evento

L'operatore ClipEventDuration accetta due flussi come parametri e modifica la durata di ogni evento nel primo flusso in base all'ora di inizio dell'evento corrispondente successivo nel secondo flusso.

Finora, sono stati analizzati operatori che consentono di modificare la durata di un evento in base a un intervallo di tempo fisso. L'operatore ClipEventDuration fornisce un metodo molto flessibile per regolare la durata degli eventi rispetto ad altri eventi. In generale, questo operatore viene specificato in un flusso e accetta un altro flusso come parametro, insieme a una condizione corrispondente. L'operatore ridurrà la durata di ogni evento nel primo flusso in base all'ora di inizio dell'evento "successivo" (in termini di tempo di applicazione) nell'altro flusso che soddisfa la condizione corrispondente.

Ad esempio, si suppongano due flussi, stream1 e stream2, contenenti eventi con un campo payload "ID". Nell'istruzione seguente tutti gli eventi in stream1 vengono ridotti all'evento successivo in stream2 che dispone dello stesso valore per "ID":

var clipped = stream1.ClipEventDuration(stream2, (e1, e2) => e1.Id == e2.Id);

La condizione corrispondente viene fornita come espressione su entrambi i payload di input. La semantica di questa istruzione viene illustrata nel diagramma seguente:

Semantica di ClipEventDuration

Nel diagramma viene mostrato il modo in cui il primo evento in stream1 con ID = A viene ridotto all'evento successivo con ID = A nello stream2. L'altro evento in stream1, dove ID = B, non viene ridotto, poiché l'evento corrispondente successivo in stream2 si verifica solo dopo la fine dell'evento in stream1.

Questo comportamento di riduzione consente un'ampia gamma di applicazioni. Un requisito comune che può essere soddisfatto è la conversione di un flusso di punti in un flusso di intervalli continui, anche denominato "segnale".

Conversione da punti a segnale

In questo caso, è necessario innanzitutto estendere tutti gli eventi punto, in modo che raggiungano effettivamente l'evento successivo. In altre parole, è necessario applicare un timeout che determina la durata prevista di un evento fino al verificarsi dell'evento successivo. Questo timeout può essere un intervallo di tempo finito o infinito. Si supponga un timeout di 60 secondi:

var extended = input.AlterEventDuration(e => TimeSpan.FromSeconds(60));

Con questa preparazione, è possibile utilizzare l'operatore ClipEventDuration, fornendo il flusso stesso come relativo parametro. In questo modo ogni evento viene ridotto al successivo nello stesso flusso, creando una serie continua di eventi intervallo. Poiché solo le ore di inizio del secondo flusso sono coinvolte nell'operazione di riduzione, è possibile utilizzare anche il flusso del punto originale:

var signal = extended.ClipEventDuration(input, (e1, e2) => true);

In questo caso, la condizione corrispondente restituisce sempre true, presupponendo che si analizzi un solo flusso logico, ovvero che tutti gli eventi nel flusso siano associati a una sola origine dati.

Nei diagrammi seguenti viene illustrato l'effetto della conversione da punti a segnale tramite l'operatore ClipEventDuration:

Conversione da punti a segnale con ClipEventDuration

Entrambe le istruzioni LINQ possono essere combinate in un'unica istruzione:

var signal = input.AlterEventDuration(e => TimeSpan.FromSeconds(60)).ClipEventDuration(input, (e1, e2) => true);

Se il flusso contiene più flussi logici, ad esempio misurazioni di più dispositivi o valori di più azioni, la rispettiva chiave (ID del dispositivo o codice azionario) deve trovare corrispondenza nell'espressione booleana:

var signal = input.AlterEventDuration(e => TimeSpan.FromSeconds(60)).ClipEventDuration(input, (e1, e2) => e1.Symbol == e2.Symbol);

Creazione di sessioni

Un altro caso di utilizzo di ClipEventDuration è la creazione di eventi di sessione per annotare eventi che si sono verificati durante tale sessione. Si supponga il seguente schema di eventi in cui vengono descritti gli eventi di alcune interazioni dell'utente:

public class EventType
{
    public int UserId;
    public string Type;
    public DateTime Time;
    public byte[] data;
};

In questo esempio, il campo payload Type può essere "inizio", "fine" o "altro", descrivendo, rispettivamente, l'inizio di una sessione utente, la fine di una sessione o eventi dell'utente durante una sessione. Nel campo Time è contenuto il timestamp dell'interazione, mentre in data sono presenti ulteriori informazioni. L'attività consiste nell'annotare ogni evento con l'ora di inizio della sessione durante la quale si è verificato l'evento. Inoltre, si supponga che ogni sessione scada dopo 10 minuti.

Nel diagramma seguente viene mostrata una serie di eventi di esempio di questo scenario:

Creazione di eventi di sessione con ClipEventDuration

Innanzitutto, l'espansione della durata in base al timeout viene applicata a tutti gli eventi di tipo "inizio":

var sessionStarts = from e in input
                    where e.Type == “start”
                    select e;
var sessionStartsExt = sessionStarts.AlterEventDuration(e => TimeSpan.FromMinutes(10));

Successivamente, questi eventi di sessione devono essere ridotti fino alla rispettiva fine, per ogni ID utente:

var sessionEnds = from e in input
                  where e.Type == “end”
                  select e;
var sessions = sessionStartsExt.ClipEventDuration(sessionEnds, (e1, e2) => e1.UserId == e2.UserId);

Nel diagramma vengono illustrate queste istruzioni:

Riduzione degli eventi di sessione con ClipEventDuration

A questo punto gli eventi di sessione possono essere uniti in join agli eventi rimanenti:

var sessionActivity = from e in input
                      where e.Type == “other”
                      select e;
var annotated = from s1 in sessions
                join s2 in sessionActivity
                on s1.UserId equals s2.UserId
                select new {
                    s2.UserId,
                    s2.Type,
                    s2.Time,
                    s2.Data,
                    SessionStart = s1.Time
                }

Nel join è possibile fare riferimento agli eventi sessionActivity nonché ai campi dell'evento di sessione, in modo da poter assemblare l'evento sessionActivity annotato, eseguendo il pull dell'ora di inizio della sessione nell'evento sessionActivity:

Creazione di un join degli eventi di sessione ad altri eventi

Poiché la condizione di join è l'uguaglianza di UserId, l'evento con UserId=Y in sessionActivity non viene preso in considerazione per questa sessione specifica dove UserId=X.

Le istruzioni LINQ possono essere compresse in un set più conciso:

var sessions = input
                 .Where(e => e.Type == “start”)
                 .AlterEventDuration(e => TimeSpan.FromMinutes(10))
                 .ClipEventDuration(input.Where(e => e.Type == “end”), (e1, e2) => e1.UserId == e2.UserId);
var annotated = from s1 in sessions
                join s2 in input.Where(e => e.Type == “other”)
                on s1.UserId equals s2.UserId
                select new {
                    s2.UserId,
                    s2.Type,
                    s2.Time,
                    s2.Data,
                    SessionStart = s1.Time
                }

Vedere anche

Concetti

Concetti relativi al server StreamInsight