MAP
MAP 関数は、データを必要な形式に加工するための基本的な関数です。
TAKE()

構文: TAKE( [offset,] n )
ストリームの先頭から n 件のレコードを取得し、処理を終了します。
offsetnumber: 省略可能。指定した位置からレコードを取得します。デフォルトは 0 です。 Since v8.0.6nnumber: 取得するレコード数。
| |
TAG0,1628694000000000000,10
TAG0,1628780400000000000,11DROP()

構文: DROP( [offset,] n )
先頭の n 件のレコードをスキップして除去します。
offsetnumber: 省略可能。指定した位置からレコードを除去します。デフォルトは 0 です。 Since v8.0.6nnumber: 除去するレコード数。
| |
TAG0,1628953200000000000,13
TAG0,1629039600000000000,14
TAG0,1629126000000000000,15FILTER()

構文: FILTER( condition )
入力レコードに条件式を適用し、condition が真の場合だけ次のステップに渡します。
たとえば、入力レコードが {key: k1, value[v1, v2]} の場合、FILTER(count(V) > 2) はこのレコードを除去します。FILTER(count(V) >= 2) なら、次の関数に渡します。
| |
TAG0,1628694000000000000,10
TAG0,1628780400000000000,11FILTER_CHANGED()
構文: FILTER_CHANGED( value [, retain(time, duration)] [, useFirstWithLast()] )
Since v8.0.15
retain(time, duration)useFirstWithLast(boolean)
前のレコードと比較して value が変化した場合だけレコードを通過させます。
最初のレコードは常に渡されます。必要に応じて FILTER_CHANGED() の後に DROP(1) を追加して除去してください。
retain() オプションを指定すると、time を基準に、指定期間にわたって変更後の value を維持したレコードが渡されます。
| |
A,1692329338,1
B,1692329340,3
C,1692329346,9
D,1692329347,9.1SET()
構文: SET(name, expression)
Since v8.0.12
namekeyword: 変数名。expressionexpression: 変数に代入する値。
SET は、レコードのスコープで使用する変数を定義します。たとえば SET(var, 10) で宣言した変数は、以降 $var で参照できます。変数は値配列に含まれないため、最終的な SINK の結果には出力されません。
| |
0,1
0.5,6
1,11GROUP()
構文: GROUP( [lazy(boolean),] by [, aggregators...] )
Since v8.0.7
lazy(boolean): デフォルトのfalseでは、by()の値が前のレコードと異なると直ちに集計結果を出力します。trueでは入力ストリームが終了するまでデータを蓄積し、結果をまとめて返します。by(value [, label]): グループ化の基準となる値。aggregatorsarray of aggregator: 使用する集計関数のリスト。
集計関数の詳細は GROUP() を参照してください。
PUSHVALUE()

構文: PUSHVALUE( idx, value [, name] )
Since v8.0.5
idxnumber: 新しい値の挿入位置(0 始まり)。valueexpression: 挿入する値。namestring: 列名。デフォルトは'column'です。
現在の値配列に新しい列を挿入します。
| |
0.0,0
0.5,5
1.0,10POPVALUE()

構文: POPVALUE( idx [, idx2, idx3, ...] )
Since v8.0.5
idxnumber: 除去する列のインデックスのリスト。
指定したインデックスの列を値配列から除去します。
| |
0
5
10MAPVALUE()

構文: MAPVALUE( idx, newValue [, newName] )
idxnumber: 値タプル内のインデックス(0 始まり)。newValueexpression: 置換後の値。newNamestring: 新しい列名。
MAPVALUE() は、指定したインデックスの値を別の値に置き換えます。たとえば MAPVALUE(0, value(0)*10) は、最初の値を 10 倍した値に置き換えます。
idx が範囲外の場合は PUSHVALUE() と同様に新しい列を追加します。たとえば MAPVALUE(-1, value(1)+'_suffix') は、2 番目の値に _suffix を連結した文字列の列を追加します。
| |
0
5
10次の例では MAPVALUE で数値演算を適用します。
| |

