etl nifi ExecuteScript 一些 Groovy,Jython,Javascript(Nashorn)和JRuby 語言手法

目錄

介紹

 幾個重要的玩意

 獲取文件前提條件

獲取流file小李子

從回話中獲取多個流文件然後弄它

小李子

用create()搞一個新的FlowFile發送到下一個處理器

小李子

從基於傳入的FlowFile生成新的FlowFile

栗子

想要添加自定義屬性的流文件,爲流文件添加一個屬性

FlowFile對象介紹

小李子

想要添加自定義屬性的流文件,將多個屬性添加到流文件

Map介紹

示例

從流文件中獲取屬性

栗子

從流文件獲取所有屬性 all

栗子:

將流文件轉移到關係  (“成功”或“失敗”)

重點

栗子

設置自己的日誌和日誌級別弄起來

栗子



介紹

           ExecuteScript 的 Groovy,Jython,Javascript(Nashorn)和JRuby 寫法, ExecuteScript優勢可言靈活的寫出內容,在運行中使用腳本。

 

 幾個重要的玩意

  • session(會話):這是對分配給處理器的ProcessSession的引用。會話允許您對流文件(如create()putAttribute()transfer()以及read()write()()進行操作。
  • context(上下文):這是對處理器的ProcessContext的引用。它可以用來檢索處理器屬性,關係,Controller服務和StateManager。
  • log:這是對處理器ComponentLog的引用。用它來記錄消息給NiFi,比如log.info('Hello world!')
  • REL_SUCCESS:這是對處理器定義的“成功”關係的引用。它也可以通過引用父類(ExecuteScript)的靜態成員來繼承,但是一些引擎(如Lua)不允許引用靜態成員,所以這是一個方便的變量。這也節省了必須使用關係的完全合格的名稱。
  • REL_FAILURE:這是對處理器定義的“失敗”關係的引用。和REL_SUCCESS一樣,它也可以通過引用父類(ExecuteScript)的靜態成員來繼承,但是一些引擎(如Lua)不允許引用靜態成員,所以這是一個方便的變量。這也節省了必須使用關係的完全合格的名稱。
  • Dynamic Properties : 在ExecuteScript中定義的任何動態屬性都將作爲設置爲與動態屬性對應的PropertyValue對象的變量傳遞給腳本引擎。這允許您獲取屬性的String值,還可以針對NiFi表達式語言評估該屬性,將該值作爲適當的數據類型(例如布爾值)等進行轉換。由於動態屬性名稱會成爲腳本的變量名稱,您必須知道所選腳本引擎的變量命名屬性。例如,Groovy不允許在變量名稱中使用句點(。),因此如果“my.property”是一個動態屬性名稱,則會發生錯誤。

 獲取文件前提條件

  •  從會話中獲取傳入的流文件
  • 在ExecuteScript 的前一個節點要有個流文件 FlowFile  ,大部分處理器都ok
  • 用 session.get() 就可以獲取


獲取流file小李子

  • Groovy

flowFile = session.get()
if(!flowFile) return
  • jython
flowFile = session.get() 
if (flowFile != None):
    # All processing code starts at this indent
# implicit return at the end
  • Javascript
var flowFile = session.get();
if (flowFile != null) {
   // All processing code goes here
}
  • JRuby
flowFile = session.get()
if flowFile != nil
   # All processing code goes here
end

從回話中獲取多個流文件然後弄它

  • 使用會話對象中的get(maxResults)此方法返回到來自工作隊列的maxResults FlowFiles
  • 如果沒有FlowFiles可用,則返回一個空列表(該方法不返回null)
  • 如果存在多個傳入隊列,則根據一次調用是否輪詢所有隊列或僅調用一個隊列,行爲是未指定的。

小李子

  • Groovy
flowFileList = session.get(100)
if(!flowFileList.isEmpty()) {
   flowFileList.each { flowFile -> 
       // Process each FlowFile here
   }
}
  • Jython
flowFileList = session.get(100)
if not flowFileList.isEmpty():
    for flowFile in flowFileList: 
         # Process each FlowFile here
  • Javascript
flowFileList = session.get(100)
if(!flowFileList.isEmpty()) {
  for each (var flowFile in flowFileList) { 
       // Process each FlowFile here
  }
}
  • JRuby
flowFileList = session.get(100)
if !(flowFileList.isEmpty())
   flowFileList.each { |flowFile| 
       # Process each FlowFile here
   }
end

用create()搞一個新的FlowFile發送到下一個處理器

 

  • 使用會話對象的create()方法。
  • 此方法返回一個新的FlowFile對象,
  • 在上執行進一步的處理

小李子

  • Groovy
flowFile = session.create()
// Additional processing here
  • Jython
flowFile = session.create() 
# Additional processing here
  • Javascript
var flowFile = session.create();
// Additional processing here
  • JRuby
flowFile = session.create()
# Additional processing here

 

從基於傳入的FlowFile生成新的FlowFile

  • 使用會話對象的create(parentFlowFile)方法。
  • 此方法採用父級FlowFile引用
  • 並返回一個新的子FlowFile對象。
  • 新創建的FlowFile將繼承除UUID之外的所有父級屬性
  • 此方法將自動生成Provenance FORK事件或Provenance JOIN事件
  • 具體取決於在提交ProcessSession之前是否從同一父級生成了其他FlowFiles

 

栗子

  • Groovy
flowFile = session.get()
if(!flowFile) return
newFlowFile = session.create(flowFile)
// Additional processing here
  • Jython
flowFile = session.get() 
if (flowFile != None):
    newFlowFile = session.create(flowFile) 
    # Additional processing here
  • Javascript
var flowFile = session.get();
if (flowFile != null) {
  var newFlowFile = session.create(flowFile);
  // Additional processing here
}
  • JRuby
flowFile = session.get()
if flowFile != nil
  newFlowFile = session.create(flowFile)
  # Additional processing here
end

想要添加自定義屬性的流文件,爲流文件添加一個屬性

  • 使用會話對象中的putAttribute(flowFile,attributeKey,attributeValue)方法
  • 此方法使用給定的鍵/值對更新給定的FlowFile屬性
  • 注意:“uuid”屬性對於FlowFile是固定的,不能修改; 如key被命名爲“uuid”,它將被忽略。

FlowFile對象介紹

        這也是一個很好的提及FlowFile對象是不可變的;這意味着如果您通過API更新FlowFile的屬性(或以其他方式更改),則會獲得新版本的FlowFile的新參考。將FlowFiles傳輸到關係時,這是非常重要的。您必須保留對最新版本FlowFile的引用,並且必須傳輸或刪除從會話中檢索或創建的所有FlowFiles的最新版本,否則在執行時會出現錯誤。大多數情況下,用於存儲FlowFile引用的變量將被從改變FlowFile的方法返回的最新版本覆蓋(中間FlowFile引用將自動丟棄)。在這些示例中,您將看到添加屬性時重新使用flowFile引用的這種技術。請注意,對FlowFile的當前引用被傳遞給putAttribute()方法。生成的FlowFile具有名爲“myAttr”的屬性,其值爲“myValue”。另請注意,該方法需要一個字符串的值;如果你有一個對象,你將不得不將它序列化爲一個字符串。最後,請注意,如果您要添加多個屬性,最好創建一個Map並使用putAllAttributes()來代替 看下邊栗子

小李子

  • Groovy
flowFile = session.get()
if(!flowFile) return
flowFile = session.putAttribute(flowFile, 'myAttr', 'myValue')
  • Jython
flowFile = session.get() 
if (flowFile != None):
    flowFile = session.putAttribute(flowFile, 'myAttr', 'myValue')
# implicit return at the end
  • Javascript
var flowFile = session.get();
if (flowFile != null) {
   flowFile = session.putAttribute(flowFile, 'myAttr', 'myValue')
}
  • JRuby
flowFile = session.get()
if flowFile != nil
   flowFile = session.putAttribute(flowFile, 'myAttr', 'myValue')
end

想要添加自定義屬性的流文件,將多個屬性添加到流文件

  • 使用會話對象中的putAllAttributes(flowFile,attributeMap)方法。
  • 此方法使用給定Map中的鍵/值對更新給定的FlowFile屬性。
  • 注意:“uuid”屬性對於FlowFile是固定的,不能修改;如果密鑰被命名爲“uuid”,它將被忽略。

Map介紹

        這裏的技術是創建一個你想更新的屬性鍵/值對的Map(Jython中的字典,JRuby中的Hash),然後調用putAllAttributes()。這比爲每個鍵/值對調用putAttribute()要高效得多,因爲後一種情況會導致框架爲添加的每個屬性創建一個臨時版本的FlowFile。這些示例顯示了兩個條目myAttr1和myAttr2的映射,設置爲“1”,將數字2的語言特定的強制轉換爲字符串(以符合key和value均需要字符串值的方法簽名)。請注意,session.transfer()沒有在這裏指定(所以下面的代碼片段不工作)

示例

  • Groovy
attrMap = ['myAttr1': '1', 'myAttr2': Integer.toString(2)]
flowFile = session.get()
if(!flowFile) return
flowFile = session.putAllAttributes(flowFile, attrMap)
  • Jython
attrMap = {'myAttr1':'1', 'myAttr2':str(2)}
flowFile = session.get() 
if (flowFile != None):
    flowFile = session.putAllAttributes(flowFile, attrMap)
# implicit return at the end
  • Javascript
var number2 = 2;
var attrMap = {'myAttr1':'1', 'myAttr2': number2.toString()}
var flowFile = session.get() 
if (flowFile != null) {
    flowFile = session.putAllAttributes(flowFile, attrMap)
}
  • JRuby
attrMap = {'myAttr1' => '1', 'myAttr2' => 2.to_s}
flowFile = session.get() 
if flowFile != nil
    flowFile = session.putAllAttributes(flowFile, attrMap)
end

從流文件中獲取屬性

  • 使用FlowFile對象的getAttribute(attributeKey)方法。
  • 此方法返回給定attributeKey的String值,如果找不到attributeKey,則返回null。 這些例子顯示了檢索“filename”屬性的值。

栗子

  • Groovy
flowFile = session.get()
if(!flowFile) return
myAttr = flowFile.getAttribute('filename')
  • Jython
flowFile = session.get() 
if (flowFile != None):
    myAttr = flowFile.getAttribute('filename')
# implicit return at the end
  • Javascript
var flowFile = session.get() 
if (flowFile != null) {
    var myAttr = flowFile.getAttribute('filename')
}
  • JRuby
flowFile = session.get() 
if flowFile != nil
    myAttr = flowFile.getAttribute('filename')
end

從流文件獲取所有屬性 all

  • 使用FlowFile對象的getAttributes()方法。
  • 此方法返回一個帶有String鍵和String值的Map,表示流文件的屬性的鍵/值對。示例顯示了對FlowFile的所有屬性的Map的迭代。

 

栗子:

  • Groovy
flowFile = session.get()
if(!flowFile) return
flowFile.getAttributes().each { key,value ->
  // Do something with the key/value pair
}
  • Jython
flowFile = session.get() 
if (flowFile != None):
    for key,value in flowFile.getAttributes().iteritems():
       # Do something with key and/or value
# implicit return at the end
  • Javascript
var flowFile = session.get() 
if (flowFile != null) {
    var attrs = flowFile.getAttributes();
    for each (var attrKey in attrs.keySet()) { 
       // Do something with attrKey (the key) and/or attrs[attrKey] (the value)
  }
}
  • JRuby
flowFile = session.get() 
if flowFile != nil
    flowFile.getAttributes().each { |key,value| 
       # Do something with key and/or value
   }
end

將流文件轉移到關係  (“成功”或“失敗”)

  • 在處理流文件(新建或傳入)之後,您要將流文件轉換爲關係(“成功”或“失敗”)。
  • 在這種簡單的情況下,讓我們假設有一個名爲“errorOccurred”的變量,指出FlowFile應該傳送到哪個關係。
  • 使用會話對象的transfer(flowFile,relationship)方法。
  • 此方法根據給定的關係將給定的FlowFile傳送到適當的目標處理器工作隊列。
  • 從文檔:如果關係導致多於一個目的地,則FlowFile的狀態被複制,使得每個目的地都接收到FlowFile的精確副本,儘管每個目的地將具有其自己的唯一標識。

重點

  • ExecuteScript將在每次執行結束時執行session.commit()以確保操作已被提交。不需要(也不應該)在腳本中執行session.commit()。

栗子

  • Groovy
flowFile = session.get()
if(!flowFile) return
// Processing occurs here
if(errorOccurred) {
  session.transfer(flowFile, REL_FAILURE)
}
else {
  session.transfer(flowFile, REL_SUCCESS)
}
  • Jython
flowFile = session.get() 
if (flowFile != None):
    # All processing code starts at this indent
    if errorOccurred:
        session.transfer(flowFile, REL_FAILURE)
    else:
        session.transfer(flowFile, REL_SUCCESS)
# implicit return at the end
  • Javascript
var flowFile = session.get();
if (flowFile != null) {
   // All processing code goes here
   if(errorOccurred) {
     session.transfer(flowFile, REL_FAILURE)
   }
   else {
     session.transfer(flowFile, REL_SUCCESS)
   }
}
  • JRuby
flowFile = session.get()
if flowFile != nil
   # All processing code goes here
   if errorOccurred
     session.transfer(flowFile, REL_FAILURE)
   else
     session.transfer(flowFile, REL_SUCCESS)
   end
end

設置自己的日誌和日誌級別弄起來

  •  使用帶有warn(),trace(),debug(),info()或error()方法的log變量。

       這些方法可以採用單個字符串,或者一個字符串,後跟一個對象數組,或者一個字符串,後跟一個Throwable對象數組。第一個用於簡單的消息。當你有一些你想記錄的動態對象/值的時候使用第二種。要在消息字符串中引用這些消息,請在消息中使用“{}”。這些是按照外觀順序對Object數組進行評估的,所以如果消息的內容是“Found these things:{} {} {}”,而Object數組是[‘Hello’,1,true],那麼記錄的消息將會是“找到這些東西:你好1true”。這些日誌記錄方法的第三種形式也需要一個Throwable參數,並且在發生異常並且想要記錄它時非常有用。

栗子

  • Groovy
log.info('Found these things: {} {} {}', ['Hello',1,true] as Object[])
  • Jython
from java.lang import Object
from jarray import array
objArray = ['Hello',1,True]
javaArray = array(objArray, Object)
log.info('Found these things: {} {} {}', javaArray)
  • Javascript
var ObjectArrayType = Java.type("java.lang.Object[]");
var objArray = new ObjectArrayType(3);
objArray[0] = 'Hello';
objArray[1] = 1;
objArray[2] = true;
log.info('Found these things: {} {} {}', objArray)
  • JRuby
log.info('Found these things: {} {} {}', ['Hello',1,true].to_java)

 

 

 

ok

 

 

 

持續更新

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章