溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Kuiper中如何使用Golang模版template定制分析結(jié)果

發(fā)布時(shí)間:2022-01-06 15:54:08 來源:億速云 閱讀:149 作者:柒染 欄目:互聯(lián)網(wǎng)科技

本篇文章給大家分享的是有關(guān)Kuiper中如何使用Golang模版template定制分析結(jié)果,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

簡介

用戶通過 Kuiper 進(jìn)行數(shù)據(jù)分析處理后,使用各種 sink 可以往不同的系統(tǒng)發(fā)送數(shù)據(jù)分析結(jié)果。針對(duì)同樣的分析結(jié)果,不同的 sink 需要的格式可能未必一樣。比如,在某物聯(lián)網(wǎng)場景中,當(dāng)發(fā)現(xiàn)某設(shè)備溫度過高的時(shí)候,需要向云端某 rest 服務(wù)發(fā)送一個(gè)請(qǐng)求,同時(shí)在本地需要通過 MQTT 協(xié)議 往設(shè)備發(fā)送一個(gè)控制命令,這兩者需要的數(shù)據(jù)格式可能并不一樣,因此,需要對(duì)來自于分析的結(jié)果進(jìn)行「二次處理」后,才可以往不同的目標(biāo)發(fā)送針對(duì)數(shù)據(jù)。下面將介紹如何利用 sink 中的數(shù)據(jù)模版(data template )來實(shí)現(xiàn)對(duì)分析結(jié)果的「二次處理」。

Golang 模版介紹

Golang 模版將一段邏輯應(yīng)用到數(shù)據(jù)上,然后按照用戶指定的邏輯對(duì)數(shù)據(jù)進(jìn)行格式化輸出,Golang 模版常見的使用場景為在網(wǎng)頁開發(fā)中,比如將 Golang 中的某數(shù)據(jù)結(jié)構(gòu)進(jìn)行轉(zhuǎn)換和控制后,將其轉(zhuǎn)換為 HTML 標(biāo)簽輸出到瀏覽器。在Kuiper 使用了 Golang 的 template(模版)對(duì)分析結(jié)果實(shí)現(xiàn)「二次處理」,請(qǐng)參考以下來自于 Golang 的官方介紹。

模版是通過將其應(yīng)用到一個(gè)數(shù)據(jù)結(jié)構(gòu)上來執(zhí)行的。模版中的注釋 (Annotations) 指的是數(shù)據(jù)結(jié)構(gòu)中的元素(典型的為結(jié)構(gòu)體中的一個(gè)字段,或者 map 中的一個(gè) key),注釋用于控制執(zhí)行、并獲取用于顯示的值。模版的執(zhí)行會(huì)迭代數(shù)據(jù)結(jié)構(gòu)并設(shè)置游標(biāo),通過符號(hào)「.」 來表示,稱之為「dot」,在執(zhí)行過程中指向數(shù)據(jù)結(jié)構(gòu)中的當(dāng)前位置。

模版的輸入文本可以為 UTF-8 編碼的任意文本?!?code>動(dòng)作 (Actions)」 -- 數(shù)據(jù)求值或者控制結(jié)構(gòu) - 是通過 "{{" 和 "}}" 來界定的;所有在動(dòng)作之外的文本會(huì)被保持原樣到輸出,除了 raw strings,動(dòng)作不可跨行(注釋除外)。

動(dòng)作 (Actions)

Golang 模版提供了一些內(nèi)置的動(dòng)作,可以讓用戶寫各種控制語句,用于提取內(nèi)容。比如,

  • 根據(jù)判斷條件來輸出不同的內(nèi)容

{{if pipeline}} T1 {{else}} T0 {{end}}
  • 循環(huán)遍歷數(shù)據(jù),并進(jìn)行處理

{{range pipeline}} T1 {{else}} T0 {{end}}

讀者可以看到,動(dòng)作是用 {{}} 界定的,在 Kuiper 的數(shù)據(jù)模版使用過程中,由于輸出一般也是 JSON 格式, 而 JSON 格式是用 {} 來界定,因此讀者在不太熟悉使用的時(shí)候,在使用 Kuiper 的數(shù)據(jù)模版的功能會(huì)覺得比較難以理解。比如以下的例子中,

{{if pipeline}} {"field1": true} {{else}}  {"field1": false} {{end}}

上述表達(dá)式的意思如下(請(qǐng)注意動(dòng)作的界定符和 JSON 的界定符):

  • 如果滿足了條件 pipeline,則輸出 JSON 字符串 {"field1": true}

  • 否則輸出 JSON 字符串 {"field1": false}

Kuiper sink 數(shù)據(jù)格式

Golang 的模版可以作用于各種數(shù)據(jù)結(jié)構(gòu),比如 map、切片 (slice),通道等,而 Kuiper 的 sink 中的數(shù)據(jù)模版得到的數(shù)據(jù)類型是固定的,是一個(gè)包含了 Golang map 切片的數(shù)據(jù)類型,如下所示。

[]map[string]interface{}