MAP_DIFF()
構文: MAP_DIFF( idx, value [, newName] )
Since v8.0.8
idxnumber: 値タプル内のインデックス(0 始まり)。valuenumber: 計算の基準となる値。newNamestring: 新しい列名。
MAP_DIFF() は、指定した位置の値を現在値と前回値の差(current - previous)に置き換えます。
| |
VALUE,DIFF
-0.693,NULL
-0.251,0.442
0.054,0.305
0.288,0.234
0.477,0.189
0.636,0.159
0.773,0.137
0.894,0.121
1.001,0.108
1.099,0.097MAP_ABSDIFF()
構文: MAP_ABSDIFF( idx, value [, label] )
Since v8.0.8
idxnumber 値タプル内のインデックス(0 始まり)。valuenumberlabelstring 指定した文字列を新しい列名にします。
MAP_ABSDIFF() は、値を現在値と前回値の差の絶対値 abs(current - previous) に置き換えます。
MAP_NONEGDIFF()
構文: MAP_NONEGDIFF( idx, value [, label] )
Since v8.0.8
idxnumber 値タプル内のインデックス(0 始まり)。valuenumberlabelstring 指定した文字列を新しい列名にします。
MAP_NONEGDIFF() は、値を現在値と前回値の差(current - previous)に置き換えます。差が 0 未満の場合は 0 を返します。
MAP_AVG()
構文: MAP_AVG(idx, value [, label] )
Since v8.0.15
idxnumber 値タプル内のインデックス(0 始まり)。valuenumberlabelstring 指定した文字列を新しい列名にします。
MAP_AVG は、指定した位置の値を平均フィルターの計算結果に置き換えます。
データ数を $k$ とすると、
$\alpha = \frac{1}{k}$ とします。
$\overline{x_k} = (1 - \alpha) \overline{x_{k-1}} + \alpha x_k$
| |

MAP_MOVAVG()
構文: MAP_MOVAVG(idx, value, window [, label] )
Since v8.0.8
idxnumber 値タプル内のインデックス(0 始まり)。valuenumberwindownumber 蓄積するレコード数。labelstring 指定した文字列を新しい列名にします。
MAP_MOVAVG は、指定した位置の値をウィンドウサイズに応じた移動平均に置き換えます。
値の数がウィンドウサイズに達していない場合は、利用可能な値の合計をその個数で割ります。
直近の window 区間の入力がすべて NULL(または数値以外)の場合、結果も NULL になります。
一部の値だけが NULL の場合は、NULL を除外して平均を計算します。
| |
- 5 行目: ノイズを含む信号値を生成します。
- 6 行目: ウィンドウサイズ 10 の移動平均を計算します。

MAP_LOWPASS()
構文: MAP_LOWPASS(idx, value, alpha [, label] )
Since v8.0.15
idxnumber: 値タプル内のインデックス(0 始まり)。valuenumberalphanumber: 0 < alpha < 1 の範囲の係数。labelstring: 新しい列名。
MAP_LOWPASS は、指定した位置の値を指数加重移動平均(EWMA)に置き換えます。
$ 0 < \alpha < 1$ のとき、
$\overline{x_k} = (1 - \alpha) \overline{x_{k-1}} + \alpha x_k$
| |
- 5 行目: ノイズを含む信号を生成します。
- 6 行目:
alpha = 0.40のローパスフィルターを適用します。

MAP_KALMAN()
構文: MAP_KALMAN(idx, value, model() [, label])
Since v8.0.15
idxnumber: 値タプル内のインデックス(0 始まり)。valuenumbermodelmodel(initial, progress, observation): システム行列を指定します。labelstring: 新しい列名。
| |
- 4 行目: 真値は定数
14.4です。 - 5 行目: 単純なノイズを生成します。
- 6 行目: 真値とノイズを加算して測定値を生成します。
- 10 行目: 測定値にカルマンフィルターを適用します。

