All Products
Search
Document Center

MaxCompute:Dokumen

Last Updated:Mar 26, 2026

MaxCompute memperkenalkan user-defined types (UDT) berdasarkan mesin SQL generasi baru. UDT memungkinkan Anda mereferensikan kelas atau objek dari bahasa pemrograman pihak ketiga dalam pernyataan SQL untuk memanggil metode atau mengambil data.

Kapan menggunakan UDT dibandingkan UDF

Baik UDT maupun user-defined functions (UDF) memperluas MaxCompute SQL dengan logika kustom. Pilih pendekatan berdasarkan alur kerja Anda:

SituasiPendekatan yang direkomendasikan
Memanggil metode kelas Java bawaan secara langsung (misalnya, Integer.MAX_VALUE)UDT — tidak memerlukan definisi fungsi
Menggunakan kembali pustaka pihak ketiga secara langsung dalam ekspresi SQLUDT — mereferensikan kelas secara inline tanpa pembungkus
Menyertakan objek bahasa sumber terkompilasi di berbagai tahap pekerjaanUDT — secara otomatis mengenkapsulasi status JVM lintas tahap
Menerapkan logika bisnis yang dapat digunakan ulang di beberapa proyekUDF — pendaftaran fungsi eksplisit memungkinkan penggunaan bersama

Kasus penggunaan

  • Memanggil metode pustaka standar Java tanpa mendefinisikan fungsi. Ketika suatu tugas memerlukan metode kelas Java bawaan yang tidak diekspos secara native oleh MaxCompute SQL, UDT memungkinkan Anda memanggilnya langsung dalam ekspresi.

  • Mereferensikan pustaka pihak ketiga secara inline. Alih-alih membungkus fungsi pustaka pihak ketiga di dalam UDF, referensikan kelas tersebut langsung dalam pernyataan SQL.

  • Menyematkan kode sumber terkompilasi dalam SQL. Untuk bahasa seperti Java yang memerlukan kompilasi, UDT memungkinkan Anda mereferensikan objek dan kelas dalam ekspresi SQL tanpa langkah pendaftaran terpisah. Lihat SELECT TRANSFORM untuk alternatif berbasis skrip.

Prasyarat

Sebelum menggunakan UDT, pastikan bahwa:

  • JDK 1.8 tersedia di lingkungan Anda. Versi yang lebih baru dari JDK 1.8 mungkin tidak didukung.

  • Tipe data baru diaktifkan jika Anda menggunakan tipe seperti INT: set odps.sql.type.system.odps2=true;

Cara kerja

Berbeda dengan UDT pada mesin SQL lainnya (yang biasanya mendefinisikan alias tipe mirip tipe STRUCT), UDT MaxCompute bekerja seperti pernyataan CREATE TYPE — mencakup bidang dan metode, serta Anda mereferensikannya langsung dalam SQL tanpa menulis DDL.

Contoh berikut menggambarkan perbedaannya. Untuk mengakses Integer.MAX_VALUE dari paket java.lang Java:

Menggunakan UDT (referensi langsung):

-- Aktifkan tipe data baru (diperlukan untuk tipe seperti INTEGER).
set odps.sql.type.system.odps2=true;
SELECT java.lang.Integer.MAX_VALUE;

Karena java.lang diimpor otomatis (seperti di Java), ini setara dengan:

set odps.sql.type.system.odps2=true;
SELECT Integer.MAX_VALUE;

Hasil:

+-----------+
| max_value |
+-----------+
| 2147483647 |
+-----------+

Menggunakan UDF (untuk perbandingan):

  1. Tulis kelas UDF:

    package com.aliyun.odps.test;
    public class IntegerMaxValue extends com.aliyun.odps.udf.UDF {
      public Integer evaluate() {
         return Integer.MAX_VALUE;
      }
    }
  2. Kompilasi, unggah, dan daftarkan:

    add jar odps-test.jar;
    create function integer_max_value as 'com.aliyun.odps.test.IntegerMaxValue' using 'odps-test.jar';
  3. Panggil:

    select integer_max_value();

UDT menyederhanakan proses ini menjadi satu pernyataan SQL.

Eksekusi multi-tahap

Objek UDT mengalir secara alami melalui tahap MapReduce. Contoh berikut melakukan join dua kolom BigInteger yang dihitung dari sumber data berbeda:

-- Data contoh.
@table1 := select * from values ('100000000000000000000') as t(x);
@table2 := select * from values (100L) as t(y);

-- Buat objek dengan metode baru.
@a := select new java.math.BigInteger(x) x from @table1;
-- Panggil metode statis.
@b := select java.math.BigInteger.valueOf(y) y from @table2;
-- Panggil metode instans melalui join.
select /*+mapjoin(b)*/ x.add(y).toString() from @a a join @b b;