切片 (slice) 數(shù)據(jù)按條發(fā)送

流入 sink 的數(shù)據(jù)是一個(gè) map[string]interface{} 切片的數(shù)據(jù)結(jié)構(gòu),但是用戶往目標(biāo) sink 發(fā)送數(shù)據(jù)的時(shí)候,可能是需要單條的數(shù)據(jù),而不是所有的數(shù)據(jù)。比如在這篇 Kuiper 與 AWS IoT Hub 集成 的文章中所介紹的,規(guī)則產(chǎn)生的樣例數(shù)據(jù)如下所示。

[
  {"device_id":"1","t_av":36.25,"t_count":4,"t_max":80,"t_min":10},
  {"device_id":"2","t_av":27,"t_count":4,"t_max":45,"t_min":12}
]

在發(fā)送到 sink 的時(shí)候,希望每條數(shù)據(jù)分開發(fā)送,首先需要將 sink 的 sendSingle 設(shè)置為 true,然后使用數(shù)據(jù)模版:{{json .}},完整配置如下,用戶可以將其拷貝到某 sink 配置的最后。

 ...
 "sendSingle": true,
 "dataTemplate": "{{json .}}"
  • sendSingle 設(shè)置為 true后,Kuiper 把傳遞給 sink 的 []map[string]interface{} 數(shù)據(jù)類型進(jìn)行遍歷處理,對(duì)于遍歷過程中的每一條數(shù)據(jù)都會(huì)應(yīng)用用戶指定的數(shù)據(jù)模版

  • json 是 Kuiper 提供的函數(shù)(用戶可以參考 Kuiper 擴(kuò)展模版函數(shù)來了解更多的 Kuiper 擴(kuò)展),可以將傳入的參數(shù)轉(zhuǎn)化為 JSON 字符串輸出,對(duì)于遍歷到的每一條數(shù)據(jù),將 map 中的內(nèi)容轉(zhuǎn)換為 JSON 字符串

Golang 還內(nèi)置提供了一些函數(shù),用戶可以參考更多 Golang 內(nèi)置提供的函數(shù)來獲取更多函數(shù)信息。

數(shù)據(jù)內(nèi)容轉(zhuǎn)換

還是針對(duì)上述例子,需要對(duì)返回的 t_av(平均溫度)做一些轉(zhuǎn)換,轉(zhuǎn)換的基本要求就是根據(jù)不同的平均溫度,加入不同的描述文字,用于目標(biāo) sink 中的處理。規(guī)則如下,

  • 當(dāng)溫度小于 30,描述字段為「Current temperature is$t_av, it's normal.」

  • 當(dāng)溫度大于 30,描述字段為「Current temperature is$t_av, it's high.」

假設(shè)目標(biāo) sink 還是需要 JSON 數(shù)據(jù),該數(shù)據(jù)模版的內(nèi)容如下,

...
"dataTemplate": "{\"device_id\": {{.device_id}}, \"description\": \"{{if lt .t_av 30.0}}Current temperature is {{.t_av}}, it's normal.\"{{else if ge .t_av 30.0}}Current temperature is {{.t_av}}, it's high.\"{{end}}}"
"sendSingle": true,

在上述的數(shù)據(jù)模版中,使用了 {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} 的內(nèi)置動(dòng)作,看上去比較復(fù)雜,稍微調(diào)整一下,去掉轉(zhuǎn)義并加入縮進(jìn)后排版如下(注意:在生成 Kuiper 規(guī)則的時(shí)候,不能傳入以下優(yōu)化后排版的規(guī)則)。

{"device_id": {{.device_id}}, "description": "
  {{if lt .t_av 30.0}}
    Current temperature is {{.t_av}}, it's normal."
  {{else if ge .t_av 30.0}}
    Current temperature is {{.t_av}}, it's high."
  {{end}}
}

使用了 Golang 內(nèi)置的二元比較函數(shù),

  • lt: 小于

  • ge:大于等于

值得注意的是,在 ltge 函數(shù)中,第二個(gè)參數(shù)值的類型應(yīng)該與 map 中的數(shù)據(jù)實(shí)際的數(shù)據(jù)類型一致,否則會(huì)出錯(cuò)。如在上述的例子中,溫度大于 30 的情況,因?yàn)?map 中實(shí)際平均數(shù)的類型為 float,因此第二個(gè)參數(shù)的值需傳入 30.0,而不是 30。

另外,模版還是應(yīng)用到切片中每條記錄上,所以還是需要將 sendSingle 屬性設(shè)置為 true。最終該數(shù)據(jù)模版針對(duì)上述數(shù)據(jù)產(chǎn)生的內(nèi)容如下,

{"device_id": 1, "description": "Current temperature is 36.25, it's high."}
{"device_id": 2, "description": "Current temperature is 27, it's normal."}

數(shù)據(jù)遍歷

