# PromQLを使ってデータをクエリする

EMQX TablesはSQLに加えてPrometheus Query Language（PromQL）をサポートしており、馴染みのあるPrometheusのセマンティクスを使って時系列データをクエリできます。

EMQX TablesはGreptimeDB上に構築されており、ネイティブなPromQL実装を提供しています。これにより、クエリをSQLに変換することなく、EMQX Tablesに格納されたメトリクス形式のデータを直接PromQLで解析できます。

EMQX Cloudの**Data Explorer**では、同じ基盤データに対して**SQL**モードと**PromQL**モードを切り替えてクエリを実行できます。

## PromQLを使うタイミング

PromQLは以下のような場合に特に有用です。

- すでにPrometheusやPromQLに慣れている場合
- レートや増分、ローリング集計など時系列指向の計算を行いたい場合
- IoTデバイス、メッセージフロー、システム監視などで生成されたメトリクス形式のデータをクエリする場合

## クエリの時間範囲とステップ

EMQX Tablesの**Data Explorer**でPromQLを使う際、クエリの時間範囲と解像度はUIで制御されます。

- **時間範囲**：クエリの開始時刻と終了時刻を定義します
- **ステップ**：クエリの解像度を定義します（例：`30s`）

これらのパラメータはPrometheusのレンジクエリ評価と同様に、自動的にPromQLクエリに適用されます。

## EMQX Tablesにおけるデータモデルのマッピング

EMQX TablesはGreptimeDBから継承した時系列テーブルモデルを使用しています。PromQLでデータをクエリする際、このモデルはPromQLの概念に以下のようにマッピングされます。

| PromQLの概念 | EMQX Tablesの概念   |
| ------------ | ------------------- |
| Metric       | テーブル            |
| Label        | タグカラム          |
| Sample value | フィールドカラム    |
| Timestamp    | 時刻インデックスカラム |

このモデルでは、1つのテーブルに複数のフィールドカラムを含めることができます。各フィールドは独立したPromQLの値ストリームとして公開され、同じメトリック名、ラベル、タイムスタンプを共有します。

これは、従来のPrometheusデータモデル（1つのメトリックに1つの値のみを含む）とは異なります。

## 特定フィールドのクエリ

デフォルトでは、PromQLクエリはテーブル内のすべての数値フィールドに対して実行されます。特定のフィールドをクエリするには、特殊なラベルマッチャー `__field__` を使用します。

### 単一フィールドのクエリ

```
mqtt_messages{__field__="count"}
```

### フィールドの除外

```
mqtt_messages{__field__!="count"}
```

### 正規表現で複数フィールドにマッチ

```
mqtt_messages{__field__=~"count|bytes"}
```

### 正規表現で複数フィールドを除外

```
mqtt_messages{__field__!~"error_.*"}
```

この拡張はEMQX Tables（GreptimeDB経由）固有のもので、標準のPromQLには含まれていません。

## クロスデータベースクエリ

EMQX Tablesは特殊なラベルマッチャー `__database__` を使って複数データベースにまたがるクエリをサポートします。

```
mqtt_messages{__database__="production"}
```

注意点：

- 等価マッチャー（`=`）のみサポートされています。
- これは標準PromQLの拡張機能です。

## サポートされるデータ型と制限

EMQX TablesのPromQLクエリは現在、以下のデータ型で動作します。

- **Timestamp**：`Timestamp`
- **Label（タグ）**：`String`
- **Value（フィールド）**：`Double`

マイクロ秒やナノ秒単位の高精度タイムスタンプは保存可能ですが、PromQLの計算はPromQL仕様に従いミリ秒精度で行われます。

## PromQL機能のサポート状況

EMQX TablesはPromQL機能の90%以上をサポートしており、一般的なクエリや集計シナリオのほとんどをカバーしています。

### リテラル

- 文字列リテラルと浮動小数点リテラルをサポートします。
- 挙動は標準PromQL仕様に準拠します。

### セレクター

- インスタントセレクターとレンジセレクターをサポートします。
- 時間の長さ指定や `offset` 修飾子をサポートします。
- `@` 修飾子は現在サポートしていません。

注意：

- メトリック名に対する否定マッチ（例：`{__name__!="metric"}`）はPrometheusと同様に許可されていません。
- 存在しないカラムを選択してもエラーにならず、空の値（`""`）として扱われます。
- 存在しないメトリック名を選択するとエラーになります。

### 二項演算子

EMQX Tablesは標準PromQLのすべての二項演算子をサポートしています。以下の表はGreptimeDB内部の演算子と対応するPromQL構文のマッピングです。

| 演算子    | PromQL構文 | 例                                      |
| --------- | ---------- | --------------------------------------- |
| `add`     | `+`        | `mqtt_bytes_in + mqtt_bytes_out`        |
| `sub`     | `-`        | `mqtt_bytes_in - mqtt_bytes_out`        |
| `mul`     | `*`        | `mqtt_msg_rate * 100`                   |
| `div`     | `/`        | `mqtt_bytes_in / mqtt_connections`      |
| `mod`     | `%`        | `mqtt_packets % 10`                     |
| `power`   | `^`        | `mqtt_latency ^ 2`                      |
| `eqlc`    | `==`       | `mqtt_status == 1`                      |
| `neq`     | `!=`       | `mqtt_status != 0`                      |
| `gtr`     | `>`        | `mqtt_latency > 100`                    |
| `lss`     | `<`        | `mqtt_latency < 50`                     |
| `gte`     | `>=`       | `mqtt_connections >= 1000`              |
| `lte`     | `<=`       | `mqtt_connections <= 100`               |
| `and`     | `and`      | `mqtt_connections and mqtt_sessions`    |
| `or`      | `or`       | `mqtt_errors or mqtt_timeouts`          |
| `unless`  | `unless`   | `mqtt_connections unless mqtt_sessions` |
| `atan2`   | `atan2()`  | `atan2(y_metric, x_metric)`             |

