Build VoltSP streaming pipelines using YAML configuration — no Java compilation needed. Define sources, processors, and sinks in a single file and run with one command.
Welcome! In this quickstart you'll build a VoltSP pipeline entirely in YAML — no Java, no compilation, no JAR files.
VoltSP pipelines follow a simple three-stage pattern:
A Source produces data. Processors transform each record. A Sink consumes the output. You define all three in one YAML file and run it with a single command.
This pipeline has a collection source that emits five greeting strings, a simple processor that appends a newline (stdout doesn't add one automatically), and a stdout sink.
Every YAML pipeline needs four fields:
version: 1 # Required - must be 1
name: "pipeline-name" # Required - pipeline identifier
source: {} # Required - where data comes from
sink: {} # Required - where data goes
The collection source is a fixed list of strings — perfect for testing. The stdout sink prints each record to the console.
Save the following as hello-pipeline.yaml:
version: 1
name: "hello-pipeline"
source:
collection:
elements:
- "Hello, Alice!"
- "Hello, Bob!"
- "Hello, Charlie!"
- "Hello, Diana!"
- "Hello, Eve!"
processors:
- javascript:
script: |
function process(input) {
return input + "\n";
}
sink:
stdout: {}
voltsp hello-pipeline.yaml
Hello, Alice! Hello, Bob! Hello, Charlie! Hello, Diana! Hello, Eve!
Now let's transform the data. Replace the processors section to convert each greeting to uppercase:
processors:
- javascript:
script: |
function process(input) {
return input.toUpperCase() + "\n";
}
Processors are an array — you can chain multiple. Each receives the output of the previous stage. YAML pipelines support JavaScript, Python, and Ruby processors.
HELLO, ALICE! HELLO, BOB! HELLO, CHARLIE! HELLO, DIANA! HELLO, EVE!
Return null from a processor to drop the record:
processors:
- javascript:
script: |
function process(input) {
if (input.includes("Eve")) return null;
return input.toUpperCase() + "\n";
}
Now let's switch from a static collection to a live Kafka topic. This requires changing both the source and the processor — Kafka delivers records as Java KafkaRequest objects (not plain strings), so the processor must decode the ByteBuffer.
Save the following as kafka-pipeline.yaml:
version: 1
name: "kafka-pipeline"
source:
kafka:
bootstrapServers:
- "localhost:9092"
topicNames:
- "greetings"
groupId: "quickstart-group"
startingOffset: "EARLIEST"
properties:
fetch.max.wait.ms: "100"
fetch.min.bytes: "1"
max.poll.records: "1"
processors:
- javascript:
script: |
function process(input) {
var Charset = Java.type(
"java.nio.charset.StandardCharsets");
var str = Charset.UTF_8
.decode(input.getValue()).toString();
return str.toUpperCase() + "\n";
}
sink:
stdout: {}
Key differences from the collection pipeline:
source.kafka — connects to a Kafka broker and subscribes to topicsinput.getValue() — extracts the raw ByteBuffer from the KafkaRequestCharset.UTF_8.decode() — converts the ByteBuffer to a stringFirst, create the Kafka topic and run the pipeline:
kafka-topics.sh --create --topic greetings --bootstrap-server localhost:9092 voltsp kafka-pipeline.yaml
In another terminal, send messages to the greetings topic:
kafka-console-producer.sh --topic greetings \ --bootstrap-server localhost:9092 > Hello, World! > Hi from Kafka! > Greetings, VoltSP!
HELLO, WORLD! HI FROM KAFKA! GREETINGS, VOLTSP!
Finally, replace stdout with a VoltDB stored procedure sink. This requires two changes:
resources block that defines a VoltDB client connectionvoltdb-procedure sink that references the resourceAdd this before the source section:
resources:
- name: "voltdb"
voltdb-client:
servers:
- "localhost:21212"
Replace the sink section:
sink:
voltdb-procedure:
voltClientResource: "voltdb"
The voltdb-procedure sink calls a stored procedure for each record. The processor must return a VoltProcedureRequest Java object.
The processor must create a VoltProcedureRequest using Java interop. Use Java.type() to import the class, decode the Kafka ByteBuffer to a string, then construct the request:
processors:
- javascript:
script: |
var VoltProcedureRequest = Java.type(
"org.voltdb.stream.plugin.volt.api.VoltProcedureRequest");
var Charset = Java.type(
"java.nio.charset.StandardCharsets");
function process(input) {
var str = Charset.UTF_8
.decode(input.getValue()).toString();
var parts = str.split("|");
var sender = parts[0] || "unknown";
var recipient = parts[1] || "unknown";
var message = parts[2] || str;
console.log(
"[GREETING] " + sender +
" -> " + recipient +
": " + message);
var params = Java.to(
[sender, recipient, message,
java.lang.System.currentTimeMillis()],
"java.lang.Object[]");
return new VoltProcedureRequest(
"InsertGreeting", params);
}
Before deploying, create the greetings table and stored procedure in VoltDB:
CREATE TABLE greetings ( sender VARCHAR(64) NOT NULL, recipient VARCHAR(64) NOT NULL, message VARCHAR(256) NOT NULL, greeting_time TIMESTAMP DEFAULT NOW ); PARTITION TABLE greetings ON COLUMN sender; CREATE PROCEDURE InsertGreeting PARTITION ON TABLE greetings COLUMN sender AS INSERT INTO greetings (sender, recipient, message, greeting_time) VALUES (?, ?, ?, TO_TIMESTAMP(MILLISECOND, ?));
Save the following as kafka-to-voltdb.yaml:
version: 1
name: "kafka-to-voltdb"
resources:
- name: "voltdb"
voltdb-client:
servers:
- "localhost:21212"
source:
kafka:
bootstrapServers:
- "localhost:9092"
topicNames:
- "greetings"
groupId: "quickstart-group"
startingOffset: "EARLIEST"
properties:
fetch.max.wait.ms: "100"
fetch.min.bytes: "1"
max.poll.records: "1"
processors:
- javascript:
script: |
var VoltProcedureRequest = Java.type(
"org.voltdb.stream.plugin.volt.api.VoltProcedureRequest");
var Charset = Java.type(
"java.nio.charset.StandardCharsets");
function process(input) {
var str = Charset.UTF_8
.decode(input.getValue()).toString();
var parts = str.split("|");
var sender = parts[0] || "unknown";
var recipient = parts[1] || "unknown";
var message = parts[2] || str;
console.log(
"[GREETING] " + sender +
" -> " + recipient +
": " + message);
var params = Java.to(
[sender, recipient, message,
java.lang.System.currentTimeMillis()],
"java.lang.Object[]");
return new VoltProcedureRequest(
"InsertGreeting", params);
}
sink:
voltdb-procedure:
voltClientResource: "voltdb"
Deploy the pipeline, then send pipe-delimited messages (sender|recipient|message) to the greetings Kafka topic:
kafka-console-producer.sh --topic greetings --bootstrap-server localhost:9092 > Alice|Bob|Hello from the stream! > Charlie|Diana|VoltSP is working!
Verify the data arrived in VoltDB:
SELECT * FROM greetings ORDER BY greeting_time DESC;
SENDER RECIPIENT MESSAGE GREETING_TIME -------- ---------- ---------------------------- -------------------------- Alice Bob Hello from the stream! 2024-02-06 12:34:56.789000 Charlie Diana VoltSP is working! 2024-02-06 12:34:57.123000
Your pipeline is ready! Run it with a single command:
voltsp kafka-to-voltdb.yaml
Ready for more? Switch to the Advanced tutorial to learn Java pipelines with the full VoltSP SDK, type safety, and production patterns.