在Apache NiFi的ExecuteScript处理器中缓存文件内容

时间:2019-11-20 16:41:50

标签: xml apache-nifi schematron

我有一个 ExecuteScript 处理器,该处理器针对schematron进行了XML流文件验证。我希望将schematron文件的内容缓存在某个位置,而不是一次又一次从磁盘读取每个流文件的内容。

执行此操作的最佳选择是什么?我是否还需要另一个脚本,将schematron的内容放入 context.stateManager PutDistributedMapCache 或什么?

2 个答案:

答案 0 :(得分:1)

我正要回答,但似乎有可能。 您可以在ExecuteScript处理器中缓存变量。

总体思路

通过 EcmaScript 引擎在 ExecuteScript 处理器中使用简单脚本,您实际上可以将状态存储在处理器中。

var flowFile = session.get();

if (flowFile !== null) {
    var x = (x || 0) + 1;
    log.error('this is round: ' + x);

    session.transfer(flowFile, REL_SUCCESS);
}

在处理器内部使用此脚本将导致某些事情被记录下来:

...
ExecuteScript[id=...] this is round: 3
ExecuteScript[id=...] this is round: 2
ExecuteScript[id=...] this is round: 1

最多每x个时间单位更新文件

borowed来自现有NiFi ValidateXML 处理器的基本代码。

基本思想是在以下情况下更新文件

  1. 尚未设置或
  2. 自上次更新以来至少经过了x个时间单位

以下代码将实现此目的,其中 SCHEMA_FILE_PATH 是架构文件的路径。在这种情况下,x为三十秒:

// type definitions
var File = Java.type("java.io.File");
var FileNotFoundException = Java.type("java.io.FileNotFoundException");
var System = Java.type("java.lang.System");

// constants
var SCHEMA_FILE_PATH = "/foo/bar"; // exchange with real path
var timeoutInMillis = 30 * 1000; // 30 seconds

// initialize
var schemaFile = schemaFile || null;
var lastUpdateMillis = lastUpdateMillis || 0;



var flowFile = session.get();

function updateSchemaFile() {
    schemaFile = new File(SCHEMA_FILE_PATH);

    if (!schemaFile.exists()) {
        throw new FileNotFoundException("Schema file not found at specified location: " + schemaFile.getAbsolutePath());
    }

    lastUpdateMillis = System.currentTimeMillis();
}

if (flowFile !== null) {
    var now = System.currentTimeMillis();
    var schemaFileShouldBeUpdated = (schemaFile == null) || ((lastUpdateMillis || 0) + timeoutInMillis) < now;

    if (schemaFileShouldBeUpdated) {
        updateSchemaFile();
    }

    // TODO Do with the file whatever you want
    log.error('was file updated this round? ' + schemaFileShouldBeUpdated + '; last update millis: ' + lastUpdateMillis);

    session.transfer(flowFile, REL_SUCCESS);
}

免责声明

我无法确定是否可以清除变量,更不用说何时清除了。检查ExecuteScript处理器中使用的source code表示该脚本文件会定期重新加载。我不确定这样做的后果。

我还没有尝试使用受支持的另一种ScriptingLanguage,因为我对JavaScript最熟悉。

答案 1 :(得分:1)

groovy脚本中,可以用静态变量声明类,因此它们肯定会在处理器启动后保持状态。

另外,要管理这些静态变量的初始化,您可以使用ExecuteGroovyScript处理器的功能来拦截处理器的启动和停止。

在下面的示例中,我将比较流文件内容和磁盘上的某些文件,因为我对schematron不熟悉。

import org.apache.nifi.processor.ProcessContext

class Cache {
    static String validatorText = null
}
//this function called on processor start, so you can't use flow file in it
static void onStart(ProcessContext context){
    //init cached(static) variable from file
    Cache.validatorText = new File('/path/to/validator.txt').getText('UTF-8')
    println "onStart ${context}"
}

//process flow file and compare it to `Cache.validatorText`
def ff=session.get()
if(!ff)return

def ffText = ff.read().getText("UTF-8")
assert ffText = Cache.validatorText

REL_SUCCESS << ff
  

注意:您可以设置Failure strategy = transfer to failure。   在这种情况下,任何错误(包括断言失败)的流文件都将被重定向到REL_FAILURE,而无需其他代码。