The MaxCompute Java SDK provides three methods for downloading table data: TableTunnel for bulk partition downloads, InstanceTunnel for SQL query results by instance ID, and SQLTask.getResultSet() for lightweight result iteration without explicit session management.
Choose a download method
| Method | Best for | Key class |
|---|---|---|
| TableTunnel | Bulk downloads from a table or partition | TableTunnel.DownloadSession |
| InstanceTunnel | Downloading results of an already-run SQL instance | InstanceTunnel.DownloadSession |
| SQLTask.getResultSet() | Simple result iteration without explicit session management | ResultSet |
Prerequisites
Before you begin, make sure you have:
The MaxCompute Java SDK added to your project dependencies
An Alibaba Cloud account with access to a MaxCompute project
Your
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETset as environment variables
Download data with TableTunnel
TableTunnel provides direct, high-throughput access to table data. The download follows three steps:
Create a
TableTunnelinterface.Create a
DownloadSessionobject.Create a
RecordReaderobject and iterate records.
Connection parameters
| Parameter | Description | Example value |
|---|---|---|
odpsUrl | MaxCompute service endpoint | http://service.odps.aliyun.com/api |
tunnelUrl | Tunnel endpoint for your region and network type. Defaults to the public internet. Set this to an intranet endpoint when transferring data over an internal network. | https://dt.cn-shanghai-intranet.maxcompute.aliyun-inc.com |
project | Your MaxCompute project name | <your project> |
table | The table to download from | <your table name> |
partition | The partition specification | <your partition spec> |
For all available endpoints by region and network type, see Endpoints.
Example
The following code demonstrates the three-step download flow: create a tunnel, open a download session, and read records column by column.
import java.io.IOException;
import java.util.Date;
import com.aliyun.odps.Column;
import com.aliyun.odps.Odps;
import com.aliyun.odps.PartitionSpec;
import com.aliyun.odps.TableSchema;
import com.aliyun.odps.account.Account;
import com.aliyun.odps.account.AliyunAccount;
import com.aliyun.odps.data.Record;
import com.aliyun.odps.data.RecordReader;
import com.aliyun.odps.tunnel.TableTunnel;
import com.aliyun.odps.tunnel.TableTunnel.DownloadSession;
import com.aliyun.odps.tunnel.TunnelException;
public class DownloadSample {
// Load credentials from environment variables to avoid hardcoding sensitive values.
// Use a RAM user with the minimum required permissions for production workloads.
private static String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
private static String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
private static String odpsUrl = "http://service.odps.aliyun.com/api";
// Set tunnelUrl to an intranet endpoint when transferring data over an internal network.
private static String tunnelUrl = "https://dt.cn-shanghai-intranet.maxcompute.aliyun-inc.com";
private static String project = "<your project>";
private static String table = "<your table name>";
private static String partition = "<your partition spec>";
public static void main(String args[]) {
Account account = new AliyunAccount(accessId, accessKey);
Odps odps = new Odps(account);
odps.setEndpoint(odpsUrl);
odps.setDefaultProject(project);
// Step 1: Create the TableTunnel interface.
TableTunnel tunnel = new TableTunnel(odps);
tunnel.setEndpoint(tunnelUrl);
PartitionSpec partitionSpec = new PartitionSpec(partition);
try {
// Step 2: Create a DownloadSession for the specified table and partition.
DownloadSession downloadSession = tunnel.createDownloadSession(project, table, partitionSpec);
System.out.println("Session Status is : " + downloadSession.getStatus().toString());
long count = downloadSession.getRecordCount();
System.out.println("RecordCount is: " + count);
// Step 3: Open a RecordReader and iterate all records.
RecordReader recordReader = downloadSession.openRecordReader(0, count);
Record record;
while ((record = recordReader.read()) != null) {
consumeRecord(record, downloadSession.getSchema());
}
recordReader.close();
} catch (TunnelException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
// Read each column value from a record and print it.
// Each column type requires a different getter method. Unrecognized types throw a RuntimeException.
private static void consumeRecord(Record record, TableSchema schema) {
for (int i = 0; i < schema.getColumns().size(); i++) {
Column column = schema.getColumn(i);
String colValue = null;
// Dispatch to the appropriate typed getter based on the column's data type.
switch (column.getType()) {
case BIGINT: {
Long v = record.getBigint(i);
colValue = v == null ? null : v.toString();
break;
}
case BOOLEAN: {
Boolean v = record.getBoolean(i);
colValue = v == null ? null : v.toString();
break;
}
case DATETIME: {
Date v = record.getDatetime(i);
colValue = v == null ? null : v.toString();
break;
}
case DOUBLE: {
Double v = record.getDouble(i);
colValue = v == null ? null : v.toString();
break;
}
case STRING: {
String v = record.getString(i);
colValue = v == null ? null : v.toString();
break;
}
default:
throw new RuntimeException("Unknown column type: " + column.getType());
}
System.out.print(colValue == null ? "null" : colValue);
if (i != schema.getColumns().size())
System.out.print("\t");
}
System.out.println();
}
}ThetunnelUrlin this example uses the cloud product interconnection network endpoint for the China (Shanghai) region. For endpoints in other regions and network types, see Endpoints. This example usesSystem.out.printlnto print records for testing purposes. In production, modifyconsumeRecord()to write data to a file or downstream system instead.
Download data with InstanceTunnel
Use InstanceTunnel to download results from a SQL instance you have already run. Create a DownloadSession from the instance ID, then read records the same way as with TableTunnel.
// Initialize a MaxCompute object.
Odps odps = OdpsUtils.newDefaultOdps();
// Run a SQL query and wait for it to complete.
Instance i = SQLTask.run(odps, "select * from wc_in;");
i.waitForSuccess();
// Create an InstanceTunnel and open a DownloadSession using the instance ID.
InstanceTunnel tunnel = new InstanceTunnel(odps);
InstanceTunnel.DownloadSession session = tunnel.createDownloadSession(odps.getDefaultProject(), i.getId());
// Get the total number of records to read.
long count = session.getRecordCount();
System.out.println(count);
// Read records column by column — same pattern as TableTunnel.
TunnelRecordReader reader = session.openRecordReader(0, count);
Record record;
while ((record = reader.read()) != null) {
for (int col = 0; col < session.getSchema().getColumns().size(); ++col) {
// All fields in wc_in are strings.
System.out.println(record.get(col));
}
}
reader.close();Download data with SQLTask.getResultSet()
SQLTask.getResultSet() returns a ResultSet iterator directly from an instance, without creating an explicit tunnel session. This is simpler for lightweight result retrieval.
// Initialize a MaxCompute object.
Odps odps = OdpsUtils.newDefaultOdps();
// Run a SQL query and wait for it to complete.
Instance i = SQLTask.run(odps, "select * from wc_in;");
i.waitForSuccess();
// Get a ResultSet iterator directly from the instance — no tunnel session required.
ResultSet rs = SQLTask.getResultSet(i);
for (Record r : rs) {
System.out.println(rs.getRecordCount());
for (int col = 0; col < rs.getTableSchema().getColumns().size(); ++col) {
// All fields in wc_in are strings.
System.out.println(r.get(col));
}
}What's next
Endpoints — find the right tunnel endpoint for your region and network type