MaxCompute memperkenalkan tipe data yang ditentukan pengguna (UDTs) berdasarkan mesin SQL generasi baru. UDTs memungkinkan Anda mereferensikan kelas atau objek dari bahasa pemrograman pihak ketiga dalam pernyataan SQL untuk memanggil metode atau mendapatkan data.
Pengenalan
UDTs yang didukung oleh banyak mesin SQL mirip dengan tipe STRUCT di MaxCompute. UDTs yang didukung oleh MaxCompute mirip dengan pernyataan CREATE TYPE. Sebuah UDT mencakup bidang dan metode. Anda tidak perlu menggunakan pernyataan DDL untuk mendefinisikan tipe data baru di MaxCompute. Sebagai gantinya, MaxCompute memungkinkan Anda mereferensikan tipe data baru secara langsung dalam pernyataan SQL. Contoh berikut menunjukkan cara menggunakan UDTs.
Sebagai contoh, untuk memanggil paket java.lang dalam pernyataan SQL, Anda dapat menggunakan salah satu metode berikut:
Gunakan UDTs untuk memanggil java.lang.
-- Aktifkan tipe data baru. Contoh berikut menggunakan tipe INTEGER baru (INT). set odps.sql.type.system.odps2=true; SELECT java.lang.Integer.MAX_VALUE;Mirip dengan Java, paket java.lang dapat dihilangkan. Oleh karena itu, pernyataan sebelumnya setara dengan pernyataan berikut:
set odps.sql.type.system.odps2=true; SELECT Integer.MAX_VALUE;Hasil berikut dikembalikan:
+-----------+ | max_value | +-----------+ | 2147483647 | +-----------+Gunakan fungsi yang ditentukan pengguna (UDFs) untuk memanggil java.lang.
Kembangkan kode. Kode berikut mendefinisikan kelas UDF.
package com.aliyun.odps.test; public class IntegerMaxValue extends com.aliyun.odps.udf.UDF { public Integer evaluate() { return Integer.MAX_VALUE; } }Kompilasi UDF menjadi paket JAR, unggah paket tersebut, dan buat fungsi.
add jar odps-test.jar; create function integer_max_value as 'com.aliyun.odps.test.IntegerMaxValue' using 'odps-test.jar';Panggil fungsi dalam pernyataan SQL.
select integer_max_value();
Dalam contoh ini, UDTs menyederhanakan prosedur bagi Anda untuk menggunakan bahasa pemrograman lain guna memperluas fitur SQL.
Skenario
UDTs cocok untuk skenario berikut:
Anda ingin menggunakan beberapa fitur yang tidak disediakan oleh MaxCompute tetapi dapat diimplementasikan dalam bahasa pemrograman lain.
Sebagai contoh, untuk mengimplementasikan beberapa fitur, Anda hanya perlu memanggil kelas bawaan Java sekali. Namun, MaxCompute tidak menyediakan metode untuk mengimplementasikan fitur-fitur ini. Jika Anda menggunakan UDF untuk menjalankan tugas-tugas ini, prosedurnya rumit.
Anda ingin memanggil pustaka pihak ketiga dalam pernyataan SQL untuk mengimplementasikan fitur terkait. Dalam skenario ini, UDF memungkinkan Anda langsung menggunakan fungsi yang disediakan oleh pustaka pihak ketiga dalam pernyataan SQL, alih-alih membungkus fungsi tersebut di dalam UDF.
Anda ingin langsung memanggil kode sumber bahasa pemrograman pihak ketiga dalam pernyataan SQL. SELECT TRANSFORM memungkinkan Anda menyertakan skrip dalam pernyataan SQL agar pernyataan SQL ini lebih mudah dibaca dan dipelihara. Untuk beberapa bahasa pemrograman, seperti Java, kode sumber hanya dapat dieksekusi setelah dikompilasi. Anda dapat menggunakan UDTs untuk mereferensikan objek dan kelas dari bahasa-bahasa ini dalam pernyataan SQL.
Batasan
Anda tidak dapat menggunakan UDF, UDAF, atau UDT untuk membaca data dari jenis tabel berikut:
Tabel tempat dilakukan evolusi skema.
Tabel yang berisi tipe data kompleks.
Tabel yang berisi tipe data JSON.
Tabel transaksional.
Implementasi
Contoh berikut menunjukkan cara menjalankan UDT.
-- Data sampel.
@table1 := select * from values ('100000000000000000000') as t(x);
@table2 := select * from values (100L) as t(y);
-- Logika kode.
-- Buat objek menggunakan 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.
select /*+mapjoin(b)*/ x.add(y).toString() from @a a join @b b;
-- Hasil berikut ditampilkan:
100000000000000000100Gambar berikut menunjukkan proses.
UDT ini memiliki tiga tahap: M1, R2, dan J3. Jika operasi JOIN digunakan dalam MapReduce, data harus diacak ulang. Akibatnya, data diproses di beberapa tahap. Proses dan mesin fisik yang memproses data bervariasi di setiap tahap.
Hanya metode new java.math.BigInteger(x) yang dipanggil pada tahap M1.
Metode java.math.BigInteger.valueOf(y) dan x.add(y).toString() dipanggil secara terpisah pada tahap J3. Metode-metode ini dipanggil pada tahap yang berbeda dan dieksekusi dalam proses dan mesin fisik yang berbeda. UDT mengenkapsulasi tahapan ini untuk mencapai efek seperti semua tahap diimplementasikan pada Java Virtual Machine (JVM) yang sama.
Contoh sebelumnya menunjukkan bahwa hasil subquery mendukung kolom UDT. Kolom x yang diambil oleh variabel a adalah tipe java.math.BigInteger, bukan tipe bawaan. Anda dapat mentransfer data UDT ke operator lain dan kemudian memanggil metodenya. Anda juga dapat menggunakan data UDT dalam pengacakan data.
Fitur
UDTs hanya mendukung Java. Secara default, semua kelas dari SDK untuk Java dapat direferensikan oleh UDTs.
CatatanLingkungan runtime JDK adalah JDK 1.8. Versi yang lebih baru dari JDK 1.8 mungkin tidak didukung.
UDTs juga memungkinkan Anda mengunggah paket JAR dan langsung mereferensikan paket-paket ini. Bendera spesifik disediakan untuk UDTs.
set odps.sql.session.resources: menentukan sumber daya yang ingin Anda referensikan. Anda dapat menentukan beberapa sumber daya dan memisahkannya dengan koma (,). Contoh:set odps.sql.session.resources=foo.sh,bar.txt;.CatatanBendera ini bekerja sama seperti bendera yang digunakan untuk menentukan sumber daya dalam pernyataan
SELECT TRANSFORM. Oleh karena itu, bendera ini mengontrol dua fitur. Sebagai contoh, Anda dapat menggunakan UDT untuk mereferensikan paket JAR UDF yang telah kami sebutkan di Ikhtisar.set odps.sql.type.system.odps2=true; set odps.sql.session.resources=odps-test.jar; -- Tentukan paket JAR yang ingin Anda referensikan. Paket ini harus diunggah ke proyek yang diperlukan. select new com.aliyun.odps.test.IntegerMaxValue().evaluate();odps.sql.session.java.imports: menentukan paket Java default. Anda dapat menentukan beberapa paket dan memisahkannya dengan koma (,). Bendera ini mirip dengan pernyataanIMPORTdalam Java. Anda dapat menentukan jalur kelas, sepertijava.math.BigInteger, atau menggunakan*.Static importtidak didukung.Sebagai contoh, Anda dapat menggunakan UDT untuk mereferensikan paket JAR UDF yang telah kami sebutkan di Ikhtisar.
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.*; -- Tentukan paket JAR default. select new IntegerMaxValue().evaluate();
UDTs mendukung akses sumber daya. Dalam SQL MaxCompute, Anda dapat memanggil metode statis
com.aliyun.odps.udf.impl.UDTExecutionContext.get()untuk mendapatkan objekExecutionContext. Kemudian, Anda dapat menggunakan objek ini untuk mengakses kelasExecutionContextsaat ini dan kemudian mengakses sumber daya, seperti file dan tabel.UDTs mendukung operasi berikut:
Buat objek menggunakan metode
new.Buat array menggunakan metode
new. Daftar inisialisasi dapat digunakan. Contoh:new Integer[] { 1, 2, 3 }.Panggil metode, termasuk metode statis.
Akses bidang, termasuk bidang statis.
CatatanHanya metode publik dan bidang publik yang didukung.
Pengenal dalam UDT mencakup nama paket, kelas, metode, dan bidang. Semua pengenal bersifat peka huruf besar/kecil.
Kelas anonim dan ekspresi lambda tidak didukung.
UDTs digunakan dalam ekspresi. Fungsi yang tidak mengembalikan nilai tidak dapat dipanggil dalam ekspresi. Masalah ini akan diselesaikan di versi mendatang.
UDTs mendukung tipe data berikut:
UDTs mendukung konversi tipe SQL, seperti
cast(1 as java.lang.Object). UDTs tidak mendukung konversi tipe Java, seperti(Object)1.Tipe data Java dipetakan ke tipe data bawaan. Pemetaan ini dapat diterapkan pada UDTs. Untuk informasi lebih lanjut, lihat tabel pemetaan tipe data di Java UDFs.
Anda dapat langsung memanggil metode tipe Java ke mana tipe bawaan dipetakan. Contoh:
'123'.length() , 1L.hashCode().UDTs dapat digunakan dalam fungsi bawaan dan UDF. Sebagai contoh, dalam
chr(Long.valueOf('100')),Long.valueOfmengembalikan nilai tipejava.lang.Long. Fungsi bawaanCHRmendukung tipe BIGINT bawaan.Data dari tipe primitif Java secara otomatis dikonversi menjadi tipe kotak dan dua aturan sebelumnya berlaku.
CatatanUntuk tipe data bawaan baru tertentu, Anda harus menggunakan
set odps.sql.type.system.odps2=true;untuk mendeklarasikan tipe-tipe ini. Jika tidak, akan terjadi kesalahan.Aturan konversi tipe berikut berlaku dalam UDTs:
Objek UDT dapat dikonversi secara implisit menjadi objek kelas dasarnya.
Objek UDT dapat dikonversi secara paksa menjadi objek kelas dasar atau kelas turunan.
Konversi tipe data antara dua objek tanpa pewarisan mengikuti aturan konversi asli. Namun, konversi semacam itu dapat mengakibatkan perubahan data. Sebagai contoh, data tipe
java.lang.Longdapat dikonversi secara paksa menjadi tipejava.lang.Integer. Konversi ini menggunakan aturan yang digunakan untuk mengonversi tipe BIGINT bawaan menjadi tipe INT. Proses ini dapat mengakibatkan perubahan data dan bahkan hilangnya presisi data.
CatatanObjek UDT tidak dapat disimpan ke disk. Ini berarti bahwa objek UDT tidak dapat
dimasukkanke dalam tabel karena pernyataan DDL tidak mendukung UDT. Namun, jika tipe data dapat dikonversi secara implisit menjadi salah satu tipe bawaan, Anda dapat membuat tabel yang berisi objek UDT. BINARY adalah tipe bawaan dan mendukung serialisasi otomatis. Anda dapat menyimpan array byte[] ke disk. Array byte[] yang disimpan dapat dideserialisasi ke tipe BINARY. Untuk menyimpan UDT, Anda harus memanggil metode serialisasi dan deserialisasi untuk mengonversi tipe data menjadi BINARY.Output tidak dapat berupa UDT. Namun, Anda dapat memanggil metode
toString()untuk mengonversi tipe data menjadi tipejava.lang.Stringkarena metode toString() mendukung semua kelas Java. Anda dapat menggunakan metode ini untuk memeriksa data UDT selama debugging.Anda juga dapat menambahkan bendera
set odps.sql.udt.display.tostring=true;untuk mengaktifkan MaxCompute mengonversi semua data UDT keluaran menjadi string menggunakan metodejava.util.Objects.toString(...). Ini memudahkan debugging. Bendera ini biasanya digunakan untuk debugging karena hanya dapat diterapkan pada pernyataan PRINT. Tidak dapat diterapkan pada pernyataanINSERT.UDTs mendukung generics Java. Sebagai contoh, kompiler dapat menentukan bahwa nilai yang dikembalikan oleh
java.util.Arrays.asList(new java.math.BigInteger('1'))adalah tipejava.util.List<java.math.BigInteger>berdasarkan tipe parameter.CatatanAnda harus menentukan parameter tipe dalam fungsi konstruktor atau menggunakan
java.lang.Object. Ini sama seperti Java.Sebagai contoh, hasil dari
new java.util.ArrayList(java.util.Arrays.asList('1', '2'))adalah tipejava.util.ArrayList<Object>. Hasil darinew java.util.ArrayList<String>(java.util.Arrays.asList('1', '2'))adalah tipejava.util.ArrayList<String>.
Semua operator menggunakan semantik SQL MaxCompute alih-alih UDTs.
Kombinasi string: Hasil dari
String.valueOf(1) + String.valueOf(2)adalah 3. Dua string secara implisit dikonversi menjadi nilai bertipe DOUBLE dan dijumlahkan. Jika Anda menggunakan penggabungan string Java untuk menggabungkan string, hasilnya adalah 12.Operasi
=: Operator=dalam pernyataan SQL digunakan sebagai operator perbandingan. Digunakan untuk membandingkan satu ekspresi dengan ekspresi lain. Anda harus memanggil metode equals dalam Java untuk memeriksa apakah dua objek setara. Operator=tidak dapat digunakan untuk memverifikasi kesetaraan dua objek.
UDTs tidak memiliki definisi yang jelas tentang kesetaraan objek. Hal ini disebabkan oleh pengacakan data. Objek mungkin ditransmisikan antara proses atau mesin fisik yang berbeda. Selama transmisi objek, sebuah objek mungkin direferensikan sebagai dua objek yang berbeda. Sebagai contoh, sebuah objek mungkin diacak ke dua mesin dan kemudian diacak ulang. Oleh karena itu, ketika menggunakan UDTs, Anda harus menggunakan metode
equalsalih-alih operator=untuk memverifikasi kesetaraan dua objek.Objek dalam baris atau kolom yang sama berkorelasi dalam beberapa hal. Namun, korelasi antara objek dalam baris atau kolom yang berbeda tidak dapat dijamin.
UDTs tidak dapat digunakan sebagai kunci shuffle dalam klausa, seperti
JOIN,GROUP BY,DISTRIBUTE BY,SORT BY,ORDER BY, atauCLUSTER BY.UDTs dapat digunakan pada tahap ekspresi, tetapi tidak dapat digunakan sebagai output. Sebagai contoh, Anda tidak dapat memanggil metode
group by new java.math.BigInteger('123'). Namun, Anda dapat memanggil metodegroup by new java.math.BigInteger('123').hashCode(). Ini karena nilai yang dikembalikan olehhashCodeadalah tipeint.class, yang dapat digunakan sebagai tipe INT bawaan. Ini menerapkan aturan baik tipe bawaan maupun tipe Java tertentu.Anda dapat menggunakan UDTs untuk mengimplementasikan fitur yang disediakan oleh fungsi SCALAR. Anda dapat menggunakan fungsi bawaan COLLECT_SET dan Fungsi lainnya dengan UDTs untuk mengimplementasikan fitur yang disediakan oleh fungsi agregat dan fungsi bernilai tabel.
Manfaat
UDTs memberikan manfaat berikut:
UDTs mudah digunakan. Anda tidak perlu mendefinisikan fungsi.
UDTs mendukung semua fitur JDK. Ini meningkatkan fleksibilitas SQL.
Kode UDT dapat disimpan dalam file yang sama dengan kode SQL. Ini memudahkan pengelolaan kode.
Anda dapat langsung mereferensikan pustaka bahasa pemrograman lain dan menggunakan kembali kode yang telah Anda tulis dalam bahasa lain.
Anda dapat membuat fitur berorientasi objek.
Fitur yang perlu ditingkatkan:
Panggil fungsi yang tidak mengembalikan nilai dan fungsi yang langsung menggunakan data yang ditransfer. Untuk fungsi yang langsung menggunakan data yang ditransfer, nilai kembaliannya diabaikan. Sebagai contoh, jika Anda memanggil metode
addyang disediakan oleh antarmuka List, metode ini mengembalikan daftar yang telah Anda transfer.Gunakan kelas anonim dan ekspresi lambda.
Gunakan UDTs sebagai kunci shuffle.
Dukung lebih banyak bahasa pemrograman, seperti Python.
Kinerja
UDTs berjalan dengan cara yang mirip dengan UDFs. Oleh karena itu, kinerja UDTs hampir sama dengan UDFs. Mesin komputasi yang dioptimalkan meningkatkan kinerja UDTs dalam skenario tertentu.
Jika objek UDT digunakan dalam proses yang berbeda, objek tersebut harus diserialisasi dan dideserialisasi. Jika Anda menggunakan UDTs untuk melakukan operasi yang tidak memerlukan pengacakan data, seperti
JOINatauAGGREGATE, overhead serialisasi dan deserialisasi dihindari.Runtime UDTs didasarkan pada Codegen alih-alih refleksi. Oleh karena itu, tidak ada kehilangan kinerja. Beberapa UDTs dapat dieksekusi dalam satu panggilan fungsi. Dalam contoh sebelumnya,
values[x].add(values[y]).divide(java.math.BigInteger.valueOf(2))hanya dipanggil sekali. Oleh karena itu, tidak ada overhead antarmuka tambahan yang disebabkan meskipun unit operasional UDTs kecil.
Keamanan
Mirip dengan UDFs, UDTs dibatasi oleh model sandbox Java. Untuk melakukan operasi yang dibatasi, Anda harus membatalkan isolasi sandbox untuk operasi tersebut atau mengajukan permohonan untuk bergabung dengan daftar putih sandbox.