Tüm Ürünler
Search
Belge Merkezi

MaxCompute:Kod gömülü UDF'ler

Son Güncelleme:Oct 04, 2026

Bu konu, Java veya Python kodunu SQL betiklerine gömmek için kod gömülü kullanıcı tanımlı işlevlerin (UDF) nasıl kullanılacağını açıklar.

Arka plan bilgileri

MaxCompute kod gömülü UDF'leri, kod uygulama ve bakımındaki aşağıdaki sorunları çözer:

  • Karmaşık kod uygulaması: UDF'leri oluşturup kodu geliştirdikten sonra, Java'da derlemeniz ve kaynaklar ile işlevler oluşturmanız gerekir.

  • Kod bakımı zorluğu: SQL betiklerinde başvurulan UDF'lerin uygulama mantığını doğrudan görüntüleyemez veya JAR paketlerinin source koduna ulaşamazsınız.

  • Düşük kod okunabilirliği: Kullanıcı tanımlı türleri (UDT) kullanarak Java kitaplık işlevlerini uygulamak için Java kodunu uzun satırlardaki ifadelere dönüştürmeniz gerekir. Ayrıca, bazı Java kodlarını ifade olarak yazamayabilirsiniz. Örnek:

    Foo f = new Foo();
    f.execute();
    f.getResult();

Açıklama

Kod gömülü UDF'ler, Java veya Python kodunu SQL betiklerine gömmanıza olanak tanır. Bir betiği derlediğinizde Janino-compiler, gömülü kodu belirler ve çıkarır, Java'da derler ve ardından dinamik olarak kaynaklar oluşturarak geçici işlevler tanımlar.

SQL betiklerini ve üçüncü taraf kod satırlarını aynı source dosyasına yerleştirebilirsiniz. Bu durum, UDT veya UDF kullanımını basitleştirir ve günlük geliştirme ile bakımı kolaylaştırır.

Sınırlamalar

Gömülü Java kodunu derlemek için yalnızca Janino-compiler kullanabilirsiniz. Gömülü Java kodunun sözdizimi, standart JDK sözdiziminin bir alt kümesi olmalıdır. Gömülü Java kodu aşağıdaki sınırlamalara sahiptir:

  • Lambda ifadeleri desteklenmez.

  • Tek bir catch bloğunda birden fazla türde özel durum belirtilemez. Örneğin, catch(Exception1 | Exception2 e) kullanılamaz.

  • Genel bağımsız değişkenleri otomatik olarak çıkaramaz. Örneğin, Map map = new HashMap<>(); desteklenmez.

  • Tür bağımsız değişkeni çıkarımı için kullanılan ifadeler yoksayılır. Bağımsız değişken türünü belirtmek için (String) myMap.get(key) gibi cast ifadeleri kullanmanız gerekir.

  • Java sanal makinesinin (JVM) -ea seçeneği kullanılsa bile onaylamalar zorla etkinleştirilir.

  • Java 8'den sonraki sürümlerde programlanmış kod desteklenmez.

UDT'de gömülü koda başvurma

Aşağıdaki kod bir örnek sağlar. SQL deyimlerini betik modunda göndermeniz gerekir. Daha fazla bilgi için bkz. Betik modunda SQL.

SELECT 
  s, 
  com.mypackage.Foo.extractNumber(s) 
FROM VALUES ('abc123def'),('apple') AS t(s);

#CODE ('lang'='JAVA')
package com.mypackage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Foo {
  final static Pattern compile = Pattern.compile(".*?([0-9]+).*");
  public static String extractNumber(String input) {
    final Matcher m = compile.matcher(input);
    if (m.find()) {
      return m.group(1);
    }
    return null;
  }
}
#END CODE;
  • #CODE gömülü kod bloğunun başlangıcını gösterir. #END CODE gömülü kod bloğunun sonunu gösterir. Bu örnekte, gömülü kod bloğu betiğin sonuna yerleştirilir ve tüm betiğe uygulanır.

  • 'lang'='JAVA' gömülü kodun Java olduğunu belirtir. Python'da kod derlerseniz JAVA yerine PYTHON kullanabilirsiniz.

  • SQL betiğinde Foo.extractNumber öğesini çağırmak için UDT sözdizimini kullanabilirsiniz.