-- Output:
100000000000000000100

Pekerjaan ini berjalan melalui tiga tahap (M1, R2, J3). new java.math.BigInteger(x) dijalankan di M1; java.math.BigInteger.valueOf(y) dan x.add(y).toString() dijalankan di J3 pada proses dan mesin fisik yang berbeda. UDT mengenkapsulasi hal ini sehingga semua tahap berperilaku seolah-olah berjalan pada Java Virtual Machine (JVM) yang sama.

Kolom x dari variabel a bertipe java.math.BigInteger, bukan tipe bawaan. Nilai UDT ini dapat diteruskan ke operator lain dan digunakan dalam pengacakan data.

Mereferensikan paket JAR dan mengatur impor Java

Semua SDK untuk kelas Java tersedia untuk UDT secara default. Untuk mereferensikan paket JAR tambahan atau mengatur jalur impor default, gunakan flag sesi berikut.

Mereferensikan paket JAR:

set odps.sql.type.system.odps2=true;
set odps.sql.session.resources=odps-test.jar;
-- JAR harus diunggah ke proyek terlebih dahulu.
select new com.aliyun.odps.test.IntegerMaxValue().evaluate();

Anda dapat menentukan beberapa sumber daya yang dipisahkan koma: set odps.sql.session.resources=foo.sh,bar.txt;

odps.sql.session.resources mengontrol baik UDT maupun SELECT TRANSFORM. JAR yang ditetapkan di sini tersedia untuk kedua fitur tersebut.

Mengatur jalur impor Java default:

set odps.sql.type.system.odps2=true;
set odps.sql.session.resources=odps-test.jar;
set odps.sql.session.java.imports=com.aliyun.odps.test.*;
-- Dengan impor yang ditetapkan, Anda dapat menghilangkan awalan paket lengkap.
select new IntegerMaxValue().evaluate();

odps.sql.session.java.imports menerima classpath (misalnya, java.math.BigInteger) atau wildcard (*). Impor statis tidak didukung.

Operasi yang didukung

UDT mendukung operasi berikut dalam ekspresi SQL:

  • Membuat objek menggunakan new — contoh: new java.math.BigInteger('123')

  • Membuat array menggunakan new dengan daftar inisialisasi — contoh: new Integer[] { 1, 2, 3 }

  • Memanggil metode instans dan metode statis

  • Mengakses bidang instans publik dan bidang statis publik

Hanya metode publik dan bidang publik yang dapat diakses. Semua pengenal (nama paket, nama kelas, nama metode, nama bidang) bersifat case-sensitive. Kelas anonim dan ekspresi lambda tidak didukung. Fungsi yang tidak mengembalikan nilai tidak dapat dipanggil dalam ekspresi.

Tipe data

Pemetaan tipe

Tipe data Java dipetakan ke tipe bawaan MaxCompute. Pemetaan yang sama yang digunakan dalam UDF Java berlaku untuk UDT.

  • Panggil metode tipe bawaan secara langsung: '123'.length(), 1L.hashCode()

  • Gunakan UDT dalam fungsi bawaan: chr(Long.valueOf('100'))Long.valueOf mengembalikan java.lang.Long, yang dipetakan ke tipe bawaan BIGINT

  • Tipe primitif Java secara otomatis dikonversi ke tipe boxing-nya

Untuk tipe data bawaan baru, tambahkan set odps.sql.type.system.odps2=true; sebelum menjalankan kueri.

Konversi tipe

  • Konversi tipe SQL didukung: cast(1 as java.lang.Object)

  • Cast bergaya Java tidak didukung: (Object)1

  • Objek UDT dapat dikonversi secara implisit ke objek kelas dasar

  • Objek UDT dapat dikonversi secara eksplisit (cast) ke objek kelas dasar atau subkelas

  • Konversi antara dua tipe yang tidak terkait mengikuti aturan yang sama dengan konversi tipe bawaan. Misalnya, mengonversi java.lang.Long ke java.lang.Integer menerapkan aturan yang sama seperti mengonversi BIGINT ke INT, yang dapat menyebabkan kehilangan data.

Objek UDT tidak dapat disimpan ke disk dan tidak dapat dimasukkan langsung ke tabel (DDL tidak mendukung UDT sebagai tipe kolom). Jika nilai UDT dapat dikonversi secara implisit ke tipe bawaan, nilai tersebut dapat ditulis ke tabel. BINARY mendukung serialisasi otomatis — array byte[] dapat disimpan dan dideserialisasi. Untuk menyimpan UDT secara persisten, konversikan ke BINARY menggunakan metode serialisasi dan deserialisasi. Nilai UDT tidak dapat muncul langsung dalam output akhir. Panggil toString() untuk mengonversi UDT apa pun ke java.lang.String agar dapat ditampilkan. Untuk mengonversi semua output UDT ke string secara otomatis selama debugging, gunakan: Flag ini hanya berlaku untuk pernyataan PRINT, bukan pernyataan INSERT.
set odps.sql.udt.display.tostring=true;