HISTOGRAM()
HISTOGRAM() には 2 つの動作方式があります。入力値の範囲が固定または予測可能な場合は固定ビンを、値の範囲が不明な場合は動的ビンを使用します。
固定ビン
構文: HISTOGRAM(value, bins [, category] [, order] )
Since v8.0.15
valuenumberbinsbins(min, max, step): ヒストグラムのビン設定。categorycategory(name_value): 分類列。orderorder(name…string): カテゴリーの順序。
HISTOGRAM() は、指定したビンごとに値の分布を集計します。ビンは最小値、最大値、ビン幅(step)で設定します。値が範囲外の場合は、下限側または上限側のビンが自動的に追加されます。
| |
low,high,count
0,40,2
40,80,31
80,120,47
120,160,16
160,200,4動的ビン
構文: HISTOGRAM(value [, bins(maxBins)] )
Since v8.0.46
valuenumberbinsnumber: 作成するビンの最大数。デフォルトは 100 です。
HISTOGRAM() は、値とビンの最大数を受け取り、入力範囲に合わせてビンを動的に調整します。value 列は各ビンの平均値、count 列はそのビンに属する値の個数を表します。
したがって、value × count はそのビンに属する値の合計と等しくなります。
| |
value,count
47,12
75,29
99,29
119,18
156,12BOXPLOT()
構文: BOXPLOT(value, category [, order] [, boxplotInterp] [, boxplotOutput])
Since v8.0.15
valuenumbercategorycategory(name_value): グループの識別子。orderorder(name…string): カテゴリーの順序。boxplotOutputboxplotOutput( "" | “chart” | “dict” ): 出力形式。boxplotInterpboxplotInterp(Q1 boolean, Q2 boolean, Q3 boolean): 四分位数の補間オプション。- 詳細な例は Michelson & Morley Experiment と Iris Sepal Length を参照してください。
TRANSPOSE()
構文: TRANSPOSE( [fixed(columnIdx...) | columnIdx...] [, header(boolean)] )
Since v8.0.8
CSV やブリッジを使用して外部 RDBMS から読み込んだデータを Machbase TAG テーブルの構造に合わせるには、列を行に変換する必要がある場合があります。TRANSPOSE は、複数の列を持つレコードを複数の行に変換します。
fixed(columnIdx...): 変換せずに保持する列を指定します。変換対象の列指定とは併用できません。columnIdx...: 変換する列のリストを指定します。fixed()とは併用できません。header(boolean):header(true)では最初のレコードをヘッダーとみなし、変換後のレコードにヘッダー値を新しい列として追加します。
| |
代表的な使用例を示します。
- 5 行目: 2、3、4 番目の列をヘッダーとともに変換します。
- 6 行目: 都市名と変換した列名を連結します。
- 7 行目: 文字列を時刻に変換します。
- 8 行目: 値の文字列を数値に変換します。
- 9 行目: 不要になった変換元の列名を除去します。
TOKYO-TEMPERATURE,1701907200,23
TOKYO-HUMIDITY,1701907200,30
TOKYO-NOISE,1701907200,40
BEIJING-TEMPERATURE,1701907200,24
BEIJING-HUMIDITY,1701907200,50
BEIJING-NOISE,1701907200,60FFT()

構文: FFT([minHz(value), maxHz(value)])
minHz(value): 解析に使用する最小周波数。maxHz(value): 解析に使用する最大周波数。
入力レコードの値を (time, amplitude) タプルの配列とみなし、高速フーリエ変換(FFT)を適用します。
変換後はキーを保持したまま、値を (frequency, amplitude) タプルの配列に置き換えます。
たとえば入力が {key: k, value[[t1,a1],[t2,a2],..., [tn,an]]} の場合、結果は {key: k, value[[F1,A1],[F2,A2],..., [Fm,Am]]} になります。
| |

3D 可視化の例を含む詳細は FFT() を参照してください。
WHEN()
構文: WHEN(condition, doer)
Since v8.0.7
conditionbooleandoerdoer
WHEN は、条件が真の場合に指定した doer の処理を実行します。
レコードの流れには影響せず、定義された副作用の処理だけを実行します。
doLog()
構文: doLog(args...)
Since v8.0.7
Web コンソールにログメッセージを出力します。
| |
doHttp()
構文: doHttp(method, url, body [, header...])
Since v8.0.7
methodstringurlstringbodystringheaderstring: 省略可能なヘッダー。
doHttp は、指定したメソッド、URL、本文、ヘッダーで HTTP リクエストを送信します。
使用例
- 指定した HTTP エンドポイントにイベントを通知します。
| |
- 現在のレコードを CSV(デフォルト形式)で送信します。
| |
- 現在のレコードをカスタム JSON 形式で送信します。
| |
do()
構文: do(args..., { sub-flow-code })
Since v8.0.7
do は、受け取った引数 args... を使用してサブフローのコードを実行します。
WHEN() は、条件に応じて副作用を実行するための機能です。
そのため、WHEN 内のサブフローでは、CSV、JSON、CHART_* など、出力ストリームに結果を書き込む SINK は使用できません。呼び出しても出力は無視され、警告メッセージが表示されます。
サブフローでは、出力ストリームに依存しない INSERT と APPEND が有効な SINK です。これらを使用すると、メインの TQL フローとは別のテーブルに値を書き込めます。処理が不要な場合は DISCARD() を使用して、警告なしでレコードを破棄できます。
| |
上記のログから、次の 2 点を確認できます。
- メインフローは、サブフローの処理が完了するまで待機します。
- 条件に一致するレコードごとにサブフローが実行されます。
2023-12-02 07:54:42.160 TRACE 0xc000bfa580 Task compiled FAKE() → WHEN() → CSV()
2023-12-02 07:54:42.160 TRACE 0xc000bfa840 Task compiled ARGS() → WHEN() → DISCARD()
2023-12-02 07:54:42.160 INFO 0xc000bfa840 Greetings: 你好 idx: 2
2023-12-02 07:54:42.160 DEBUG 0xc000bfa840 Task elapsed 254.583µs
2023-12-02 07:54:42.161 TRACE 0xc000bfa9a0 Task compiled ARGS() → WHEN() → DISCARD()
2023-12-02 07:54:42.161 INFO 0xc000bfa9a0 Greetings: 世界 idx: 4
2023-12-02 07:54:42.161 DEBUG 0xc000bfa9a0 Task elapsed 190.552µs
2023-12-02 07:54:42.161 DEBUG 0xc000bfa580 Task elapsed 1.102681ms使用例
サブフローが引数以外のデータを取得する場合は、args([idx]) オプション関数で渡された引数を再参照できます。
- サブフローの引数を使用してクエリーを実行します。
// 疑似コード
// ...
WHEN( condition,
do(value(0), {
SQL(`select time, value from table where name = ?`, args(0))
// ... MAP 関数による処理 ...
INSERT(...)
})
)
// ...
- 外部 Web サーバーから CSV ファイルを取得します。
// 疑似コード
// ...
WHEN( condition,
do(value(0), value(1), {
CSV( file( strSprintf("https://exmaple.com/data_%s.csv?id=%s", args(0), escapeParam(args(1)) )))
WHEN(true, doHttp("POST", "http://my_server", value()))
DISCARD()
})
)
// ...
FLATTEN()