### 集約演算子

サポートされている集約演算子の例は以下の通りです。

| 集約関数       | 例                                         |
| -------------- | ------------------------------------------- |
| `sum`          | `sum by (clientid)(mqtt_messages)`          |
| `avg`          | `avg by (topic)(mqtt_latency)`               |
| `min`          | `min by (node)(cpu_usage)`                   |
| `max`          | `max by (node)(cpu_usage)`                   |
| `count`        | `count(mqtt_connections)`                    |
| `count_values` | `count_values("version", build_info)`        |
| `topk`         | `topk(5, rate(mqtt_messages[5m]))`           |
| `bottomk`      | `bottomk(5, rate(mqtt_messages[5m]))`        |
| `quantile`     | `quantile(0.95, mqtt_latency)`                |
| `stddev`       | `stddev(mqtt_latency)`                        |
| `stdvar`       | `stdvar(mqtt_latency)`                        |

### インスタント関数

EMQX Tablesはインスタントベクトルに対して動作し、インスタント結果を返す多くのPromQLインスタント関数をサポートしています。主なものは以下の通りです。

- 数学関数：`abs`、`ceil`、`floor`、`sqrt`、`exp`、`ln`
- 三角関数：`sin`、`cos`、`tan`およびその派生関数
- ユーティリティ関数：`timestamp`、`scalar`、`sort`、`sort_desc`
- ヒストグラム：`histogram_quantile`
- 予測：`predict_linear`
- クエリユーティリティ：`absent`

以下の表はサポートされている関数とPromQL式の例です。

| 関数名               | 例                                               |
| -------------------- | ------------------------------------------------ |
| `abs`                | `abs(mqtt_latency)`                               |
| `ceil`               | `ceil(cpu_usage)`                                 |
| `floor`              | `floor(cpu_usage)`                                |
| `sqrt`               | `sqrt(sensor_value)`                              |
| `exp`                | `exp(metric)`                                     |
| `ln`                 | `ln(metric)`                                      |
| `log2`               | `log2(metric)`                                    |
| `log10`              | `log10(metric)`                                   |
| `acos`               | `acos(metric)`                                    |
| `asin`               | `asin(metric)`                                    |
| `atan`               | `atan(metric)`                                    |
| `sin`                | `sin(metric)`                                     |
| `cos`                | `cos(metric)`                                     |
| `tan`                | `tan(metric)`                                     |
| `acosh`              | `acosh(metric)`                                   |
| `asinh`              | `asinh(metric)`                                   |
| `atanh`              | `atanh(metric)`                                   |
| `sinh`               | `sinh(metric)`                                    |
| `cosh`               | `cosh(metric)`                                    |
| `tanh`               | `tanh(metric)`                                    |
| `sgn`                | `sgn(metric)`                                     |
| `scalar`             | `scalar(metric)`                                  |
| `timestamp`          | `timestamp(mqtt_messages)`                        |
| `sort`               | `sort(http_requests_total)`                       |
| `sort_desc`          | `sort_desc(http_requests_total)`                  |
| `histogram_quantile` | `histogram_quantile(0.95, mqtt_latency_bucket)`  |
| `predict_linear`     | `predict_linear(cpu_usage[5m], 120)`              |
| `absent`             | `absent(nonexistent{job="myjob"})`                |
| `pi`                 | `pi()`                                            |
| `deg`                | `deg(metric)`                                     |
| `rad`                | `rad(metric)`                                     |
| `clamp`              | `clamp(metric, 0, 100)`                           |
| `clamp_min`          | `clamp_min(metric, 0)`                            |
| `clamp_max`          | `clamp_max(metric, 100)`                          |

> 注意：
> - `v` はインスタントベクトルを表します。
> - `predict_linear` のような関数はレンジベクトルを入力として必要とします。
> - すべての関数は標準PromQLのセマンティクスに準拠しています。

### レンジ関数

以下の一般的なレンジ関数がサポートされています。

| 関数名               | 例                              |
| -------------------- | -------------------------------- |
| `idelta`             | `idelta(metric[5m])`             |
| `deriv`              | `deriv(metric[5m])`              |
| `stdvar_over_time`   | `stdvar_over_time(metric[5m])`  |
| `reset`              | `reset(metric[5m])`              |
| `rate`               | `rate(mqtt_messages[5m])`        |
| `irate`              | `irate(mqtt_messages[1m])`       |
| `increase`           | `increase(mqtt_messages[10m])`   |
| `delta`              | `delta(sensor_value[5m])`        |
| `changes`            | `changes(connection_state[5m])`  |
| `<aggr>_over_time`   | `avg_over_time(cpu_usage[5m])`   |
| `stddev_over_time`   | `stddev_over_time(latency[5m])`  |

### ラベル操作関数

以下のラベル処理関数が完全にサポートされています。

| 関数名               | 例                                                                 |
| -------------------- | ------------------------------------------------------------------ |
| `label_join`         | `label_join(mqtt_metrics{src1="a",src2="b"}, "dst", ",", "src1", "src2")` |
| `label_replace`      | `label_replace(mqtt_metrics{job="api-server"}, "service", "$1", "job", "(.*)-server")` |
| `sort_by_label`      | `sort_by_label(mqtt_metrics{node="node1"}, "node")`                 |
| `sort_by_label_desc` | `sort_by_label_desc(mqtt_metrics{node="node1"}, "node")`            |
