Skip to main content
vnv
Gold ⭐️
Gold ⭐️
May 25, 2016

Python Script in NiFi

  • October 5, 2026 at 8:48 AM
  • 12 replies
  • 123870 views
  • Translate All

In NiFi the data being passed between operators is referred to as a FlowFile and can be accessed via various scripting languages in the ExecuteScript operator.

In order to access the data in the FlowFile you need to understand a few requirements first.

In this example we will access the json data being passed into the ExecuteScript operator via a getTwitter operator.

This could be any data ingestion operator.

4528-screen-shot-2016-05-25-at-103502-am.png

Using the ExecuteScript (Note: Execute script will use Jython libraries which are good but limited. If you have a python script which uses other libs and produces an output you can use Execute Process instead which will execute the python script on the machine using the full python lib and the output will become your flow file. )  operator set the script type to python and in the "script body" section enter the following code:

4530-screen-shot-2016-05-25-at-104804-am.png

import json
import java.io
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback

class ModJSON(StreamCallback):
def __init__(self):
pass
def process(self, inputStream, outputStream):
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
obj = json.loads(text)
newObj = {
"Source": "NiFi",
"ID": obj['id'],
"Name": obj['user']['screen_name']
}
outputStream.write(bytearray(json.dumps(newObj, indent=4).encode('utf-8')))

flowFile = session.get()
if (flowFile != None):
flowFile = session.write(flowFile, ModJSON())
flowFile = session.putAttribute(flowFile, "filename", flowFile.getAttribute('filename').split('.')[0]+'_translated.json')
session.transfer(flowFile, REL_SUCCESS)
session.commit()

the import statements are required to take advantage of the NiFi components.

The way we actually access the flowfile is through a global variable available to you in NiFi called "session".

As you can see:

flowFile = session.get()

is how we grab the IOStream from NiFi and the pass to the processing Class via the session.write() method.

You can build up a new JSON object while referencing attributes from the source JSON as you can see in the script:

newObj = {
"Source": "NiFi",
"ID": obj['id'],
"Name": obj['user']['screen_name']
}

This should help you get started with using python scripts inside of NiFi.

I hope to see some posts of how you modify this to create more interesting flows.

12 replies

raghav130593
Silver ⭐️⭐️⭐️
August 17, 2016

Hi,

Thank you very much for the tutorial. I am new to Nifi and trying out some use cases. I followed your steps to write a Jython script where I read from an xml file(rss) and then convert it into a string and write to outputStream and routed to putFile. The problem I am facing is that the data is getting queued in the connection to ExecuteScript and not getting into the processor. I am posting the code I wrote here in the ExecuteScript Script body. Did I need to point it to a module directory?

import xml.etree.ElementTree as ET
import java.io
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback
class xmlParser(StreamCallback):
def __init__(self):
pass
def process(self,inputStream,outputStream):
text= IOUtils.ToString(inputStream,StandardCharsets.UTF_8)
xmlRoot = ET.fromstring(text);
extracted_list=[]
for elmnts in xmlRoot.fromall('item'):
title= elmnts.find("title").text
description = elmnts.find("description").text
extracted_list.append(title)
extracted_list.append(description)
str_extract = ''.join(extracted_list)
outputStream.write(bytearray(str_extract.encode('utf-8')))

flowFile = session.get()
if(flowFile!=None):
flowFile = session.write(flowFile,xmlParser())
flowFile = session.putAtrribute(flowFile, 'filename', 'rss_feed.xml')
session.transfer(flowFile, REL_SUCCESS)
session.commit()


If you can help me with this, it would be great.

6679-nifi-capture.png

Translate
vnv
Gold ⭐️
vnvAuthor
Gold ⭐️
August 18, 2016

That is strange. I see that you loop the failures back into the script processor. Can you delete that and route failure and success to the PutFile processor?

Translate
raghav130593
Silver ⭐️⭐️⭐️
August 18, 2016

I did as you said but to no avail. It's the same. And, there's nothing populating the bulletin board for me to debug.

Translate
vnv
Gold ⭐️
vnvAuthor
Gold ⭐️
August 22, 2016

It looks like flowFile.get() is in a method in a class All that script does is define a class and exit. Gotta move the indents so the flowFile.get() block is outside the class definition (so no indent at all). That might fix the issue.

Translate
celalettin1286
Gold ⭐️
August 19, 2016

Hi

We are experiencing trouble in flowFile = session.write(flowFile, ModJSON()) that line.

javax.script.ScriptException: TypeError: write(): 1st arg can't be coerced to int , byte[] in <script> at line number 64

Do you think what is the problem:

import json
import java.io
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback




class ModJSON(StreamCallback):


def __init__(self):
pass