構文: FLATTEN()
GROUPBYKEY() の逆の処理を行います。多次元タプルを持つレコードを要素ごとに分解し、次元を減らした複数のレコードを生成します。
たとえば入力が {key:k, value:[[v1,v2],[v3,v4],...,[vx,vy]]} の場合、結果は {key:k, value:[v1, v2]}、{key:k, value:[v3, v4]}、…、{key:k, value:[vx, vy]} になります。
MAPKEY()

構文: MAPKEY( newkey )
現在のキーを、指定した新しいキーに置き換えます。
| |
1701343504143299000,TAG0,1628694000000000000,10
1701343504143303000,TAG0,1628780400000000000,11
1701343504143308000,TAG0,1628866800000000000,12
1701343504143365000,TAG0,1628953200000000000,13
1701343504143379000,TAG0,1629039600000000000,14
1701343504143383000,TAG0,1629126000000000000,15PUSHKEY()

構文: PUSHKEY( newkey )
すべてのレコードのキーを指定値に変更し、元のキーを値タプルの先頭に挿入します。
たとえば {key: 'k1', value: [v1, v2]} に PUSHKEY(newkey) を適用すると、{key: newkey, values: [k1, v1, v2]} に変換されます。
| |
1701343504143299000,TAG0,1628694000000000000,10
1701343504143303000,TAG0,1628780400000000000,11
1701343504143308000,TAG0,1628866800000000000,12
1701343504143365000,TAG0,1628953200000000000,13
1701343504143379000,TAG0,1629039600000000000,14
1701343504143383000,TAG0,1629126000000000000,15POPKEY()

構文: POPKEY( [idx] )
現在のキーを除去し、値タプルの idx 番目の要素を新しいキーにします。
たとえば {key: k, value: [v1, v2, v3]} に POPKEY(1) を適用すると、{key: v2, value:[v1, v3]} になります。
引数を省略すると POPKEY(0) と同じ動作になり、最初の値をキーにします。
| |
1628694000000000000,10
1628780400000000000,11
1628866800000000000,12
1628953200000000000,13
1629039600000000000,14
1629126000000000000,15GROUPBYKEY()

構文: GROUPBYKEY( [lazy(boolean)] )
lazy(boolean): デフォルトのfalseでは、キーが前のレコードと異なると直ちにグループ化したレコードを返します。trueでは入力ストリームが終了するまで待機します。
GROUPBYKEY は GROUP( by( key() ) ) と同じ動作をします。
THROTTLE()
構文: THROTTLE(tps)
Since v8.0.8
tpsnumber: 1 秒あたりに渡すレコード数。
THROTTLE は、指定した tps に合わせてレコードの転送速度を抑えます。
保存済みのデータ(CSV など)を一定周期で流し、センサーデバイスをシミュレートする場合に便利です。
| |
- コンソールログの
"tick"メッセージは、約 200ms 間隔(毎秒 5 件)で出力されます。
2023-12-07 09:33:30.131 TRACE 0x14000f88b00 Task compiled FAKE() → THROTTLE() → WHEN() → CSV()
2023-12-07 09:33:30.332 INFO 0x14000f88b00 ===>tick 1
2023-12-07 09:33:30.533 INFO 0x14000f88b00 ===>tick 2
2023-12-07 09:33:30.734 INFO 0x14000f88b00 ===>tick 3
2023-12-07 09:33:30.935 INFO 0x14000f88b00 ===>tick 4
2023-12-07 09:33:31.136 INFO 0x14000f88b00 ===>tick 5
2023-12-07 09:33:31.136 DEBUG 0x14000f88b00
Task elapsed 1.005070167sSCRIPT()
カスタムスクリプト言語をサポートします。
詳細な例は SCRIPT を参照してください。

