概览
NiFi主要的功能是数据处理和数据分发,在NiFi中数据均抽象为FlowFile。FlowFile有两个部分组成:内容(Content)和属性(attribute)。这里Content是实际上要处理和分发的数据,而FlowFile并不直接存储数据而是存储了一个指向实际存储地址的指针。属性(attribute)是数据本身相关的元数据,描述信息等,形式是一组键值对。例如:“GetFile Processor”从本地磁盘中读取文件,则文件内容将成为FlowFile的内容,则属性可能为文件名、文件目录、文件大小、最后修改时间、读写权限等。FlowFile的属性使我们在不需要读取数据内容的情况下,能够完成很多数据处理操作。NiFi引入Expression Language就是为了使用户能够方便的访问FlowFile的属性,对它们进行引用、比较、赋值等操作。如果使用过其他表达式语言例如:spring el或者jsp el,那么掌握NiFi el将非常容易。如果有开发经验,掌握NiFi el也非常容易。
NiFi 表达式的结构
NiFi 表达式语言总是以界定符${
开始,并以界定符}
结束。在界定符之间的文本就是表达式本身。最基本的形式是表达式只包含一个属性名称,例如:表达式${filename}将返回“filename”属性的值。
稍复杂的形势,可以调用一个函数对值进行处理再返回。例如:$ {filename:toUpper()}
, 调用filename的toUpper函数,返回的是filename属性值的全大写形势。有编程经验的同学应该非常容易理解,这相当于在java代码“filename.toUpper();”,或者python代码的“filename.upper()”。我们拆解一下这个表达式:
-
调用方法使用的界定符是“:”
-
函数名称“toUpper”
-
函数的参数列表开始界定符"("
-
参数列表,这个例子里没有
-
函数的参数列表开始界定符")",这里也表示函数调用结束了。
NiFi el语言提供了很多的函数(这里基本对应了java的各种函数),用于应对各种各样的需求。例如操作字符串的toUpper(转大些)、equals(比较)、matches(正则匹配)等功能,另外还提供了丰富的数学计算和时间、日期操作函数。我们在一个属性上执行函数时,将这个属性称为函数的“subject”,因为函数是在属性实体上运行的。
�这里可以类比java函数调用。函数的调用时依赖于一个对象的,通常是object.xxx();在nifi里属性就是这个object。
链式调用
在NiFi el中,可以链式调用函数,形式是这样的${filename:toUpper():equals('HELLO.TXT')}
。在这个例子中“filename”是toUpper的“subject”,toUpper的返回值是equals的“subject”。链接在一起调用的功能函数的数量没有限制。
这里必须明确每个函数返回值的类型,因为返回值类型决定了下一个步能够使用什么函数。filename是一个字符串,能够使用字符串处理的函数toUpper, toUpper函数返回的也是字符串,能够继续是用字符串比较函数equals,equals函数返回的是一个boolean,这是就不能再调用字符串函数了,只能调用Boolean类型的函数。
字符转义
任何FlowFile的属性都可以被NiFi el引用。但是如果属性名称包含特殊字符,则必须对该属性名称进行转义。NiFi el定义的特殊字符有:
-
$ (dollar sign)
-
| (pipe)
-
{ (open brace)
-
} (close brace)
-
( (open parenthesis)
-
) (close parenthesis)
-
[ (open bracket)
-
] (close bracket)
-
, (comma)
-
: (colon)
-
; (semicolon)
-
/ (forward slash)
- (asterisk)
-
' (single quote)
-
(space)
-
\t (tab)
-
\r (carriage return)
-
\n (new-line)
此外,如果属性名称的第一个字符是数字,则它也被视为"特殊字符"。如果属性名称中存在特殊字符,则需要将属性名称至于双引号或者单引号之间。在NiFi el中双引号和单引号有等同的作用,可以互换使用。例如:一个属性名称“my attribute”中有空格,则在使用中应该转义,而使用${“my attribute”}
或${my attribute'}
这两种形式都是对的。
在本例中,要返回的值是“my attribute”属性的值(如果存在)。表达式语言将在一个层次结构中搜索匹配的属性。层次结构在下文中详细介绍。
还有一些函数是没有“subject”的,类似于java的静态函数没有对象就能调用。这些函数需在表达式开始进行调用,例如${hostname()}
。这些功能也可以一起改变。例如,${hostname():toUpper()}
。尝试使用“subject”调用这些函数将导致错误。
嵌入式表达式
如果需要比较两个不同属性的值,可以通过嵌入式表达式来实现这一点。例如,检查“filename”属性是否与“uuid”属性相同:${filename:equals( ${uuid})}
。**特别注意,在“equals”函数的左括号和嵌入表达式之间有一个空格,这不影响表达式的计算,它的目的是使表达式更易于阅读。分隔符之间的空白会被el忽略。因此,我们可以使用表达式${ filename : equals(${ uuid}) }
或 ${filename:equals(${uuid})}
,这两个表达式的意思是一样的。但是属性名之间的空格是不会被忽略的,而且必须转义。
属性搜索层级
当NiFi el引用了一个属性名称时,NiFi都会去哪里搜索这个属性?
-
当前FlowFile的属性
-
搜索Process Group的变量
-
搜索File Registry file
-
搜索NiFi JVM的属性
-
搜索操作系统环境变量
NiFi由上到下逐一搜索,发现匹配的属性或者变量立即返回。如果没有搜索到则返回一个“null”。
el的使用
在NiFi应用程序中,el大量用于配置处理器属性,但是并非所有处理器属性都支持le。属性是否支持el,是由“Processor"的开发人员在编写处理器时决定。NiFi为每个属性清楚地标命了el是否被支持。
在NiFi配置组件属性时,用户界面在属性名称旁边提供一个信息图标([图片上传失败...(image-fec500-1606195078087)] )。将鼠标悬停在该图标上,将提供一个提示,其中提供有关属性的有用信息。此信息包括属性的描述、默认值(如果有)、历史配置的值(如果有)以及表达式语言的此属性的计算范围。有三个值,表达式语言的求值范围是分层的:NONE(不支持) → VARIABLE_REGISTRY(变量注册表)→ FLOWFILE_ATTRIBUTES(FlowFile属性)。
-
None:此属性不支持使用el记性配置。
-
VARIABLE_REGISTRY: 按层次结构构造如下:
-
在"Process Group"级别定义的变量,然后递归地向上到更高的"Process Group",直到根"Process Group"。
-
在自定义属性文件(NiFi.properties)中通过nifi.variable.registry.properties注册的属性。
-
在JVM级别定义的环境变量和系统属性。
-
-
FLOWFILE_ATTRIBUTES-将使用当前FlowFile的属性,以及变量注册表定义的变量。
转义
在NiFi EL中${
和}
被赋予特别的意义,因此如果Processor属性中要使用这个两个标记作为文本意义时则需要进行转义。例如,用户可能希望将属性值配置为文本Hello${UserName}
,NiFi会将这段文本识别为EL表达式,这时候就需要使用转义,即添加一个额外的美元符号$
,使用Hello$${UserName}
。转义本身比较简单,但是容易被忽略,而造成困扰,需要小心应对。
如果在{
之前连续遇到两个以上的$
字符,则每对$
字符都将被视为$
字符的转义。从左到右执行转义。为了帮助说明这一点,请考虑变量“abc”包含值“xyz”。然后,考虑下表中的表达式及其相应的求值:
表达式 | 返回值 | 说明 |
---|---|---|
${abc} |
xyz |
|
$${abc} |
${abc} |
$$,第一个被转义 |
$$${abc} |
$xyz |
|
$$$${abc} |
$${abc} |
|
$$$$${abc} |
$$xyz |
|
I owe you $5 |
I owe you $5 |
没有el表达式 |
You owe me $$5 too |
You owe me $$5 too |
$字符没有转义,因为它不在el表达式前面。 |
Unescaped $$${5 because no closing brace |
Unescaped $$${5 because no closing brace |
因为这里没有右大括号,所以没有实际的el表达式,因此$字符没有转义。 |
Unescaped $$${5} because no closing brace |
<Error> | 此表达式无效,因为前两个美元符($$)因为转义在文本上等于一个美元({5}”,而“{‘5’}” |
Unescaped $$${'5'} because no closing brace |
Unescaped $ because no closing brace |
',因为它紧跟在表达式前面。 |
表达式语言编辑器
配置“Processor”属性的值时,NiFi用户界面使用表达式语言编辑器提供有关表达式语言的帮助。一旦一个表达式以${
开始,编辑器就开始突出显示括号和大括号,这样用户就可以很容易地分辨出哪个左括号或大括号与哪个右括号或大括号匹配。
编辑器还提供了上下文相关的帮助,它提供了可以在当前光标位置使用的所有函数的列表。要激活此功能,请按键盘上的Ctrl+Space(注意操作系统快捷键冲突)。用户还可以键入函数名的一部分,然后按Ctrl+Space查看所有可以使用的以相同前缀开头的函数。例如,如果我们在编辑器中输入${filename:to
然后按Ctrl+Space,会弹出一个弹出窗口,其中列出了六个不同的函数:“toDate”、“toLower”、“toNumber”、“toRadix”、“toString”和“toUpper”。然后,我们可以继续键入以缩小显示的函数,也可以通过用鼠标双击列表中的一个函数或使用箭头键突出显示所需的函数并按Enter键从列表中选择一个函数。
函数
函数提供了一种操作和比较属性值的方法。表达式语言提供了许多不同的函数来满足自动化数据流程的需要。每个函数接受零个或多个参数并返回一个值。然后可以将这些函数链接在一起,以创建强大的表达式来计算条件和操作值。
数据类型
函数的每个参数和从函数返回的每个值都有特定的数据类型。表达式语言支持四种不同的数据类型:
-
String:字符串是一系列字符,可以由数字、字母、空格和特殊字符组成。
-
Number(整数): 数字是由一个或多个数字组成的整数(
0
到9
)。从日期数据类型转换为数字时,它们表示为自1970年1月1日格林尼治标准时间午夜以来的毫秒数。 -
Decimal: Decimal是一个可以支持小数和更大值的数值,精度损失最小。更准确地说,它是一个双精度64位IEEE 754(浮点数运算标准) 浮点。由于有精度损失,因此不应将此数据类型用于非常精确的值,例如货币。以下是表达式语言支持的文字小数形式的一些示例(“E”也可以是小写):
-
1.1
-
.1E1
-
1.11E-12
-
-
Date:
-
期是保存日期和时间的对象。利用日期操纵和类型强制函数此数据类型可以转换为字符串和数字。如果整个表达式语言表达式的计算结果为日期,则它将转换为格式为“<Day of Week><Month><Day of Month><Hour>:<Minute>:<Second><Time Zone><Year>”的字符串。在Java SimpleDateFormat格式中也表示为“E MMM dd HH:mm:ss z yyyy”。例如:“2016年12月31日星期三12:00:04 UTC”。
-
Boolean: 布尔值是“true”或“false”之一。
在计算表达式语言函数之后,所有属性都存储为类型字符串。
表达式语言一般能够自动进行类型转化,但是也存在一些函数需要进行强制转换。
数字和十进制类型支持十六进制值,但在解释为文本时,必须用“0x”加引号和前缀。例如,这两个表达式是有效的(如果没有引号或“0x”,表达式将无法正常运行):
-
${literal("0xF"):toNumber()}
-
${literal("0xF.Fp10"):toDecimal()}
布尔逻辑
表达式语言够将属性值与其他值进行比较。例如,这通常用于配置“Processor”应如何路由数据。以下函数用于执行布尔逻辑,例如比较两个值。这些函数中的每一个都是为处理Boolean类型的值而设计的。
isNull
判断值是否为空。为空返回"true",不为空返回“false”
例子: ${filename:isNull()}
返回 true
如果"filename" 属性不存在 ,返回 false
如果属性存在。
notNull
“notNull”函数返回“isNull”函数的相反值。也就是说,如果主题存在,它将返回“true”,否则返回“false”。
例子: ${filename:notNull()}
isEmpty
如果Subject为null、不包含任何字符或只包含空白(换行、回车、空格、制表符),则“isEmpty”函数返回“true”;否则返回“false”.
例子: ${filename:isEmpty()}
返回 true
如果“filename”属性为空或者只包含空白字符, 否则返回“false”
equals
“equals”函数使用非常广泛,它可以确定其主题是否等于另一个字符串值。注意,equals
函数执行两个字符串值的直接比较,另外一个比较函数“matches”是使用正则表达式进行匹配。
例子: 通过使用表达式${filename:equals("hello.txt")}
,我们可以检查FlowFile的文件名是否为“hello.txt“,,或者可以检查属性“hello”的值是否等于“filename”属性的值:${hello:equals( ${filename} )}
equalsIgnoreCase
描述: 与“equals”函数类似,“equalsIgnoreCase”函数忽略大小写。
例子: ${filename:equalsIgnoreCase('hello.txt')}
gt
描述: “gt”函数用于数值比较,如果主题大于参数,则返回“true”。如果不能将主语或参数强制转换为数字,则此函数返回“false”。
例子: ${fileSize:gt( 1024 )}
如果"filesize"大于1024返回“true”,否则返回"false".
ge
描述: 描述: “ge”函数用于数值比较,如果主题大于等于参数,则返回“true”,否则返回"false"。如果不能将主语或参数强制转换为数字,则此函数返回“false”。
例子: ${fileSize:ge( 1024 )}
如果"filesize"大于或正等于1024返回“true”,否则返回"false".
lt
描述: “lt”函数用于数值比较,如果主题小于参数,则返回“true”,否则返回"false"。如果不能将主语或参数强制转换为数字,则此函数返回“false”。
例子: ${fileSize:lt( 1048576 )}
如果"filesize"小于1048576返回“true”,否则返回"false".
le
描述: “le”函数用于数值比较,如果主题小于或等于参数,则返回“true”,否则返回"false"。如果不能将主语或参数强制转换为数字,则此函数返回“false”。
例子: ${fileSize:le( 1048576 )}
如果"filesize"小于等于1048576返回“true”,否则返回"false".
and
and的主题是boolean型,参数也是boolean型,当主题和参数都为“true”,则返回"true",其他情况全返回"false"
Expression | Value |
---|---|
${bool:ifElse('a','b')} |
a |
${literal(true):ifElse('a','b')} |
a |
${nullFilename:isNull():ifElse('file does not exist', 'located file')} |
file does not exist |
${nullFilename:ifElse('found', 'not_found')} |
not_found |
${filename:ifElse('found', 'not_found')} |
not_found |
${filename:isNull():not():ifElse('found', 'not_found')} |
found |
字符串操作
toUpper
返回字符串的大写。
toLower
返回字符串的小写。
trim
去掉首尾的空白字符。
substring
返回字符串的一部分,两个参数开始位置(包含)和结束位置(不包含)。
例子:
如果属性"filename"的值为"a brand new filename.txt"则一下表达式成立:
Expression | Value |
---|---|
${filename:substring(0,1)} |
a |
${filename:substring(2)} |
brand new filename.txt |
${filename:substring(12)} |
filename.txt |
${filename:substring( ${filename:length():minus(2)} )} |
xt |
substringBefore
接收一个字符串型的参数。在subject中由左至右匹配参数字符串,如果过匹配到,返回匹配位置左侧的子串。
例子: "filename" => "a brand new filename.txt":
Expression | Value |
---|---|
${filename:substringBefore('.')} |
a brand new filename |
${filename:substringBefore(' ')} |
a |
${filename:substringBefore(' n')} |
a brand |
${filename:substringBefore('missing')} |
a brand new filename.txt |
substringBeforeLast
接收一个字符串型的参数。在subject中由右至左匹配参数字符串,如果过匹配到,返回匹配位置左侧的子串。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:substringBeforeLast('.')} |
a brand new filename |
${filename:substringBeforeLast(' ')} |
a brand new |
${filename:substringBeforeLast(' n')} |
a brand |
${filename:substringBeforeLast('missing')} |
a brand new filename.txt |
substringAfter
接收一个字符串型的参数。在subject中由左至右匹配参数字符串,如果过匹配到,返回匹配位置右侧的子串。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:substringAfter('.')} |
txt |
${filename:substringAfter(' ')} |
brand new filename.txt |
${filename:substringAfter(' n')} |
ew filename.txt |
${filename:substringAfter('missing')} |
a brand new filename.txt |
substringAfterLast
接收一个字符串型的参数。在subject中由右至左匹配参数字符串,如果过匹配到,返回匹配位置右侧侧的子串。
例子: "filename" => "a brand new filename.txt":
Expression | Value |
---|---|
${filename:substringAfterLast('.')} |
txt |
${filename:substringAfterLast(' ')} |
filename.txt |
${filename:substringAfterLast(' n')} |
ew filename.txt |
${filename:substringAfterLast('missing')} |
a brand new filename.txt |
getDelimitedField
使用分隔符将subject分成若干字段,并返回其中指定的字段。
参数:
- 字段索引,指定返回第几个字段,注意索引是由1开始的,要区别于数组索引。
- 分割符,默认是“,”。
- 引用字符 : 引用字符范围内的分割符将会被忽略。
- 转义字符,转义后的分割符将失去分割作用。默认为“\”。
- 删除字符(bool),是否删除转义字符和引用字符。如果在处理过程中遇到转移字符或引用字符,此字符将被删除。
返回值: String
例子:
-
"line" => "Jacobson, John", 32, Mr.
-
"altLine" => Jacobson, John|32|Mr.
Expression Value ${line:getDelimitedField(2)}
(space)32 ${line:getDelimitedField(2):trim()}
32 ${line:getDelimitedField(1)}
"Jacobson, John" ${line:getDelimitedField(1, ',', '"', '\\', true)}
Jacobson, John ${altLine:getDelimitedField(1, '|')}
Jacobson, John append
接收一个字符串参数,将参数追加到主题(subject)之后然后返回。
例子: "filename" => "a brand new filename.txt", 则表达式 ${filename:append('.gz')}
返回 "a brand new filename.txt.gz".
prepend
接收一个字符串参数,将主题追加到参数之后然后返回。
例子: "filename" => "a brand new filename.txt", 则表达式 ${filename:prepend('a brand new ')}
返回 "a brand new filename.txt".
replace
替换字符串,接收两个参数,第一个参数查找并被的字符串,第二个参数替换字符串。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:replace('.', '_')} |
a brand new filename_txt |
${filename:replace(' ', '.')} |
a.brand.new.filename.txt |
${filename:replace('XYZ', 'ZZZ')} |
a brand new filename.txt |
${filename:replace('filename', 'book')} |
a brand new book.txt |
replaceFirst
替换字符串,但是只替换找到的第一个字符串。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:replaceFirst('a', 'the')} |
the brand new filename.txt |
${filename:replaceFirst('[br]', 'g')} |
a grand new filename.txt |
${filename:replaceFirst('XYZ', 'ZZZ')} |
a brand new filename.txt |
${filename:replaceFirst('\w{8}', 'book')} |
a brand new book.txt |
replaceAll
replaceAll函数接收两个字符串参数:一个文本字符串或正则表达式(NiFi使用Java模式语法)和一个替换字符串。返回值是用替换字符串替换主题中与正则表达式匹配的所有模式的结果。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:replaceAll('\..*', '')} |
a brand new filename |
${filename:replaceAll('a brand (new)', '$1')} |
new filename.txt |
${filename:replaceAll('XYZ', 'ZZZ')} |
a brand new filename.txt |
${filename:replaceAll('brand (new)', 'somewhat $1')} |
a somewhat new filename.txt |
padLeft
“padLeft”函数将给定的填充字符串(默认为“_”)添加到参数“subject”左侧,直到达到指定长度。
以下两种情况不执行填充:
- subject的长度已经等于或大于指定长度
- 指定的长度为负数,或者大于Integer.MAX
如果参数字符串不是有效属性,则返回“null”。
例子: "greetings" => "hello",
Expression | Value |
---|---|
${greetings:padLeft(10)} |
_____hello |
${greetings:padLeft(10, '@')} |
@@@@@hello |
${greetings:padLeft(10, 'xy')} |
xyxyxhello |
${greetings:padLeft(10, 'aVeryLongPaddingString')} |
aVeryhello |
padRight
“padLeft”函数将给定的填充字符串(默认为“_”)添加到参数“subject”右侧,直到达到指定长度。
以下两种情况不执行填充:
- subject的长度已经等于或大于指定长度
- 指定的长度为负数,或者大于Integer.MAX
如果参数字符串不是有效属性,则返回“null”。
例子: "greetings" => "hello",
Expression | Value |
---|---|
${greetings:padRight(10)} |
hello_____ |
${greetings:padRight(10, '@')} |
hello@@@@@ |
${greetings:padRight(10, 'xy')} |
helloxyxyx |
${greetings:padLeft(10, 'aVeryLongPaddingString')} |
helloaVery |
replaceNull
接收一个参数,如果主题不存在则返回参数值,如果主题存在则返回主题属性值。
例子: "filename" => "a brand new filename.txt" , "hello" 不存在, 则表达式 ${filename:replaceNull('abc')}
返回 "a brand new filename.txt", 而${hello:replaceNull('abc')}` 返回 "abc".
replaceEmpty
接收一个参数,如果主题不存在或者主题属性值只包含空字符串则返回参数值,否则返回主题属性值。
例子: "filename" => "a brand new filename.txt" 、"hello" => " ", 则表达式 ${filename:replaceEmpty('abc')}
返回 "a brand new filename.txt", 而${hello:replaceEmpty('abc')}` 返回 "abc".
length
返回subject的长度.
例子: "filename" => "a brand new filename.txt" , "hello" => null, ${filename:length()}
返回 24. ${hello:length()}
返回 0.
evaluateELString
此函数用于计算变量值内的表达式语言。
例子: "query" => "SELECT * FROM TABLE WHERE ID = {query:evaluateELString()}` 将返回“SELECT * FROM TABLE WHERE ID = 20”
repeat
返回一个字符串,该字符串的主题在min repeats和max repeats之间随机重复多次。如果没有提供max repeats,它将返回Subject repeated exactly min repeats次。
min repeats和max repeats必须是正数,max repeats大于或等于min repeats
如果min repeats或max repeats不是数字,则此函数调用将导致错误。
Expression | Value |
---|---|
${str:repeat(1)} |
abc |
${str:repeat(2)} |
abcabc |
${str:repeat(1,2)} |
abc or abcabc (at random) |
${str:repeat( ${str:length()} )} |
abc or abcabc or abcabcabc (at random) |
编码/解码函数
escapeJson
此函数通过使用JSON字符串规则转义字符串中的字符来准备要插入到JSON文档中的主题。函数正确地转义引号和控制字符(tab, backslash, cr, ff等)
例子: "message" => 'He didn’t say, "Stop!"', 则表达式 ${message:escapeJson()}
将返回 'He didn\u2019t say, "Stop!"'
escapeXml
此函数通过使用XML实体转义字符串中的字符来准备要插入到XML文档中的主题。函数正确地转义引号、撇号、和号、<,>和控制字符。
例子: "message" => '"bread" & "butter"',表达式 ${message:escapeXml()}
返回:
"bread" & "butter"
escapeCsv
此函数通过使用RFC 4180中的规则转义字符串中的字符来准备要插入到CSV文档中的主题。如果需要,函数正确地转义引号并将字符串括在引号中。
例子: "message" => 'But finally, she left', 则表示 ${message:escapeCsv()}
返回 " 'But finally, she left'"
escapeHtml3
此函数通过使用HTML实体转义字符串中的字符来准备要插入到HTML文档中的主题。仅支持HTML3.0实体。
例子: "message" => '"bread" & "butter"', 则表达式${message:escapeHtml3()}
返回
"bread" & "butter"
escapeHtml4
此函数通过使用HTML实体转义字符串中的字符来准备要插入到HTML文档中的主题。支持所有已知的HTML4.0实体
主题: String
参数: 无
返回值: String
例子: "message" => '"bread" & "butter"', 则表达式${message:escapeHtml4()}
返回
"bread" & "butter"
unescapeJson
描述: 此函数用于取消在字符串中找到的任何Json文本的转义。
Expression | Value |
---|---|
${filename:find('a [Bb]rand [Nn]ew')} |
true |
${filename:find('Brand.*')} |
false |
${filename:find('brand')} |
true |
unescapeXml
此函数将包含XML实体转义符的字符串取消转义为包含与转义符对应的实际Unicode字符的字符串。仅支持五个基本XML实体(gt、lt、quot、amp、apos)。
unescapeCsv
此函数根据RFC 4180的规则从CSV文档中取消转义字符串。
unescapeHtml3
此函数用于将包含HTML3实体的字符串转换为包含与转义符对应的实际Unicode字符的字符串。仅支持HTML3.0实体。
unescapeHtml4
此函数用于将包含HTML4实体的字符串转换为包含与转义符对应的实际Unicode字符的字符串。支持所有已知的HTML4.0实体。
urlEncode
返回主题的URL编码。
例子: "url" => "https://nifi.apache.org/some value with spaces", 表达式${url:urlEncode()}返回"https%3A%2F%2Fnifi.apache.org%2Fsome+value+with+spaces".
urlDecode
返回主题url解码的值。
例子: "url" => "https://nifi.apache.org/some%20value%20with%20spaces" 或者 "https%3A%2F%2Fnifi.apache.org%2Fsome+value+with+spaces", 则表达式 ${url:urlDecode()}
返回 "https://nifi.apache.org/some value with spaces".
base64Encode
对主题进行base64编码
base64Decode
对主题进行base64解码
UUID3
返回基于类型3(MD5哈希)命名空间名称的UUID。
hash
使用提供的哈希算法返回十六进制编码的字符串。这可用于生成唯一密钥。
UUID5
返回基于类型5(SHA-1 hashed)命名空间名称的UUID。,算法可以选择[SHA-384, SHA-224, SHA-256, MD2, SHA, SHA-512, MD5]
字符串搜索
用于搜索其主题以获取某些值。
startsWith
如果主题以参数提供的字符串开头,则返回“true”;否则返回“false”。
endsWith
如果主题以参数提供的字符串结尾,则返回“true”;否则返回“false”。
contains
如果主题在任何位置包含参数的值,则返回“true”。
in
接收多个参数,如果主题与提供的参数之一匹配,则返回“true”。
find
如果主题包含与参数提供的正则表达式匹配的任何字符序列,则返回“true”。
例子:"filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:find('a [Bb]rand [Nn]ew')} |
true |
${filename:find('Brand.*')} |
false |
${filename:find('brand')} |
true |
matches
如果主题与参数提供的正则表达式完全匹配,则返回“true”。
例子:
"filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:matches('a.*txt')} |
true |
${filename:matches('brand')} |
false |
${filename:matches('.brand.')} |
true |
indexOf
返回与作为参数提供的字符串值匹配的主题中第一个字符的索引。如果在Subject中多次找到该参数,则返回的值是第一次出现的起始索引。如果在主题中找不到参数,则返回“-1”。索引从零开始,如果在主题的开头找到搜索字符串,则返回的值将为“0”,而不是“1”。
例子: "filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:indexOf('a.*txt')} |
-1 |
${filename:indexOf('.')} |
20 |
${filename:indexOf('a')} |
0 |
${filename:indexOf(' ')} |
1 |
lastIndexOf
返回与作为参数提供的字符串值匹配的主题中第一个字符的索引。如果在Subject中多次找到该参数,则返回的值是最后一次出现的起始索引。如果在主题中找不到参数,则返回“-1”。索引从零开始,如果在主题的开头找到搜索字符串,则返回的值将为“0”,而不是“1”。
例子:"filename" => "a brand new filename.txt",
Expression | Value |
---|---|
${filename:lastIndexOf('a.*txt')} |
-1 |
${filename:lastIndexOf('.')} |
20 |
${filename:lastIndexOf('a')} |
17 |
${filename:lastIndexOf(' ')} |
11 |
jsonPath
“jsonPath”函数通过将主题计算为JSON并应用JSON路径表达式来生成字符串。如果主题不包含有效的JSON、jsonPath无效或主题中不存在路径,则生成空字符串。如果计算结果是标量值,则生成标量值的字符串表示形式。否则将生成JSON结果的字符串表示形式。长度为1的JSON数组是特殊大小写的,当“[0]”是标量时,生成“[0]”的字符串表示形式。
例子: "myJson"的值如下
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null
}
表达式 | 返回值 |
---|---|
${myJson:jsonPath('$.firstName')} |
John |
${myJson:jsonPath('$.address.postalCode')} |
10021-3100 |
${myJson:jsonPath('$.phoneNumbers[?(@.type=="home")].number')} |
212 555-1234 |
${myJson:jsonPath('$.phoneNumbers')} |
[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"}] |
${myJson:jsonPath('$.missing-path')} |
empty |
${myJson:jsonPath('$.bad-json-path..')} |
exception bulletin |
jsonPathDelete
“jsonPathDelete”函数从主题JSON中删除指定的JsonPath,并返回更新后的JSON的字符串形式。
例子: "myJson"的值如下
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null
}
Expression | Value |
---|---|
${myJson:jsonPathAdd('$.nicknames', 'Jimmy')} |
{"firstName":"James", lastName":"Smith", "age":25, "voter":true, "height":6.1, "address":{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021-3100"}, "phoneNumbers":[{"type":"home", "number":"212 555-1234"}, {"type":"office", "number":"646 555-4567"}],"nicknames":["Jimmy"]} |
${myJson:jsonPathAdd('$.missingpath', 'Jimmy')} |
Returns original JSON document with no modifications |
${myJson:jsonPathAdd('$.firstName', 'Jimmy')} |
empty |
空的subject值或带有无效JSON文档的subject值将导致异常公告。
jsonPathAdd
函数将标量值添加到主题JSON的指定JsonPath处的数组中,并返回更新后的JSON的字符串形式。如果expression目标元素是非数组,则返回一个空字符串,并记录一个指示错误的异常。如果表达式目标元素路径不在JSON中,则该操作返回原始JSON而不做任何修改。
例子: "myJson"的值如下
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"voter" : true,
"height" : 6.1,
"address" : {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"nicknames" : []
}
Expression | Value |
---|---|
${myJson:jsonPathAdd('$.nicknames', 'Jimmy')} |
{"firstName":"James", lastName":"Smith", "age":25, "voter":true, "height":6.1, "address":{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021-3100"}, "phoneNumbers":[{"type":"home", "number":"212 555-1234"}, {"type":"office", "number":"646 555-4567"}],"nicknames":["Jimmy"]} |
${myJson:jsonPathAdd('$.missingpath', 'Jimmy')} |
Returns original JSON document with no modifications |
${myJson:jsonPathAdd('$.firstName', 'Jimmy')} |
empty |
jsonPathSet
“jsonPathSet”函数在主题JSON的指定JsonPath处设置值,并返回更新后的JSON的字符串形式。
例子: "myJson"的值如下
Expression | Value |
---|---|
${myJson:jsonPathPut('$','middlename','Turon')} |
{"firstName":"James", lastName":"Smith", "middlename": "Turon", "age":25, "voter":true, "height":6.1, "address":{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021-3100"}, "phoneNumbers":[{"type":"home", "number":"212 555-1234"}, {"type":"office", "number":"646 555-4567"}]} |
jsonPathPut
“jsonPathPut”函数将键和标量值放在主题JSON的指定JsonPath处,并返回更新后的JSON的字符串形式。
例子: "myJson"的值如下
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"voter" : true,
"height" : 6.1,
"address" : {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"nicknames" : []
}
Expression | Value |
---|---|
${myJson:jsonPathPut('$','middlename','Turon')} |
{"firstName":"James", lastName":"Smith", "middlename": "Turon", "age":25, "voter":true, "height":6.1, "address":{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021-3100"}, "phoneNumbers":[{"type":"home", "number":"212 555-1234"}, {"type":"office", "number":"646 555-4567"}]} |
空的subject值或带有无效JSON文档的subject值将导致异常公告。
数学计算与数字操作
对于那些支持Decimal和Number(整数)类型的函数,返回值类型取决于输入类型。如果主语或参数是十进制,则结果将是十进制。如果两个值都是数字,则结果将是数字,包括除法,这是为了保持向后兼容性,而不是强制舍入错误。
plus
返回主题与参数相加的和。
minus
返回主题减去参数的差。
multiply
返回主题与参数相乘的积
divide
返回主题被参数除开的商。
mod
返回主题对参数取模(余数)。
toRadix
将主语数字基数转化,即数字在不同进制间转化。第一个参数进制,第二个参数显示数位。
例子: "fileSize" =>1024
Expression | Value |
---|---|
${fileSize:toRadix(10)} |
1024 |
${fileSize:toRadix(10, 1)} |
1024 |
${fileSize:toRadix(10, 8)} |
00001024 |
${fileSize:toRadix(16)} |
400 |
${fileSize:toRadix(16, 8)} |
00000400 |
${fileSize:toRadix(2)} |
10000000000 |
${fileSize:toRadix(2, 16)} |
0000010000000000 |
fromRadix
将主语从指定的基数(或基数)转换为以10为基数的整数。主题将按原样转换,无需解释,并且所有字符都必须对所转换的基有效。例如,由于“x”是无效的十六进制字符,从十六进制转换“0xFF”将不起作用。如果一个十进制数作为主语传递,它将首先转换为整数,然后再进行处理。参数范围为2~36。
例子: "fileSize" =>1234A
Expression | Value |
---|---|
${fileSize:fromRadix(11)} |
17720 |
${fileSize:fromRadix(16)} |
74570 |
${fileSize:fromRadix(20)} |
177290 |
random
返回一个随机的整数,范围为0~2^63 - 1
math
高级功能。此表达式仅供高级用户使用。它利用Java反射来运行任意java.lang.Math静态方法。确切的API将取决于您运行的Java版本。
为了运行正确的方法,参数类型必须正确。表达式语言“Number”(整数)类型被解释为Java“long”。“Decimal”类型被解释为Java“double”。运行所需的方法可能需要调用“toNumber()”或“toDecimal()”,以便将值“强制转换”为所需的类型。当级联“math()”调用时,记住这一点也很重要,因为返回值依赖于运行的方法。
例子:
- ${math("random")} => Math.random().
- ${literal(2):toDecimal:math("pow", 2.5)} => Math.pow(2D,2.5D).
日期操作
format
根据参数指定的格式将数字格式化为日期/时间。参数必须是有效的Java SimpleDateFormat格式的字符串。主题应该是一个数字,表示自1970年1月1日格林尼治标准时间午夜以来的毫秒数。除非在第二个可选选项中指定,否则将使用本地时区计算该数字参数.函数.
例子: "time" =>"1420058163264"
表达式 | 返回值 |
---|---|
${time:format("yyyy/MM/dd HH:mm:ss.SSS'Z'", "GMT")} |
2014/12/31 20:36:03.264Z |
${time:format("yyyy/MM/dd HH:mm:ss.SSS'Z'", "America/Los_Angeles")} |
2014/12/31 12:36:03.264Z |
${time:format("yyyy/MM/dd HH:mm:ss.SSS'Z'", "Asia/Tokyo")} |
2015/01/01 05:36:03.264Z |
${time:format("yyyy/MM/dd", "GMT")} |
2014/12/31 |
${time:format("HH:mm:ss.SSS'Z'", "GMT")} |
20:36:03.264Z |
${time:format("yyyy", "GMT")} |
2014 |
toDate
将字符串根据指定格式转化为日期,第一个参数日期格式,第二个参数时区。
now
返回当前的时间,返回类型为Date。
表达式 | 返回值 |
---|---|
${now()} |
表示当前日期和时间的日期类型,精确到毫秒 |
${now():toNumber()} |
自1970年1月1日格林尼治标准时间午夜起的毫秒数(例如,1453843201123) |
${now():toNumber():minus(86400000) |
一个显示24小时前时间的数字 |
${now():format(‘yyyy’)} |
返回4位年 |
${now():toNumber():minus(86400000):format('E')} |
昨天是星期几,用3个字母的缩写(例如,“Wed”) |
类型转换
无主函数
表达式语言中的大多数函数是通过使用语法${属性名:函数名(参数列表)}
调用。有一些函数不包含主题,即属性名不存在,则使用如下形式进行调用函数名(参数列表)}
,例如${ip()}`获得机器的IP地址。本节中的所有函数没有主题,直接进行调用。
ip
返回当前主机的ip地址。
例子:获取本机地址的方式为: ${ip()}
.
hostname
返回当前主机名。接受一个布尔型参数,参数为“true”,返回一个完全限定的主机名,参数为“false”,返回一个简单主机名,参数默认值为“false”
例子: 返回完全限定主机名{hostname(false)} 或 ${hostname()}。
UUID
描述: 返回随机生成的类型4 UUID。
例子: ${UUID()} 返回值类似于“305d54-75b4-431b-adb2-eb6b9e546013”
nextInt
返回一个整数,在一个NiFi实例中连续调用理论上返回一个单调递增整数序列(由0开始)。此值不会在重启后保持,也不能保证在集群中是唯一的。这个计数器在所有NiFi组件之间共享,因此一个Processor连续调用不一定能得到连续的序列。
literal
将参数作为文本字符串值返回。
例子: {literal( ${allMatchingAttributes('a.*'):count()} ):gt(3)},如果有三个以上的属性名以“a”开头则返回true。
getStateValue
通过传入字符串键并将值作为字符串返回来访问“processor”的状态值。这是一个特殊的表达式语言函数,它只适用于显式允许EL查询状态的“processor”。目前只有UpdateAttribute可以。
例子: 如果“UpdateAttribute processor”曾经在状态中使用“count”键存储了一个值“20” ,'${getStateValue("count")}返回20.
thread
返回"processor"在计算表达式时使用的线程的名称。当使用具有多个并发任务的处理器并且需要某些数据唯一性时,这可能用得到。
例子: ${thread()}
返回值类似 Timer-Driven Process Thread-4
.
多属性求值
当有必要针对多个属性相同的条件求值时,可以通过“and”和“or”函数来实现。如果属性超过两个,表达式将变得晦涩难懂、容易出错,并且很难维护。出于这个原因,NiFi提供了几个函数来同时针对属性组相同的条件求值。
anyAttribute
检查给定属性是否与给定条件匹配。此函数没有主语,它接受一个或多个参数,这些参数是要应用表达式其余部分的属性的名称。如果指定的任何属性在对表达式求值时返回值“true”,则此函数将返回“true”。否则,此函数将返回“false”。相当于多个属性分别求值再进行"或"计算。
例子: 有三对属性:"abc"=> "hello world", "xyz" => "good bye world", "filename" => "file.txt"
表达式 | 返回值 |
---|---|
${anyAttribute("abc", "xyz"):contains("bye")} |
true |
${anyAttribute("filename","xyz"):toUpper():contains("e")} |
false |
allAttributes
检查所有给定属性是否与给定条件匹配。此函数没有主语,它接受一个或多个参数,这些参数是要应用表达式其余部分的属性的名称。如果在对表达式的其余部分求值时,指定的所有属性都返回值“true”,则此函数将返回“true”。否则,此函数将返回“false”。相当于多个属性分别求值再进行或计算。相当于多个属性分别求值再进行"与"计算。
例子: 有三对属性: "abc" => "hello world", "xyz" => "good bye world", "filename" => "file.txt" ,
表达式 | 返回值 |
---|---|
${allAttributes("abc", "xyz"):contains("world")} |
true |
${allAttributes("abc", "filename","xyz"):toUpper():contains("e")} |
false |
anyMatchingAttribute
检查给定属性是否与给定条件匹配。此函数没有主语,它接受一个或多个正则表达式参数以与属性名匹配。任何名称与提供的正则表达式之一匹配的属性都将根据表达式的其余部分进行计算。如果指定的任何属性在对表达式的其余部分求值时返回值“true”,则此函数将返回“true”。否则,此函数将返回“false”。相当于多个属性分别求值再进行或计算。相当于多个属性(能够与正则表达式相匹配)分别求值再进行"或"计算。
例子: 有三对属性: "abc" => "hello world", "xyz" => "good bye world", "filename" => "file.txt" ,
表达式 | 返回值 |
---|---|
${anyMatchingAttribute("[ax].*"):contains('bye')} |
true |
${anyMatchingAttribute(".*"):isNull()} |
false |
allMatchingAttributes
检查给定属性中是否有任何与给定条件匹配。此函数没有主语,它接受一个或多个正则表达式参数以与属性名匹配。任何名称与提供的正则表达式之一匹配的属性都将根据表达式的其余部分进行计算。如果在对表达式的其余部分求值时,指定的所有属性都返回值“true”,则此函数将返回“true”。否则,此函数将返回“false”。相当于多个属性(能够与正则表达式相匹配)分别求值再进行"与"计算。
例子:有三对属性: "abc" => "hello world", "xyz" => "good bye world", "filename" => "file.txt" ,
表达式 | 返回值 |
---|---|
${allMatchingAttributes("[ax].*"):contains("world")} |
true |
${allMatchingAttributes(".*"):isNull()} |
false |
${allMatchingAttributes("f.*"):count()} |
1 |
anyDelineatedValue
根据提供的分隔符拆分字符串,然后根据表达式的其余部分计算每个值。如果表达式在对任何单个值求值时返回“true”,则此函数返回“true”。否则,函数返回“false”。第一个参数,被拆分的字符串。第二个参数,分隔符。
例子: "number_list" =>"1,2,3,4,5", "word_list" =>"the,and,or,not",
表达式 | 返回值 |
---|---|
${anyDelineatedValue("${number_list}", ","):contains("5")} |
true |
${anyDelineatedValue("this that and", ","):equals("${word_list}")} |
false |
allDelineatedValues
根据提供的分隔符将字符串拆分,然后根据表达式的其余部分计算每个值。如果表达式在对所有单个值求值时,在每种情况下都返回“true”,则此函数返回“true”。否则,函数返回“false”。第一个参数,被拆分的字符串。第二个参数,分隔符。
例子: "number_list" =>"1,2,3,4,5", "word_list" =>"the,and,or,not",
Expression | Value |
---|---|
${allDelineatedValues("${word_list}", ","):contains("o")} |
true |
${allDelineatedValues("${number_list}", ","):count()} |
4 |
${allDelineatedValues("${number_list}", ","):matches("[0-9]+")} |
true |
${allDelineatedValues("${word_list}", ","):matches('e')} |
false |
join
用指定的分隔符连接多个值的聚合函数。此函数只能与“allAttributes”、“allMatchingAttributes”和“allresourcedvalues”函数一起使用。
例子: "abc" => "hello world", "xyz" => "good bye world", "filename" => "file.txt",
表达式 | 返回值 |
---|---|
${allMatchingAttributes("[ax].*"):substringBefore(" "):join("-")} |
hello-good |
${allAttributes("abc", "xyz"):join(" now")} |
hello world nowgood bye world now |
count
一个聚合函数,用于统计“allAttributes”、“allMatchingAttributes”和“allresourcedvalues”返回的非null、非false值的数量。此函数只能与“allAttributes”、“allMatchingAttributes”和“allresourcedvalues”函数一起使用。
例子: "abc" => "hello world", "xyz" => "good bye world", "number_list" => "1,2,3,4,5",
表达式 | 返回值 |
---|---|
${allMatchingAttributes("[ax].*"):substringBefore(" "):count()} |
2 |
${allAttributes("abc", "xyz"):contains("world"):count()} |
1 |
${allDelineatedValues(${number_list}, ","):count()} |
5 |
${allAttributes("abc", "non-existent-attr", "xyz"):count()} |
2 |
${allMatchingAttributes(".*"):length():gt(10):count()} |
2 |
网友评论