Java kod gömülü UDF tanımlama ve çağırma

Aşağıdaki kod bir örnek sağlar. SQL deyimlerini betik modunda göndermeniz gerekir. Daha fazla bilgi için bkz. Betik modunda SQL.

CREATE TEMPORARY FUNCTION foo AS 'com.mypackage.Reverse' USING
#CODE ('lang'='JAVA')
package com.mypackage;
import com.aliyun.odps.udf.UDF;
public class Reverse extends UDF {
  public String evaluate(String input) {
    if (input == null) return null;
    StringBuilder ret = new StringBuilder();
    for (int i = input.toCharArray().length - 1; i >= 0; i--) {
      ret.append(input.toCharArray()[i]);
    }
    return ret.toString();
  }
}
#END CODE;

SELECT foo('abdc');
  • Gömülü kod bloğu USING deyiminin hemen sonrasına veya betiğin sonuna yerleştirilebilir. USING deyiminin hemen sonrasına yerleştirilen kod bloğu yalnızca CREATE TEMPORARY FUNCTION deyimi için geçerlidir.

  • CREATE TEMPORARY FUNCTION ile oluşturulan işlev geçici bir işlevdir. Bu geçici işlev yalnızca mevcut yürütme işlemi sırasında etkili olur ve MaxCompute meta veri sisteminde depolanmaz. Kalıcı bir işlev oluşturup bunu MaxCompute meta veri sisteminde depolama hakkında daha fazla bilgi için bkz. CREATE SQL FUNCTION.

Java kod gömülü UDTF tanımlama ve çağırma

Aşağıdaki kod bir örnek sağlar. SQL deyimlerini betik modunda göndermeniz gerekir. Daha fazla bilgi için bkz. Betik modunda SQL.

CREATE TEMPORARY FUNCTION foo AS 'com.mypackage.Reverse' USING 
#CODE ('lang'='JAVA', 'filename'='embedded.jar')
package com.mypackage;

import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.UDFException;
import com.aliyun.odps.udf.annotation.Resolve;

@Resolve({"string->string,string"})
public class Reverse extends UDTF {
  @Override
  public void process(Object[] objects) throws UDFException {
    String str = (String) objects[0];
    String[] split = str.split(",");
    forward(split[0], split[1]);
  }
}

#END CODE;

SELECT foo('ab,dc') AS (a,b);

@Resolve dönüş değeri string[] türünde olmalıdır. Ancak Janino-compiler, "string->string,string" ifadesini string[] olarak tanımlayamaz. Bu sorunu gidermek için @Resolve ile açıklamalı parametreler {} süslü parantezleri içine alınmalıdır. Ortak bir yöntem kullanarak Java UDTF oluştururken {} süslü parantezleri gerekli değildir.

Python kod gömülü UDF tanımlama ve çağırma

Aşağıdaki kod bir örnek sağlar. SQL deyimlerini betik modunda göndermeniz gerekir. Daha fazla bilgi için bkz. Betik modunda SQL.

CREATE TEMPORARY FUNCTION foo AS 'embedded.UDFTest' USING
#CODE ('lang'='PYTHON', 'filename'='embedded')
from odps.udf import annotate
@annotate("bigint->bigint")
class UDFTest(object):
  def evaluate(self, a):
    return a * a
#END CODE;

SELECT foo(4);
  • Python kodunun girintisi Python dilinin özelliklerine uygun olmalıdır.

  • Python UDF oluştururken, AS yan tümcesinden sonra gelen sınıf adı Python source dosyasının dosya adını içermelidir. Sanal bir dosya adı belirtmek için 'filename'='embedded' kullanabilirsiniz.

  • Farklı Python sürümlerinin geliştirilmesi ve kullanımı hakkında daha fazla bilgi için aşağıdaki konulara bakın: