Raggruppamento e applicazione

Negli esempi inclusi in questo argomento viene illustrato come suddividere gli eventi in gruppi di eventi utilizzando la funzionalità di raggruppamento di LINQ. È possibile eseguire le aggregazioni e le altre operazioni sui gruppi di eventi, in modo che ciascun gruppo venga calcolato separatamente. Il set di operazioni applicato a ogni gruppo è denominato ramo di applicazione. È possibile specificare in modo implicito il ramo di applicazione all'interno di una singola istruzione di raggruppamento e applicazione oppure, se è contenuta una sottoquery più complessa, come istruzione LINQ separata. Si noti che i rami di applicazione sono chiusi all'interno del costrutto di raggruppamento e applicazione; ad esempio, non è possibile creare un join del flusso raggruppato con un flusso esterno al raggruppamento.

Esempi

Nell'esempio seguente gli eventi vengono raggruppati in base alla funzione modulo specificata. Viene quindi applicata una finestra snapshot a ciascun gruppo e viene calcolata la media su una colonna del payload per ciascun gruppo separatamente. Il ramo di applicazione, pertanto, è costituito dalla finestra e dall'aggregazione.

// Assuming the following input event type for inputStream:
public class MyPayload 
{
    public int i; 
    public float j; 
}

var avgCount = from v in inputStream
               group v by v.i % 4 into eachGroup
               from window in eachGroup.SnapshotWindow(SnapshotWindowOutputPolicy.Clip)
               select new { avgNumber = window.Avg(e => e.j) };

Nell'esempio precedente è stato generato un flusso con un singolo campo payload contenente la media del campo j all'interno di ogni finestra snapshot e per ogni gruppo.

È inoltre possibile raggruppare una proiezione del tipo originale in un clausola 'group by', come mostrato nell'esempio seguente.

var result = from e in source.AlterEventDuration(e => TimeSpan.FromMinutes(10))
                  group new { myVal = e.Value * 10 } by e.SourceId into g
                  from win in g.SnapshotWindow(SnapshotWindowOutputPolicy.Clip)
                  select new
                  {
                      avg = win.Avg(e => e.myVal)
                   };

In genere, è necessario mantenere la chiave di raggruppamento in modo che il risultato dell'aggregazione possa essere associato al rispettivo gruppo. Nell'esempio successivo viene mostrato come recuperare la chiave di raggruppamento.

var avgCount = from v in inputStream
               group v by v.i % 4 into eachGroup
               from window in eachGroup.SnapshotWindow(SnapshotWindowOutputPolicy.Clip)
               select new { avgNumber = window.Avg(e => e.number), groupId = eachGroup.Key };

È possibile raggruppare diverse chiavi, in modo che ogni combinazione di chiave univoca nel flusso di input risultasse un gruppo separato. In questo caso, le chiavi di raggruppamento devono essere contenute in una definizione di tipo anonima in modo che sia possibile recuperarle in modo esplicito nella proiezione finale. Notare che è necessario fare riferimento a tutti i campi di raggruppamento. Nell'esempio seguente gli eventi vengono raggruppati in base a due campi payload dell'evento e viene assegnato un nuovo nome della chiave a uno di loro.

// Assuming the following input event type for inputStream:
public class MyPayload 
{
    public int section; 
    public string category; 
    public float value; 
}

var avgCount = from v in inputStream
               group v by new { sec = v.section, v.category } into eachGroup
               from window in eachGroup.SnapshotWindow(SnapshotWindowOutputPolicy.Clip)
               select new { avgNumber = window.Avg(e => e.value), section = eachGroup.Key.sec, category = eachGroup.Key.category };

Il ramo di applicazione può essere più complesso contenendo una serie di operazioni, come mostrato nell'esempio seguente.

// Assuming the following input event type for inputStream:
public class MyPayload 
{
    public int section; 
    public string category; 
    public float value; 
}

var result = from s in source
                group s by s.section into sg
                from e in
                    (from e in sg
                    group e by e.category into cg
                    from win in cg.TumblingWindow(TimeSpan.FromMinutes(5), HoppingWindowOutputPolicy.ClipToWindowEnd)
                    select new { cat = cg.Key, top = win.Max(e => e.value) })
                select new { sec = sg.Key, e.cat, e.top };

Nell'esempio seguente viene preso in considerazione un flusso di letture del misuratore di alimentazione contenente i dati di diversi misuratori. Nell'esempio viene annotata ogni lettura con la media degli ultimi 10 minuti per lo stesso misuratore. La query consente innanzitutto di raggruppare i dati in ingresso in base all'ID del misuratore. In ognuno di questi gruppi, viene calcolata la media dei 10 minuti, di cui successivamente viene creato un join con gli eventi del misuratore originale.

// Assuming the following input event type for sensorStream:
public class MeterReading
{
    public string meterId; 
    public float usage; 
}

var resultB = from s in sensorStream
              group s by s.meterId into g
              from e in
                  (from left in g
                  from right in
                      (from win in g
                          .AlterEventDuration(e => TimeSpan.FromMinutes(10))
                          .SnapshotWindow(SnapshotWindowOutputPolicy.Clip)
                      select new { avg = win.Avg(e => e.usage) })
                  select new { right.avg, left.usage })
              select new { slidingAvg = e.avg, e.usage, g.Key };

Come indicato in precedenza, nella funzione che rappresenta il ramo di applicazione non può essere integrato nessun altro flusso di ingresso eccetto applyIn.

Vedere anche

Concetti

Concetti relativi al server StreamInsight

Utilizzo delle finestre di eventi

Finestre snapshot