結合
このトピックの例では、結合演算を使用して、異なるストリームの値を相互に関連付ける方法を示します。結合演算では、1 つの入力ストリームの各イベントを CepStream の種類の 1 つまたは複数の入力ストリームの各イベントと比較します。両者の有効な期間が重複しており、結合条件が有効である場合は、1 つの出力イベントが生成されます。
通常どおり LINQ では、複数の入力ストリームを参照できる on … equals 句または where 句により、結合条件を 2 つの入力ストリーム間の等結合述語として指定できます。等結合述語は、where x.a equals y.a のように単一フィールドを比較することも、where {x.a, x.b} equals {y.a, y.b} または where x equals y のように複合キーを比較することもできます。
使用例
Inner Join
内部結合演算では、複数の入力ストリーム間の結合述語が true として評価される場合に、2 つ以上の入力ストリームからすべてのイベントを返します。結合述語は、結合されているイベント ストリームのペイロード フィールドを比較する式です。内部結合では、指定された他方のイベント ストリーム内に一致するイベントがないすべてのイベントが除外されます。
Equi Join
次の例では、ストリーム stream1 のイベントをストリーム stream2 のイベントと比較します。on 句で定義された等価条件に一致する、ストリーム内のイベント (2 つのイベントの期間は重複しています) が結合され、新しいイベントに出力されます。このイベントには、イベント e1 のペイロード フィールド i および j と、イベント e2 のフィールド j が含まれています。
// Assuming the following input event type for both stream1 and stream2.
public class MyPayload
{
public int i;
public float j;
}
var equiJoin = from e1 in stream1
join e2 in stream2
on e1.i equals e2.i
select new { e1.i, e1.j, e2.j };
等値述語では、プリミティブ型と複合型を比較できます。たとえば on {e1i, e1j} equals {e2i, e2j} を結合することができます。
Cross Join
クロス結合 (デカルト積) 演算では、各ストリームのイベントの間隔が重複している間、1 つ目のストリームの各イベントと 2 つ目のストリームの各イベントを組み合わせた 1 つのイベント ストリームを返します。各入力ストリームからのイベントを制限するために、where 句内でフィルター式を使用できます。2 つの入力ストリームでは、等しいかどうかをチェックする where 句のあるクロス結合は、対応する on … equals 句のある等結合と同等です。不等値述語または複数の入力ストリームにはクロス結合を使用する必要があります。
次の例では、ペイロード フィールド i の値が 3 よりも大きい stream1 のイベントが、ペイロード フィールド j の値が 10 未満の stream2 のイベントと結合されます。
var crossJoin = from e1 in stream1
from e2 in stream2
where e1.i > 3 && e2.j < 10
select new { e1.i, e2.j };
Left Anti-Semi-Join
Left Anti-Semi-Join は、各時点における通常の結合の結果が空の場合に、左側の各イベントの結合結果を作成します。この演算は、イベントがないギャップを検出する際に便利です。
var leftAntiSemiJoin = from left in stream1
where (from right in stream2
where left.v == right.v
select right).IsEmpty()
select left;
次の図は、結合条件が True と評価されていることを前提に、2 つの入力ストリーム例を使用した上記の結合結果を示します。中間の通常結合の結果も表示されています。
複数のストリームの結合
次の例のように、1 つのクエリで複数のストリームを結合できます。
var slopetest = from f in fastSignal
from s in slowSignal
from r in refSignal
select new { alarm = f.avg / s.avg < r.Threshold };