Rule Engine 規則引擎
以 SQL(SELECT/FROM/WHERE)描述資料流:把 topic 或 EMQX 事件當成資料來源,挑出欄位、加上條件、套用內建函數,寫出第一條規則並用「Try It Out」驗證。
為什麼要學這個
Mosquitto 把每個主題的訊息原封不動轉給訂閱者,你永遠拿不到「挑過、改過的資料」。想在智慧家庭裡把感測器讀數過濾掉雜訊、轉成另一個主題、或當某個 client 掉線時即時發通知——你要的是 Broker 能自己處理資料的能力。
EMQX 的 Rule Engine(規則引擎)就是這項能力:用類似 SQL 的語法描述「資料從哪來、要怎麼挑、最後做什麼」,把 Broker 從純轉發器升級成資料管線的中樞。讀完這章,你會寫得出自己的第一條規則,並且知道怎麼用內建的測試工具驗證它。
核心概念
規則引擎的核心是「來源 → 加工 → 動作」三段式:
- 資料來源(data source):規則從哪裡取得資料。可以是 MQTT 訊息(一個或多個 topic)、MQTT 事件(
$events/…),或由 Data Integration 送回的資料。 - 資料加工(transformation):用規則 SQL 決定挑哪幾筆、挑哪幾個欄位、加什麼條件與函數。SQL 的
FROM指定來源,WHERE加條件,SELECT決定輸出。 - 動作(action):規則命中後要做什麼。EMQX 5.8.9 提供 republish(轉發)、console(印到主控台或 log)與 Forwarding to Sinks(送到外部系統)。
規則寫在哪一層?EMQX 5.x 把它歸在 Data Integration(資料整合)區域,Dashboard 側欄選 Integration → Rules 就能建立或編輯規則。規則引擎不只處理訊息,也能處理 client 上線/離線這類事件(event)。
名詞對照
| 英文 | 中文 | 一句話 |
|---|---|---|
| Rule Engine | 規則引擎 | 以 SQL 描述資料流處理能力的引擎 |
| Data Source | 資料來源 | 規則要讀取的 topic/事件/外部資料 |
| SELECT / FROM / WHERE | 選取/來源/條件 | SQL 的三段主要子句 |
| Action | 動作 | 規則命中後執行的輸出行為 |
| MQTT Event | MQTT 事件 | 上線、下線、訂閱這類連動事件,主題以 $events/ 開頭 |
| Data Integration | 資料整合 | EMQX 5.x 把規則、來源、連接器與輸出整合在一起的區塊 |
動手做
以 EMQX 官方教學的 t/#a/1 轉發規則為例,練習是最快的。
開啟規則頁面
在 EMQX Dashboard 左側點 Integration → Rules,按右上 Create 進入「Create Rule」。
填規則資訊並寫 SQL
填規則名稱與備註,在 SQL Editor 輸入
SELECT * FROM "t/#",讓規則選取所有 topic 符合t/#的訊息。用 Try It Out 測試 SQL
開啟 Create Rule 頁的 Try It Out 開關,選對應的 Data Source,填入模擬資料(Client ID、Username、Topic、QoS、Payload 等),按 Run Test,應出現
Test Passed,右側 Output Result 會顯示 SQL 輸出。加上動作
按右側 Add Action,選 Republish,設目標 topic、QoS、Payload(
${payload}),按 Add 後回 Create Rule 頁。建立並觸發
回到 Create Rule 頁,按底部 Create 完成。訂閱
a/1,再用t/1主題發布一則訊息,應能收到轉發後的a/1。
規則 SQL:SELECT/FROM/WHERE
規則 SQL 的基本格式是:
SELECT <欄位與運算式> FROM <資料來源> [WHERE <條件>]
FROM 指定資料來源,有兩種主要樣態:
- topic:例如
SELECT * FROM "t/#",處理 topic 符合t/#的所有訊息;多個 topic 用逗號分隔,如FROM "t/1", "t/2"。topic 必須用雙引號或單引號括起。 - 事件(event):例如
SELECT clientid FROM "$events/client_connected" WHERE clientid = 'c1',處理 client 成功連線的事件。事件主題以$events/開頭,無法用一般訂閱方式直接讀取。
WHERE 給出額外過濾條件。欄位可以是 metadata(如 clientid、username)或 payload 內欄位(用點號語法如 payload.x.y,前提是 payload 是 JSON/Map);也能用 and/or 組成複合條件。
SELECT 挑選輸出的欄位,還可重新命名:
SELECT clientid, payload.clientid as myclientid FROM "t/#"
輸出會是 JSON 物件。SQL 執行完的欄位,後續動作可以用 ${欄位名} 引用。
運算式支援算術(+/-/*/div/mod)、比較(=、<>、<、>…)與邏輯(and/or),還有大量內建函數。另一種 FOREACH 語句可一次輸出多個結果(例如把 payload 的感測器陣列拆成一則一則訊息),進階用到再學習即可。
資料欄位與內建函數
規則能引用的欄位依資料來源而異。處理 MQTT 訊息時,metadata 提供下列常見欄位:
| 欄位 | 說明 |
|---|---|
topic | 來源 topic |
qos | 訊息 QoS 等級 |
clientid | 發布者 client ID |
username | 發布者 username |
payload | 訊息內容(JSON 時可用點號取內欄) |
peerhost | 發布者 IP |
timestamp | 事件觸發時間(毫秒) |
事件來源(如 $events/client_connected)則額外提供 clientid、username、keepalive、is_bridge、connected_at 等欄位;$events/client_disconnected 還有 reason 說明斷線原因。官方文件有完整事件清單與欄位對照。
內建函數(built-in functions)可以在 SELECT/WHERE 內使用,常見分類:
- 數學:
abs、floor、ceil、round、power、sqrt… - 型別:
is_array、is_bool、is_null… - 字串:
upper、lower、tokens、concat… - 其他:
now_timestamp、now_rfc3339、uuid_v4、日期轉換、mapping/array 操作、以及高階jq程序。
SELECT upper(clientid) as cid FROM "t/#"
如果 payload 不是 JSON,想用點號語法就得先轉型或改用函數;官方也提供 Schema Registry 教學處理非 JSON 格式。
故障排除
- 規則沒被觸發:檢查
FROM的 topic pattern 是否與發布主題相符(萬用字元、大小寫),規則是否已啟用,事件名是否拼錯(例如$events/client_connected)。 - SQL 輸出空白/欄位錯誤:查一下官方欄位對照,確認欄位名是否存在於該資料來源;metadata 與 payload 是兩層不同的欄位。
- payload 不是 JSON 卻想取內欄:點號語法只適用 JSON/Map;非 JSON 要用轉型函數或先經 Schema 處理。
- 規則命中了但動作沒執行:用 Try It Out 的「Test the Rule」模擬對應事件或 publish,或直接發布測試訊息,再檢視該次執行記錄的 Action 錯誤。
常見問題
規則與動作的差別在哪
規則由 SQL(資料來源+加工)與動作(輸出行為)組成。SQL 決定「處理哪些資料、怎麼挑」,動作決定「處理完要發布到哪/印到哪/送給誰」。
能直接訂閱 $events/… 事件主題嗎
一般 client 無法直接訂閱 MQTT 事件主題;事件主題是給規則的 FROM 使用的(例如 $events/client_connected)。若想從外面收到事件資料,可用規則轉發,或訂閱 EMQX 的 system topics。
SQL 在 FROM 用 # 大範圍會怎樣
可以,但會讓所有送到 EMQX 的訊息都進規則比對,效能成本較高。官方建議盡量用較收斂的 topic pattern,而非一開頭就 #。
「Data Integration」和舊版 4.x 用的名詞差在哪
EMQX 5.x 以 Data Integration(Rules/Connectors/Actions/Sources/Sinks)與 Extensions 為主;命名與 4.x 舊版的 Modules/Data Bridge 不同。看到舊版文件用 4.x 名詞時,記得那是 legacy 位置。