Topik ini menjelaskan cara menggunakan tipe data kompleks dalam fungsi yang ditentukan pengguna (UDF) Java dan Python UDF.
Deskripsi
Dalam contoh ini, sebuah UDF bernama UDF_COMPLEX_DATA dibuat.
Contoh ini menunjukkan cara menggunakan tipe data kompleks ARRAY, MAP, dan STRUCT dalam UDF. Untuk Java UDF, nama UDF yang sama dapat digunakan untuk tipe data tersebut berdasarkan metode overloading. Untuk Python UDF, Anda harus membuat UDF bernama UDF_COMPLEX_DATA_ARRAY, UDF_COMPLEX_DATA_MAP, dan UDF_COMPLEX_DATA_STRUCT untuk menggunakan tipe data tersebut.
Sintaks:
array<string> UDF_COMPLEX_DATA(array<bigint> <as>) map<string, string> UDF_COMPLEX_DATA(map<string,bigint> <ms>) struct<output_name:string,output_time:string> UDF_COMPLEX_DATA(<input_name:string,input_timestamp:bigint> <st>)
Deskripsi:
Mengonversi timestamp input menjadi string waktu dalam format yyyy-MM-dd HH:mm:ss. Parameter input adalah tipe data kompleks ARRAY, MAP, dan STRUCT.
Parameter:
as: Parameter ini bertipe data ARRAY<BIGINT>. Daftar timestamp ditentukan. Parameter ini wajib.
ms: Parameter ini bertipe data MAP<STRING, BIGINT>. Nilai setiap elemen peta adalah timestamp. Parameter ini wajib.
st: Parameter ini bertipe data STRUCT. Nilai dari field input_timestamp adalah timestamp.
Prosedur pengembangan dan penggunaan
1. Menulis UDF
Kode contoh UDF Java
package com.aliyun; // Tentukan nama paket.
import com.aliyun.odps.data.Struct;
import com.aliyun.odps.udf.UDF;
import com.aliyun.odps.udf.annotation.Resolve;
import java.text.SimpleDateFormat;
import java.util.*;
@Resolve("struct<input_name:string, input_timestamp:bigint>->map<string,string>")
public class ComplexDataTypeExample extends UDF{
private static final String PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* Konversikan daftar timestamp menjadi daftar string waktu.
* @param timestamps Masukkan daftar timestamp.
* @return Dapatkan daftar string waktu.
*/
public List<String> evaluate(List<Long> timestamps) {
if (timestamps == null) {
return null;
}
List<String> result = new ArrayList<>();
SimpleDateFormat formatter = new SimpleDateFormat(PATTERN);
for (Long timestamp : timestamps) {
Date date = new Date(timestamp < 9999999999L ? timestamp * 1000 : timestamp);
String dateString = formatter.format(date);
result.add(dateString);
}
return result;
}
/**
* Konversikan timestamp tipe data MAP menjadi string waktu tipe data MAP.
* @param timestamps Masukkan data tipe data MAP di mana nilainya adalah timestamp.
* @return Dapatkan daftar string waktu tipe data MAP.
*/
public Map<String, String> evaluate(Map<String, Long> timestamps) {
if (timestamps == null) {
return null;
}
Map<String, String> result = new HashMap<>(timestamps.size());
SimpleDateFormat formatter = new SimpleDateFormat(PATTERN);
for (String key : timestamps.keySet()) {
Long timestamp = timestamps.get(key);
Date date = new Date(timestamp < 9999999999L ? timestamp * 1000 : timestamp);
String dateString = formatter.format(date);
result.put(key, dateString);
}
return result;
}
/**
* Konversikan timestamp menjadi string waktu.
* @param input Masukkan timestamp tipe data STRUCT.
* @return Dapatkan string waktu tipe data STRUCT.
*/
public Map<String, String> evaluate(Struct input) {
if (input == null) {
return null;
}
SimpleDateFormat formatter = new SimpleDateFormat(PATTERN);
String nameValue = (String) input.getFieldValue("input_name");
Long timestampValue = (Long) input.getFieldValue("input_timestamp");
Date date = new Date(timestampValue < 9999999999L ? timestampValue * 1000 : timestampValue);
String dateString = formatter.format(date);
Map<String, String> result = new HashMap<>(8);
result.put("output_name", nameValue);
result.put("output_time", dateString);
return result;
}
}Dependensi berikut perlu diperkenalkan ke pom.xml:
<dependency>
<groupId>com.aliyun.odps</groupId>
<artifactId>odps-sdk-udf</artifactId>
<version>0.29.10-public</version>
</dependency>Dalam kode contoh, tiga metode evaluate didefinisikan untuk overloading UDF.
Metode 1: Gunakan ARRAY sebagai parameter yang sesuai dengan kelas java.util.List.
Metode 2: Gunakan MAP sebagai parameter yang sesuai dengan kelas java.util.Map.
Metode 3: Gunakan STRUCT sebagai parameter yang sesuai dengan kelas com.aliyun.odps.data.Struct.
CatatanAnda tidak dapat menggunakan fitur refleksi untuk kelas com.aliyun.odps.data.Struct untuk mendapatkan nama dan tipe data bidang. Jika Anda ingin menggunakan tipe data STRUCT untuk UDF, Anda harus menambahkan
@Resolve annotationke kelas com.aliyun.odps.data.Struct. Anotasi ini hanya memengaruhi overloading UDF yang parameter input atau nilai baliknya mengandung kelas com.aliyun.odps.data.Struct.
Jika Anda menulis UDF dalam Java, Anda harus mewarisi kelas UDF. Dalam contoh ini, metode evaluate mendefinisikan tiga parameter input dari tipe LIST, MAP, dan STRUCT, yang secara terpisah mengembalikan nilai dari tipe LIST, MAP, dan MAP. Tipe data parameter input dan nilai balik digunakan sebagai tanda tangan UDF dalam pernyataan SQL. Untuk informasi lebih lanjut tentang spesifikasi dan persyaratan kode lainnya, lihat Java UDFs.
Kode contoh UDF Python 3
Dalam contoh berikut, parameter input bertipe data MAP<STRING, BIGINT>. Kode contoh menciptakan UDF bernama UDF_COMPLEX_DATA_MAP.
from odps.udf import annotate import datetime @annotate('map<string,bigint>->map<string,datetime>') class MapExample: def evaluate(self, input_dict): output_dict = dict() for key in input_dict: value = input_dict[key] t = datetime.datetime.fromtimestamp(value) output_dict[key] = t return output_dictDalam contoh berikut, parameter input bertipe data ARRAY<BIGINT>. Kode contoh menciptakan UDF bernama UDF_COMPLEX_DATA_ARRAY.
from odps.udf import annotate import datetime @annotate('array<bigint>->array<datetime>') class ArrayExample: def evaluate(self, input_list): output_list = list() for item in input_list: t = datetime.datetime.fromtimestamp(item) output_list.append(t) return output_listDalam contoh berikut, parameter input bertipe data STRUCT<input_name:string,input_timestamp:bigint>. Kode contoh menciptakan UDF bernama UDF_COMPLEX_DATA_STRUCT.
from odps.udf import annotate import datetime, collections @annotate('struct<input_name:string,input_timestamp:bigint>->struct<output_name:string,output_time:datetime>') class StructExample: def evaluate(self, input_namedtuple): OutputNamedTuple = collections.namedtuple('output_namedtuple', ['output_name', 'output_time']) name_val = input_namedtuple.input_name time_val = datetime.datetime.fromtimestamp(input_namedtuple.input_timestamp) output_namedtuple = OutputNamedTuple(name_val, time_val) return output_namedtuple
Secara default, Python 2 digunakan untuk menjalankan UDF dalam proyek MaxCompute. Jika Anda ingin menjalankan UDF dalam Python 3, jalankan perintah berikut pada tingkat sesi: set odps.sql.python.version=cp37. Untuk informasi lebih lanjut tentang spesifikasi Python 3 UDF, lihat Python 3 UDFs.
2. Unggah sumber daya dan buat UDF
Setelah Anda mengembangkan dan men-debug kode UDF, unggah sumber daya ke MaxCompute dan buat UDF. Dalam contoh ini, sebuah Java UDF bernama UDF_COMPLEX_DATA dibuat. Untuk Python UDF, Anda harus membuat UDF berikut: UDF_COMPLEX_DATA_ARRAY, UDF_COMPLEX_DATA_MAP, dan UDF_COMPLEX_DATA_STRUCT. Untuk informasi lebih lanjut tentang cara mengunggah sumber daya dan membuat Java UDF, lihat Kemas Program Java, Unggah Paket, dan Buat MaxCompute UDF. Untuk informasi lebih lanjut tentang cara mengunggah sumber daya dan membuat Python UDF, lihat Unggah Program Python dan Buat MaxCompute UDF.
3. Gunakan UDF
Jalankan perintah berikut untuk mengonversi timestamp tipe data ARRAY menjadi string waktu:
-- Panggil Java UDF. SELECT UDF_COMPLEX_DATA(array(1554047999, 1554047989)); -- Panggil Python UDF. set odps.sql.python.version=cp37; -- Untuk menggunakan Python3 UDF, jalankan perintah ini untuk mengaktifkan Python3. SELECT UDF_COMPLEX_DATA_ARRAY(array(1554047999, 1554047989));Hasil berikut dikembalikan:
+---------------------------------------------+ | _c0 | +---------------------------------------------+ | [2019-03-31 23:59:59, 2019-03-31 23:59:49] | +---------------------------------------------+Jalankan perintah berikut untuk mengonversi timestamp tipe data MAP menjadi string waktu:
-- Panggil Java UDF. SELECT UDF_COMPLEX_DATA(map('date1', 1554047989, 'date2', 1554047999)); -- Panggil Python UDF. set odps.sql.python.version=cp37; -- Untuk menggunakan Python3 UDF, jalankan perintah ini untuk mengaktifkan Python3. SELECT UDF_COMPLEX_DATA_MAP(map('date1', 1554047989, 'date2', 1554047999));Hasil berikut dikembalikan:
+----------------------------------------------------------------+ | _c0 | +----------------------------------------------------------------+ | {"date1":"2019-03-31 23:59:49","date2":"2019-03-31 23:59:59"} | +----------------------------------------------------------------+Jalankan perintah berikut untuk mengonversi timestamp tipe data STRUCT menjadi string waktu:
-- Panggil Java UDF. SELECT UDF_COMPLEX_DATA(struct('date', 1554047989)); -- Panggil Python UDF. set odps.sql.python.version=cp37; -- Untuk menggunakan Python3 UDF, jalankan perintah ini untuk mengaktifkan Python3. SELECT UDF_COMPLEX_DATA_STRUCT(struct('date', 1554047989));Hasil berikut dikembalikan:
+-------------------------------------------------------------+ | _c0 | +-------------------------------------------------------------+ | {"output_name":"date","output_time":"2019-03-31 23:59:49"} | +-------------------------------------------------------------+