This example shows how to write a Java user-defined table-valued function (UDTF) that reads file resources and table resources from MaxCompute, using MaxCompute Studio. You will run the UDTF locally in the IDE, then deploy and call it from the MaxCompute client.
Prerequisites
Before you begin, make sure you have:
-
MaxCompute Studio installed and connected to a MaxCompute project, with a Java module created. See Install MaxCompute Studio, Manage project connections, and Create a MaxCompute Java module
-
IntelliJ IDEA 2024 and JDK 1.8 installed
How the UDTF works
A MaxCompute Java UDTF handler class uses two lifecycle methods:
| Method | When called | Purpose |
|---|---|---|
setup(ExecutionContext ctx) |
Once, before any row is processed | Load resources (files, tables) into memory |
process(Object[] args) |
Once per input row | Emit output rows using forward() |
Loading resources in setup instead of process means each resource is read once and reused across all rows — this is the recommended pattern for file and table resources.
Resource reading API
The ExecutionContext class provides two methods for reading MaxCompute resources:
| Method | Resource type | Returns |
|---|---|---|
ctx.readResourceFileAsStream(name) |
File resource | InputStream — read line by line using a BufferedReader |
ctx.readResourceTable(name) |
Table resource | Iterable<Object[]> — iterate over records |
UDTF code
The UDTF below takes two string inputs and outputs three columns. In setup, it reads one file resource (file_resource.txt) and two table resources (table_resource1, table_resource2). In process, it forwards the input values alongside the line and record counts loaded during setup.
Input and output parameters:
| Direction | Type | Description |
|---|---|---|
| Input | String | First input parameter |
| Input | String | Second input parameter |
| Output | String | Value of the first input parameter |
| Output | BIGINT | Length of the second input parameter string |
| Output | String | Concatenated record counts from file_resource.txt, table_resource1, and table_resource2 |
UDTF class (`UDTFResource`):
package com.aliyun.odps.examples.udf;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import com.aliyun.odps.udf.ExecutionContext;
import com.aliyun.odps.udf.UDFException;
import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.annotation.Resolve;
/**
* project: example_project
* table: wc_in2
* partitions: p1=2,p2=1
* columns: cola,colc
*/
@Resolve("string,string->string,bigint,string")
public class UDTFResource extends UDTF {
ExecutionContext ctx;
long fileResourceLineCount;
long tableResource1RecordCount;
long tableResource2RecordCount;
@Override
public void setup(ExecutionContext ctx) throws UDFException {
this.ctx = ctx;
try {
InputStream in = ctx.readResourceFileAsStream("file_resource.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
fileResourceLineCount = 0;
while ((line = br.readLine()) != null) {
fileResourceLineCount++;
}
br.close();
Iterator<Object[]> iterator = ctx.readResourceTable("table_resource1").iterator();
tableResource1RecordCount = 0;
while (iterator.hasNext()) {
tableResource1RecordCount++;
iterator.next();
}
iterator = ctx.readResourceTable("table_resource2").iterator();
tableResource2RecordCount = 0;
while (iterator.hasNext()) {
tableResource2RecordCount++;
iterator.next();
}
} catch (IOException e) {
throw new UDFException(e);
}
}
@Override
public void process(Object[] args) throws UDFException {
String a = (String) args[0];
long b = args[1] == null ? 0 : ((String) args[1]).length();
forward(a, b, "fileResourceLineCount=" + fileResourceLineCount + "|tableResource1RecordCount="
+ tableResource1RecordCount + "|tableResource2RecordCount=" + tableResource2RecordCount);
}
}
`pom.xml` dependency for local testing:
<dependency>
<groupId>com.aliyun.odps</groupId>
<artifactId>odps-udf-local</artifactId>
<version>0.48.0-public</version>
</dependency>
Local testing
-
In MaxCompute Studio, create a new Java class of the UDTF type. Name the class
UDTFResourceand paste the UDTF code from UDTF code. -
Configure the runtime parameters using the warehouse resource in the Java module.
The input parameters are the values of the first and third columns (
colaandcolc) of each row in partitionp1=2, p2=1of thewc_in2table in the local resource. The code readsfile_resource.txtfrom the file resource,table_resource1(mapped towc_in1), andtable_resource2(mapped towc_in2withp1=2, p2=1).
-
Right-click the UDTFResource class and select Run. The results appear in the output panel.


Deploy and test with the MaxCompute client
Step 1: Add the file resource
In the upper-left corner of IDEA, click
Project Explorer and select
Add Resource.
Add file_resource.txt based on the MaxCompute instance information.
Step 2: Create sample tables and insert data
Create the sample tables wc_in1 and wc_in2 in the MaxCompute project and insert data.
CREATE TABLE wc_in1 (
col1 STRING,
col2 STRING,
col3 STRING,
col4 STRING
);
INSERT INTO wc_in1 VALUES
('A1','A2','A3','A4'),
('A1','A2','A3','A4'),
('A1','A2','A3','A4'),
('A1','A2','A3','A4');
CREATE TABLE wc_in2 (
cola STRING,
colb STRING,
colc STRING
) PARTITIONED BY (p1 STRING, p2 STRING);
ALTER TABLE wc_in2 ADD PARTITION (p1='2',p2='1');
INSERT INTO wc_in2 PARTITION (p1='2',p2='1') VALUES
('three1','three2','three3'),
('three1','three2','three3'),
('three1','three2','three3');
Step 3: Add table resources
Map wc_in1 to table_resource1 and wc_in2 to table_resource2 in Resource.
Add the wc_in1 resource:
Add the wc_in2 resource:
Step 4: Package and deploy the UDTF
Right-click the UDTFResource class and select Deploy to Server... to open the packaging interface. In the Extra resources section, include file_resource.txt, table_resource1, and table_resource2. Set the function name to my_udtf.
Step 5: Call the UDTF from the client
In the upper-left corner of IDEA, click
Project Explorer, right-click the MaxCompute project, and select Open Console. Run the following SQL command to call the UDTF:
SELECT my_udtf("10","20") AS (a, b, fileResourceLineCount);
The results appear in the console.

UDTF code requirements
A valid MaxCompute Java UDTF must meet the following requirements:
-
The class must extend
UDTF. -
The class must be annotated with
@Resolve, specifying input and output types in the format"input_types->output_types". -
The class must implement the
process(Object[] args)method and callforward()to emit output rows. -
All file and table resources used in the UDTF must be declared in the Extra resources section when deploying with Deploy to Server....