MaxCompute, yeni nesil SQL motoruna dayalı olarak kullanıcı tanımlı türler (UDT) sunar. UDT'ler, SQL ifadelerinde üçüncü taraf programlama dillerinin sınıflarına veya nesnelerine başvurmanıza, yöntemleri çağırmanıza veya veri almanıza olanak tanır.
UDT'leri ne zaman UDF'lere tercih etmelisiniz?
Hem UDT'ler hem de kullanıcı tanımlı işlevler (UDF), MaxCompute SQL'i özel mantıkla genişletir. İş akışınıza göre seçim yapın:
| Durum | Önerilen yaklaşım |
|---|---|
Yerleşik bir Java sınıfı yöntemini doğrudan çağırma (örneğin, Integer.MAX_VALUE) |
UDT — işlev tanımı gerekmez |
| Üçüncü taraf bir kitaplığı SQL ifadesinde doğrudan yeniden kullanma | UDT — sarmalamadan sınıfı satır içi olarak referans alın |
| Derlenmiş kaynak dil nesnelerini çok aşamalı işlere dahil etme | UDT — aşamalar arası JVM durumunu otomatik olarak kapsüller |
| Birden fazla projede yeniden kullanılabilir iş mantığı uygulama | UDF — açık işlev kaydı paylaşımı kolaylaştırır |
Kullanım senaryoları
İşlev tanımlamadan Java standart kitaplık yöntemlerini çağırın. Göreviniz, MaxCompute SQL'in yerel olarak sunmadığı yerleşik bir Java sınıfı yöntemi gerektirdiğinde, UDT bu yöntemi ifade içinde doğrudan çağırmanızı sağlar.
Üçüncü taraf kitaplıkları satır içi olarak referans alın. Üçüncü taraf kitaplık işlevini bir UDF içine sarmak yerine, sınıfı SQL ifadesinde doğrudan referans alın.
Derlenmiş kaynak kodunu SQL'e gömün. Java gibi derleme gerektiren diller için UDT'ler, ayrı bir kayıt adımı olmadan nesnelere ve sınıflara SQL ifadelerinden başvurmanıza olanak tanır. Betik tabanlı alternatifler için bkz. SELECT TRANSFORM.
Ön koşullar
UDT'leri kullanmadan önce şunlardan emin olun:
Ortamınızda JDK 1.8 bulunur. JDK 1.8'den sonraki sürümler desteklenmeyebilir.
INT gibi türleri kullanıyorsanız yeni veri türlerini etkinleştirin:
set odps.sql.type.system.odps2=true;
Çalışma mantığı
Diğer SQL motorlarında bulunan UDT'lerden (genellikle STRUCT türüne benzer şekilde tür takma adları tanımlayan) farklı olarak, MaxCompute UDT'leri bir CREATE TYPE ifadesi gibi çalışır; hem alanlar hem de yöntemler içerir ve DDL yazmadan bunlara SQL'de doğrudan başvurursunuz.
Aşağıdaki örnek farkı göstermektedir. Java'nın java.lang paketinden Integer.MAX_VALUE değerine erişmek için:
UDT kullanarak (doğrudan başvuru):
-- Enable new data types (required for types such as INTEGER).
set odps.sql.type.system.odps2=true;
SELECT java.lang.Integer.MAX_VALUE;
java.lang otomatik olarak içeri aktarıldığından (Java'da olduğu gibi), bu ifade şuna eşdeğerdir:
set odps.sql.type.system.odps2=true;
SELECT Integer.MAX_VALUE;
Sonuç:
+-----------+
| max_value |
+-----------+
| 2147483647 |
+-----------+
UDF kullanarak (karşılaştırma için):
-
UDF sınıfını yazın:
package com.aliyun.odps.test; public class IntegerMaxValue extends com.aliyun.odps.udf.UDF { public Integer evaluate() { return Integer.MAX_VALUE; } } -
Derleyin, yükleyin ve kaydedin:
add jar odps-test.jar; create function integer_max_value as 'com.aliyun.odps.test.IntegerMaxValue' using 'odps-test.jar'; -
Çağırın:
select integer_max_value();
UDT'ler bu süreci tek bir SQL ifadesine indirger.
Çok aşamalı yürütme
UDT nesneleri MapReduce aşamaları arasında doğal olarak akar. Aşağıdaki örnek, farklı veri kaynaklarından hesaplanan iki BigInteger sütununu birleştirir:
-- Sample data.
@table1 := select * from values ('100000000000000000000') as t(x);
@table2 := select * from values (100L) as t(y);
-- Create an object with the new method.
@a := select new java.math.BigInteger(x) x from @table1;
-- Call a static method.
@b := select java.math.BigInteger.valueOf(y) y from @table2;
-- Call an instance method across the join.
select /*+mapjoin(b)*/ x.add(y).toString() from @a a join @b b;
-- Output:
100000000000000000100
Bu iş üç aşamada (M1, R2, J3) çalışır. new java.math.BigInteger(x) M1'de; java.math.BigInteger.valueOf(y) ve x.add(y).toString() ise farklı süreçlerde ve fiziksel makinelerde J3'te çalışır. UDT, tüm aşamaların aynı Java Sanal Makinesinde (JVM) çalıştığı izlenimini verecek şekilde bunu kapsüller.
Bu UDT örneği SQL işinin DAG'i üç aşama içerir: M1 → R2_1 → J3_2. Tüm aşamalar %100 tamamlanmıştır ve her aşama arasında 1 satır veri iletilir.
a değişkeninden gelen x sütunu, yerleşik bir tür yerine java.math.BigInteger türündedir. Bu UDT değeri diğer operatörlere iletilebilir ve veri karıştırma işlemlerinde kullanılabilir.
JAR paketlerine başvurma ve Java içe aktarmalarını ayarlama
Tüm SDK for Java sınıfları varsayılan olarak UDT'ler tarafından kullanılabilir. Ek JAR paketlerine başvurmak veya varsayılan içe aktarma yollarını ayarlamak için aşağıdaki oturum bayraklarını kullanın.
JAR paketine başvurma:
set odps.sql.type.system.odps2=true;
set odps.sql.session.resources=odps-test.jar;
-- The JAR must be uploaded to the project beforehand.
select new com.aliyun.odps.test.IntegerMaxValue().evaluate();
Virgülle ayrılmış birden fazla kaynak belirtebilirsiniz: set odps.sql.session.resources=foo.sh,bar.txt;
odps.sql.session.resources hem UDT'leri hem de SELECT TRANSFORM'u kontrol eder. Burada ayarlanan bir JAR, her iki özellik için de kullanılabilir.
Varsayılan Java içe aktarma yolunu ayarlama:
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.*;
-- With the import set, you can omit the full package prefix.
select new IntegerMaxValue().evaluate();
odps.sql.session.java.imports bir sınıf yolu (örneğin, java.math.BigInteger) veya joker karakter (*) kabul eder. Statik içe aktarmalar desteklenmez.
Desteklenen işlemler
UDT'ler SQL ifadelerinde aşağıdaki işlemleri destekler:
newkullanarak nesne oluşturma — örnek:new java.math.BigInteger('123')Başlatıcı listeleriyle
newkullanarak dizi oluşturma — örnek:new Integer[] { 1, 2, 3 }Örnek ve statik yöntemleri çağırma
Genel örnek ve statik alanlara erişme
Yalnızca genel yöntemlere ve genel alanlara erişilebilir. Tüm tanımlayıcılar (paket adları, sınıf adları, yöntem adları, alan adları) büyük/küçük harfe duyarlıdır. Anonim sınıflar ve lambda ifadeleri desteklenmez. Değer döndürmeyen işlevler ifadelerde çağrılamaz.
Veri türleri
Tür eşlemesi
Java veri türleri MaxCompute yerleşik türleriyle eşlenir. Java UDF'leri için kullanılan aynı eşleme UDT'ler için de geçerlidir.
Yerleşik tür yöntemlerini doğrudan çağırma:
'123'.length(),1L.hashCode()Yerleşik işlevlerde UDT kullanma:
chr(Long.valueOf('100'))—Long.valueOfjava.lang.Longdöndürür ve bu da yerleşik BIGINT türüne eşlenirJava ilkel türleri otomatik olarak kutulama türlerine dönüştürülür
Yeni yerleşik veri türleri için sorguyu çalıştırmadan önce set odps.sql.type.system.odps2=true; ekleyin.
Tür dönüşümleri
SQL tür dönüşümleri desteklenir:
cast(1 as java.lang.Object)Java tarzı tür dönüşümleri desteklenmez:
(Object)1UDT nesneleri örtük olarak temel sınıf nesnelerine dönüştürülebilir
UDT nesneleri açıkça temel sınıf veya alt sınıf nesnelerine dönüştürülebilir (yayınlanabilir)
İlişkisiz iki tür arasında dönüşüm yapmak, yerleşik tür dönüşümüyle aynı kuralları izler. Örneğin,
java.lang.Longtürünüjava.lang.Integertürüne dönüştürmek, BIGINT'i INT'e dönüştürmeyle aynı kuralları uygular ve bu durum veri kaybına neden olabilir.
UDT nesneleri diske kaydedilemez ve doğrudan tablolara eklenemez (DDL, UDT'leri sütun türü olarak desteklemez). UDT değeri yerleşik bir türe örtük olarak dönüştürülebiliyorsa tabloya yazılabilir. BINARY otomatik serileştirmeyi destekler —byte[]dizileri kaydedilebilir ve serileştirme kaldırılabilir. Bir UDT'yi kalıcı hale getirmek için serileştirme ve serileştirme kaldırma yöntemlerini kullanarak BINARY'ye dönüştürün. UDT değerleri doğrudan son çıktıda görünemez. Herhangi bir UDT'yi görüntüleme amacıylatoString()çağırarakjava.lang.Stringtürüne dönüştürün. Hata ayıklama sırasında tüm UDT çıktısını otomatik olarak dizelere dönüştürmek için şunu kullanın: Bu bayrak yalnızca PRINT ifadeleri için geçerlidir, INSERT ifadeleri için geçerli değildir.
set odps.sql.udt.display.tostring=true;
Generics (Jenerikler)
UDT'ler Java jeneriklerini destekler. Derleyici, tür parametresini bağımsız değişkenden çıkarır:
-- Returns java.util.List<java.math.BigInteger>
java.util.Arrays.asList(new java.math.BigInteger('1'))
Tür parametrelerini oluşturucu çağrılarında açıkça belirtin veya java.lang.Object kullanın:
-- 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'))
Operatör anlambilimi
Tüm operatörler Java anlambilimini değil, MaxCompute SQL anlambilimini izler:
Dize birleştirme:
String.valueOf(1) + String.valueOf(2)ifadesi3döndürür (her iki dize örtük olarak DOUBLE'a yayılanır ve toplanır). Dizeleri birleştirmek için bunun yerine bir dize birleştirme işlevi kullanın.Eşitlik:
=operatörü bir SQL karşılaştırma operatörüdür, Java referans eşitliği değildir. İki nesnenin eşdeğer olup olmadığını kontrol etmek içinequalsyöntemini kullanın.
Nesne eşitliği ve veri karıştırma
UDT'lerin nesne eşitliği konusunda net bir tanımı yoktur. Veri karıştırma sırasında nesneler süreçler ve fiziksel makineler arasında iletilebilir, bu da tek bir nesnenin iki farklı başvuru olarak görünmesine neden olabilir. UDT nesnelerini karşılaştırmak için = yerine her zaman equals yöntemini kullanın.
Aynı satır veya sütun içindeki nesneler ilişkilidir, ancak satırlar veya sütunlar arasındaki ilişki garanti edilmez.
Sınırlamalar
UDT'ler JOIN, GROUP BY, DISTRIBUTE BY, SORT BY, ORDER BY veya CLUSTER BY yan tümcelerinde karıştırma anahtarı olarak kullanılamaz. UDT'ler bu aşamalardaki ifadelerde geçerlidir ancak çıktı olamazlar. Örneğin:
group by new java.math.BigInteger('123')— desteklenmezgroup by new java.math.BigInteger('123').hashCode()— desteklenir, çünkühashCode()int.classdöndürür ve bu da yerleşik INT türüne eşlenir
UDF'ler, kullanıcı tanımlı toplama işlevleri (UDAF) ve UDT'ler aşağıdaki tablo türlerinden veri okuyamaz:
Şema evriminin uygulandığı tablolar
Karmaşık veri türleri içeren tablolar
JSON veri türleri içeren tablolar
İşlemsel tablolar
Kaynaklara erişme
MaxCompute SQL'de, ExecutionContext nesnesini almak için com.aliyun.odps.udf.impl.UDTExecutionContext.get() statik yöntemini çağırın. Kaynak olarak kaydedilen dosyalar ve tablolar dahil olmak üzere mevcut yürütme bağlamına erişmek için bu nesneyi kullanın.
Performans hususları
UDT performansı UDF performansına benzer. Optimize edilmiş hesaplama motoru belirli senaryolarda ek iyileştirmeler sağlar:
Yerel işlemler için serileştirme ek yükü yok. Bir UDT nesnesi aynı süreç içinde kullanıldığında (JOIN veya AGGREGATE aşamalarında olduğu gibi veri karıştırma gerekmediğinde) serileştirme ve serileştirme kaldırma atlanır.
Kod üretime dayalı çalışma zamanı. UDT'ler yansıma yerine Kod Üretimi aracılığıyla çalışır, bu nedenle yansıma ek yükü yoktur. Birden fazla UDT çağrısı tek bir işlev çağrısında gruplanır — örneğin,
values[x].add(values[y]).divide(java.math.BigInteger.valueOf(2))bir kez çağrılır ve çağrı başına arayüz ek yükünden kaçınılır.
Güvenlik
UDT'ler, UDF'lerle aynı Java korumalı alanı modeline tabidir. Korumalı alan tarafından kısıtlanan işlemleri gerçekleştirmek için bu işlemlerin korumalı alan izolasyonunu iptal edin veya korumalı alan izin listesine katılmak için başvurun.
Geliştirilecek özellikler
Aşağıdaki özellikler gelecek sürümler için planlanmaktadır:
Değer döndürmeyen işlevleri ve doğrudan aktarılan verileri kullanan işlevleri (dönüş değeri yoksayıldığı için List arabiriminin
addyöntemi gibi) çağırma.Anonim sınıfları ve lambda ifadelerini kullanma.
UDT'leri karıştırma anahtarı olarak kullanma.
Python gibi daha fazla programlama dilini destekleme.
Sonraki adımlar
Java UDF'leri — veri türü eşleme tablosu ve UDF uygulama referansı
Yeni yerleşik veri türleri —
set odps.sql.type.system.odps2=true;gerektiren türlerSELECT TRANSFORM — betikleri SQL ifadelerine gömme
COLLECT_SET ve diğer toplama işlevleri — toplama ve tablo değerli işlev davranışını uygulamak için UDT'lerle birlikte kullanma
Java korumalı alanı — korumalı alan modeli ve izin listesi başvurusu