通過給 sink 的 sendSingle 屬性設(shè)置為 true ,可以實(shí)現(xiàn)把傳遞給 sink 的切片數(shù)據(jù)進(jìn)行遍歷。在此處,我們將介紹一些更為復(fù)雜的例子,比如在 sink 的結(jié)果中,包含了嵌套的數(shù)組類型的數(shù)據(jù),如何通過在數(shù)據(jù)模版中提供的遍歷功能,自己來實(shí)現(xiàn)遍歷。

假設(shè)流入 sink 中的數(shù)據(jù)內(nèi)容如下所示,

{"device_id":"1", 
 "values": [
  {"temperature": 10.5},
  {"temperature": 20.3},
  {"temperature": 30.3}
 ]
}

需求為,

  • 當(dāng)發(fā)現(xiàn) "values" 數(shù)組中某個(gè) temperature 值小于等于 25 的時(shí)候,增加一個(gè)名為 description 的屬性,將其值設(shè)置為 fine。

  • 當(dāng)發(fā)現(xiàn) "values" 數(shù)組中某個(gè) temperature 值大于 25 的時(shí)候,增加一個(gè)名為 description 的屬性,將其值設(shè)置為 high。

"sendSingle": true,
"dataTemplate": "{{$len := len .values}} {{$loopsize := add $len -1}} {\"device_id\": \"{{.device_id}}\", \"description\": [{{range $index, $ele := .values}} {{if le .temperature 25.0}}\"fine\"{{else if gt .temperature 25.0}}\"high\"{{end}} {{if eq $loopsize $index}}]{{else}},{{end}}{{end}}}"

該數(shù)據(jù)模板比較復(fù)雜,解釋如下,

  • {{$len := len .values}} {{$loopsize := add $len -1}},這一段執(zhí)行了兩個(gè)表達(dá)式,第一個(gè) len 函數(shù)取得數(shù)據(jù)中 values 的長度,第二個(gè) add 將其值減 1 并賦值到變量 loopsize:由于 Golang 的表達(dá)式中目前還不支持直接將數(shù)值減 1 的操作, add 是 Kuiper 為實(shí)現(xiàn)該功能而擴(kuò)展的函數(shù)。

  • {\"device_id\": \"{{.device_id}}\", \"description\": [ 這一段模版在作用到樣例數(shù)據(jù)后,生成了 JSON 串 {"device_id": "1", "description": [

  • {{range $index, $ele := .values}} {{if le .temperature 25.0}}\"fine\"{{else if gt .temperature 25.0}}\"high\"{{end}} {{if eq $loopsize $index}}]{{else}},{{end}}{{end}} ,這一段模版看起來比較復(fù)雜,但是如果把它調(diào)整一下,去掉轉(zhuǎn)義并加入縮進(jìn)后排版如下,看起來可能會(huì)更加清晰(注意:在生成 Kuiper 規(guī)則的時(shí)候,不能傳入以下優(yōu)化后排版的規(guī)則)。

    {{range $index, $ele := .values}} 
      {{if le .temperature 25.0}}
        "fine"
      {{else if gt .temperature 25.0}}
        "high"
      {{end}} 
      {{if eq $loopsize $index}}
        ]
      {{else}}
        ,
      {{end}}
    {{end}}


    第一個(gè)條件判斷生成是 fine 或者 high;第二個(gè)條件判斷是生成分隔數(shù)組的 , 還是數(shù)組結(jié)尾的 ]。

另外,模版還是應(yīng)用到切片中每條記錄上,所以還是需要將 sendSingle 屬性設(shè)置為 true。最終該數(shù)據(jù)模版針對(duì)上述數(shù)據(jù)產(chǎn)生的內(nèi)容如下,

  {"device_id": "1", "description": [ "fine" , "fine" , "high" ]}

通過 Kuiper 提供的數(shù)據(jù)模版功能可以實(shí)現(xiàn)對(duì)分析結(jié)果的二次處理,以滿足不同的 sink 目標(biāo)的需求。但是讀者也可以看到,由于 Golang 模版本身的限制,實(shí)現(xiàn)比較復(fù)雜的數(shù)據(jù)轉(zhuǎn)換的時(shí)候會(huì)比較笨拙,希望將來 Golang 模版的功能可以做得更加強(qiáng)大和靈活,這樣可以支持處理更加復(fù)雜的需求。目前建議用戶可以通過數(shù)據(jù)模版來實(shí)現(xiàn)一些較為簡單的數(shù)據(jù)的轉(zhuǎn)換;如果用戶需要對(duì)數(shù)據(jù)進(jìn)行比較復(fù)雜的處理,并且自己擴(kuò)展了 sink 的情況下,可以在 sink 的實(shí)現(xiàn)中直接進(jìn)行處理。

另外,Kuiper 團(tuán)隊(duì)在規(guī)劃將來支持自定義擴(kuò)展 sink 中的模版函數(shù),這樣一些比較復(fù)雜的邏輯可以在函數(shù)內(nèi)部實(shí)現(xiàn),用戶調(diào)用的時(shí)候只需一個(gè)簡單的模版函數(shù)調(diào)用即可實(shí)現(xiàn)。

以上就是Kuiper中如何使用Golang模版template定制分析結(jié)果,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI