All Products
Search
Document Center

MaxCompute:Example of simple downloads

Last Updated:Mar 26, 2026

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

MethodBest forKey class
TableTunnelBulk downloads from a table or partitionTableTunnel.DownloadSession
InstanceTunnelDownloading results of an already-run SQL instanceInstanceTunnel.DownloadSession
SQLTask.getResultSet()Simple result iteration without explicit session managementResultSet

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_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET set as environment variables

Download data with TableTunnel

TableTunnel provides direct, high-throughput access to table data. The download follows three steps:

  1. Create a TableTunnel interface.

  2. Create a DownloadSession object.

  3. Create a RecordReader object and iterate records.

Connection parameters

ParameterDescriptionExample value
odpsUrlMaxCompute service endpointhttp://service.odps.aliyun.com/api
tunnelUrlTunnel 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
projectYour MaxCompute project name<your project>
tableThe table to download from<your table name>
partitionThe 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();
    }
}
The tunnelUrl in 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 uses System.out.println to print records for testing purposes. In production, modify consumeRecord() 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