Generik

UDT mendukung generik Java. Kompilator melakukan inferensi parameter tipe dari argumen:

-- Mengembalikan java.util.List<java.math.BigInteger>
java.util.Arrays.asList(new java.math.BigInteger('1'))

Tentukan parameter tipe secara eksplisit dalam pemanggilan konstruktor atau gunakan java.lang.Object:

-- ArrayList<Object>
new java.util.ArrayList(java.util.Arrays.asList('1', '2'))

-- ArrayList<String>
new java.util.ArrayList<String>(java.util.Arrays.asList('1', '2'))

Semantik operator

Semua operator mengikuti semantik MaxCompute SQL, bukan semantik Java:

  • Konkatenasi string: String.valueOf(1) + String.valueOf(2) mengembalikan 3 (kedua string secara implisit di-cast ke DOUBLE dan dijumlahkan). Untuk menggabungkan sebagai string, gunakan fungsi konkatenasi string.

  • Kesetaraan: Operator = adalah operator perbandingan SQL, bukan kesetaraan referensi Java. Gunakan metode equals untuk memeriksa apakah dua objek setara.

Kesetaraan objek dan pengacakan data

UDT tidak memiliki definisi yang jelas mengenai kesetaraan objek. Selama pengacakan data, objek dapat ditransmisikan melalui proses dan mesin fisik, menyebabkan satu objek tampak sebagai dua referensi berbeda. Selalu gunakan metode equals — bukan = — untuk membandingkan objek UDT.

Objek dalam baris atau kolom yang sama saling berkorelasi, tetapi korelasi antar baris atau kolom tidak dijamin.

Batasan

UDT tidak dapat digunakan sebagai kunci pengacakan dalam klausa JOIN, GROUP BY, DISTRIBUTE BY, SORT BY, ORDER BY, atau CLUSTER BY. UDT valid dalam ekspresi pada tahap-tahap tersebut, tetapi tidak dapat menjadi output. Contohnya:

  • group by new java.math.BigInteger('123') — tidak didukung

  • group by new java.math.BigInteger('123').hashCode() — didukung, karena hashCode() mengembalikan int.class, yang dipetakan ke tipe bawaan INT

UDF, user-defined aggregate functions (UDAF), dan UDT tidak dapat membaca data dari jenis tabel berikut:

  • Tabel yang menjalani evolusi skema

  • Tabel yang berisi tipe data kompleks

  • Tabel yang berisi tipe data JSON

  • Tabel transaksional

Mengakses sumber daya

Dalam MaxCompute SQL, panggil metode statis com.aliyun.odps.udf.impl.UDTExecutionContext.get() untuk mendapatkan objek ExecutionContext. Gunakan objek ini untuk mengakses konteks eksekusi saat ini, termasuk file dan tabel yang didaftarkan sebagai sumber daya.

Pertimbangan kinerja

Kinerja UDT mirip dengan kinerja UDF. Mesin komputasi yang dioptimalkan memberikan peningkatan tambahan dalam skenario tertentu:

  • Tidak ada overhead serialisasi untuk operasi lokal. Ketika objek UDT digunakan dalam proses yang sama (tidak memerlukan pengacakan data, seperti pada tahap JOIN atau AGGREGATE), serialisasi dan deserialisasi dilewati.

  • Runtime berbasis Codegen. UDT dijalankan melalui Codegen, bukan refleksi, sehingga tidak ada overhead refleksi. Beberapa pemanggilan UDT di-batch menjadi satu pemanggilan fungsi — misalnya, values[x].add(values[y]).divide(java.math.BigInteger.valueOf(2)) dipanggil sekali, menghindari overhead antarmuka per pemanggilan.

Keamanan

UDT tunduk pada model sandbox Java yang sama seperti UDF. Untuk melakukan operasi yang dibatasi oleh sandbox, batalkan isolasi sandbox untuk operasi tersebut atau ajukan permohonan untuk bergabung dalam daftar putih sandbox.

Fitur yang akan ditingkatkan

Fitur berikut direncanakan untuk versi mendatang:

  • Memanggil fungsi yang tidak mengembalikan nilai, dan fungsi yang langsung menggunakan data yang ditransfer (di mana nilai kembali diabaikan, seperti metode add pada antarmuka List).

  • Menggunakan kelas anonim dan ekspresi lambda.

  • Menggunakan UDT sebagai kunci pengacakan.

  • Mendukung lebih banyak bahasa pemrograman, seperti Python.

Langkah selanjutnya