def process(self, inputStream, outputStream):
text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
obj = json.loads(text)
endorsements = obj['endorsement'].split(',')
categoryIds = obj['categoryIds'].split(',')
orderItemIds = obj['orderItemIds'].split(',')
seq_num = 0
seq_num1 = 1
for endorsement in endorsements:
if seq_num == 0 and seq_num1 == len(endorsements):
newObj = '[{"endorsement":' + endorsement \
+ ',"eventId":"' + obj['eventId'] \
+ '", "categoryId":"' + categoryIds[seq_num] \
+ '", "createDate":"' + obj['createDate'] \
+ '", "buyerId":"' + obj['buyerId'] \
+ '", "channel":"' + obj['channel'] + '", "city":"' \
+ obj['city'] + '", "orderItemId": "'+orderItemIds[seq_num]+'"}]'
seq_num += 1
seq_num1 += 1
elif seq_num == 0:
newObj = '[{"endorsement":' + endorsement + ',"eventId":"' \
+ obj['eventId'] + '", "categoryId":"' \
+ categoryIds[seq_num] + '", "createDate":"' \
+ obj['createDate'] + '", "buyerId":"' \
+ obj['buyerId'] + '", "channel":"' + obj['channel'
] + '", "city":"' + obj['city'] + '", "orderItemId": "'+orderItemIds[seq_num]+'"},'
seq_num += 1
seq_num1 += 1
elif seq_num1 == len(endorsements) :
newObj += '{"endorsement":' + endorsement + ',"eventId":"' \
+ obj['eventId'] + '", "categoryId":"' \
+ categoryIds[seq_num] + '", "createDate":"' \
+ obj['createDate'] + '", "buyerId":"' \
+ obj['buyerId'] + '", "channel":"' + obj['channel'
] + '", "city":"' + obj['city'] + '", "orderItemId": "'+orderItemIds[seq_num]+'"}]'
seq_num += 1
seq_num1 += 1
else:
newObj += '{"endorsement":' + endorsement + ',"eventId":"' \
+ obj['eventId'] + '", "categoryId":"' \
+ categoryIds[seq_num] + '", "createDate":"' \
+ obj['createDate'] + '", "buyerId":"' \
+ obj['buyerId'] + '", "channel":"' + obj['channel'
] + '", "city":"' + obj['city'] + '", "orderItemId": "'+orderItemIds[seq_num]+'"},'
seq_num += 1
seq_num1 += 1
outputStream.write(bytearray(newObj.encode('utf-8')))




flowFile = session.get()
if flowFile != None:
flowFile = session.write(flowFile, ModJSON())
flowFile = session.putAttribute(flowFile, 'filename',
flowFile.getAttribute('filename'
).split('.')[0] + '_translated.json'
)
session.transfer(flowFile, REL_SUCCESS)
session.commit()

Translate
lvaldeavellano
Silver ⭐️⭐️⭐️
September 1, 2016

Hi,

My flowFile seems to be null although its being generated in a previous GetFile processor. Creating a script like yours logs me a NullPointerException error in the session.transfer line as flowFile appears to be null. I modified the script to log and in the logs I'm seeing that the flowfile seems to be null. What workaround can I make?

flowFile = session.get()
if (flowFile != None):
log.info('is not null') # This is not being logged
flowFile = session.write(flowFile, ModJSON())
else:
log.info('is null') # This is being logged

session.transfer(flowFile, REL_SUCCESS) # NullPointerException thrown here
session.commit()

Translate
soharshanky
Silver ⭐️
October 19, 2016

In the example above, ExecuteScript Processor is showing some error and write is zero bytes from it.

GetTwitter (In: 0/0 bytes)

ExecuteScript (In: 0/0 bytes)

PutFile (In : 738 /59.59 KB) How ?

Is this example working.

Translate
omeralvi
Gold ⭐️
March 23, 2017

Hi @Vasilis Vagias

Great article.

I am scraping facebook page contents using python and want to used executescript processor to get all the posts returned by python function and pass it on to solr processor for indexing. Currently I am writing the contents returned by facebook in a file and I want to put those contents to the output stream instead and pass on to next processsor.Can you please share the steps with regards to the example given in your article?

Can I used outputstream object in any python function and use it for writing records; I don't think creating inner class is mandatory. Also, does it allow writerow () kind of functionality ?

Appreciate showing me the way here. Thanks.

Translate
pallavi_abhang
Silver ⭐️⭐️
February 10, 2018
@Vasilis Vagias

I am trying to create a data flow with nifi using python scripts. To begin the process I used ExecuteProcess processor and to execute subsequent scripts I am trying to use ExecuteScript processor.as I need to build dependency between my flow. I want the subsequent job to run only if the dependent job executes successfully.

However, I see that the 'ExecuteProcess' jobs runs successfully but the subsequent 'ExecuteScript' jobs does not starts. I also see the relationship queue is empty. How can I make the flow run successfully.

Here are the screenshots for your reference:

60486-capture.png

60487-capture.png

Translate
turker_tunali
Gold ⭐️
April 27, 2019

Hello @Vasilis Vagias, some other tutorials state that "NOTE: ExecuteScript will perform a session.commit() at the end of each execution to ensure the operations have been committed. You do not need to (and should not) perform a session.commit() within the script." (Source:Link )

Do we really need to use commit statement?

Translate
shashank_naresh
Gold ⭐️
June 13, 2019

Thank you @Vasilis Vagias

Translate
zenkovac
Silver ⭐️
March 11, 2022

hi, this isn't working as it is on nifi 1.14, can you give me a hand please?

i used a "generateFlowfile" with some random text, and connected to executeScript but get the following:

 

ExecuteScript[id=78c5739f-017f-1000-0000-0000016ca301] ExecuteScript[id=78c5739f-017f-1000-0000-0000016ca301] failed to process due to javax.script.ScriptException: java.lang.NullPointerException: java.lang.NullPointerException in <script> at line number 25; rolling back session: java.lang.NullPointerException ↳ causes: Traceback (most recent call last): File "<script>", line 25, in <module> java.lang.NullPointerException java.lang.NullPointerException: java.lang.NullPointerException ↳ causes: javax.script.ScriptException: java.lang.NullPointerException: java.lang.NullPointerException in <script> at line number 25 ↳ causes: org.apache.nifi.processor.exception.ProcessException: javax.script.ScriptException: java.lang.NullPointerException: java.lang.NullPointerException in <script> at line number 25

Translate