Tüm Ürünler
Search
Belge Merkezi

MaxCompute:Java UDAF

Son Güncelleme:Oct 10, 2026

Bu konuda, Java'da kullanıcı tanımlı bir toplama işlevi (UDAF) nasıl yazılacağı açıklanmaktadır.

UDAF Kod Yapısı

Java UDAF'i IntelliJ IDEA ile Maven kullanarak veya MaxCompute Studio'ya Giriş yoluyla yazabilirsiniz. Kod aşağıdaki bileşenleri içermelidir:

  • Java paketi: İsteğe bağlı.

    Tanımladığınız Java sınıflarını paketleyerek bunların daha kolay bulunmasını ve yeniden kullanılmasını sağlayabilirsiniz.

  • Gerekli sınıflar ve ek açıklamalar: Zorunlu.

    com.aliyun.odps.udf.Aggregator sınıfını içeri aktarmanız ve @Resolve ek açıklamasını (com.aliyun.odps.udf.annotation.Resolve) kullanmanız gerekir. com.aliyun.odps.udf.UDFException sınıfı isteğe bağlıdır ve hata yönetimi için kullanılabilir. Diğer UDAF ile ilgili sınıfları veya karmaşık veri türlerini kullanmanız gerekiyorsa, gerekli sınıfları MaxCompute UDF'lerine Genel Bakış bölümünde açıklandığı şekilde içeri aktarın.

  • @Resolve ek açıklaması: Zorunlu.

    Biçimi @Resolve(<imza>) şeklindedir; burada signature (imza), giriş parametrelerinin ve dönüş değerinin veri türlerini tanımlayan işlev imzasıdır. Bir UDAF'in işlev imzası yansıma (reflection) yoluyla belirlenemez ve yalnızca @Resolve ek açıklaması kullanılarak alınabilir; örneğin @Resolve("smallint->varchar(10)"). @Resolve ek açıklaması hakkında daha fazla bilgi için bkz. @Resolve Ek Açıklaması.

  • Özel Java sınıfı: Zorunlu.

    Bu sınıf, UDAF kodunun yapısal birimidir. İş mantığınızı uygulayan değişkenleri ve yöntemleri tanımlar.

  • Java sınıfı yöntemleri: Zorunlu.

    Java sınıfınız com.aliyun.odps.udf.Aggregator sınıfından türemeli ve aşağıdaki yöntemleri uygulamalıdır.

    import com.aliyun.odps.udf.ContextFunction;
    import com.aliyun.odps.udf.ExecutionContext;
    import com.aliyun.odps.udf.UDFException;
    public abstract class Aggregator implements ContextFunction {
        // The initialization method.
        @Override
        public void setup(ExecutionContext ctx) throws UDFException {
        }
        // The termination method.
        @Override
        public void close() throws UDFException {
        }
        // Creates an aggregation buffer.
        abstract public Writable newBuffer();
        // The iterate method.
        // buffer is an aggregation buffer that holds intermediate, summarized data. In map tasks, it aggregates data for a group, and this method is executed once for each row.
        // Writable[] represents a row of data, which refers to the input columns in the code. For example, writable[0] refers to the first column, and writable[1] refers to the second column.
        // args are the parameters specified when calling the UDAF in SQL. The args array itself cannot be null, but its elements can be null, which indicates that the corresponding input data is null.
        abstract public void iterate(Writable buffer, Writable[] args) throws UDFException;
        // The terminate method.
        abstract public Writable terminate(Writable buffer) throws UDFException;
        // The merge method.
        abstract public void merge(Writable buffer, Writable partial) throws UDFException;
    }

    iterate, merge ve terminate yöntemleri, bir UDAF'in ana mantığını uygulayan üç temel yöntemdir. Ayrıca özel bir yazılabilir arabellek (writable buffer) uygulamanız gerekir.

    Yazılabilir bir arabellek, bellek içi nesneleri bir bayt dizisine (veya başka bir veri aktarım protokolüne) dönüştürerek diskte kalıcılığı ve ağ üzerinden iletimi kolaylaştırır. MaxCompute, toplama işlevlerini işlemek için dağıtık hesaplamayı kullandığından, verileri çalışanlar arasında aktarmak için verileri seri hale getirmesi (serialize) ve seri hale getirilmiş veriyi çözümlemesi (deserialize) gerekir.

    Bir Java UDAF yazarken Java türlerini veya Java Writable türlerini kullanabilirsiniz. MaxCompute tarafından desteklenen veri türleri ile Java veri türleri arasındaki eşlemeler hakkında daha fazla bilgi için bkz. Veri Türleri.

Aşağıdaki kodda bir UDAF örneği verilmiştir.

// Package the defined Java class in org.alidata.odps.udaf.examples.
package org.alidata.odps.udaf.examples;
// Import the required base classes.
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import com.aliyun.odps.io.DoubleWritable;
import com.aliyun.odps.io.Writable;
import com.aliyun.odps.udf.Aggregator;
import com.aliyun.odps.udf.UDFException;
import com.aliyun.odps.udf.annotation.Resolve;
// Define the custom Java class.
// Specify the @Resolve annotation.
@Resolve("double->double")
public class AggrAvg extends Aggregator {
// Implement the methods for the Java class.
  private static class AvgBuffer implements Writable {
    private double sum = 0;
    private long count = 0;
    @Override
    public void write(DataOutput out) throws IOException {
      out.writeDouble(sum);
      out.writeLong(count);
    }
    @Override
    public void readFields(DataInput in) throws IOException {
      sum = in.readDouble();
      count = in.readLong();
    }
  }
  private DoubleWritable ret = new DoubleWritable();
  @Override
  public Writable newBuffer() {
    return new AvgBuffer();
  }
  @Override
  public void iterate(Writable buffer, Writable[] args) throws UDFException {
    DoubleWritable arg = (DoubleWritable) args[0];
    AvgBuffer buf = (AvgBuffer) buffer;
    if (arg != null) {
      buf.count += 1;
      buf.sum += arg.get();
    }
  }
  @Override
  public Writable terminate(Writable buffer) throws UDFException {
    AvgBuffer buf = (AvgBuffer) buffer;
    if (buf.count == 0) {
      ret.set(0);
    } else {
      ret.set(buf.sum / buf.count);
    }
    return ret;
  }
  @Override
  public void merge(Writable buffer, Writable partial) throws UDFException {
    AvgBuffer buf = (AvgBuffer) buffer;
    AvgBuffer p = (AvgBuffer) partial;
    buf.sum += p.sum;
    buf.count += p.count;
  }
}
Not

Yukarıdaki UDAF kodunda, iterate ve merge yöntemlerindeki arabellek yeniden kullanılabilir. Bu arabellek, uygulamanıza göre giriş satırlarını arabellekte toplar.

Sınırlamalar

  • UDF'leri Kullanarak İnternet'e Erişim

    Varsayılan olarak MaxCompute, UDF'ler kullanarak İnternet'e erişmenize izin vermez. UDF'ler aracılığıyla İnternet'e erişmek istiyorsanız, iş gereksinimlerinize göre ağ bağlantısı başvuru formunu doldurun ve başvuruyu gönderin. MaxCompute teknik destek ekibi, ağ bağlantısını etkinleştirmek için sizinle hızla iletişime geçecektir. Ağ bağlantısı başvuru formunun nasıl doldurulacağı hakkında daha fazla bilgi için bkz. Ağ Bağlantı Süreci.

  • UDF'leri Kullanarak VPC'ye Erişim

    Varsayılan olarak MaxCompute, UDF'ler kullanarak VPC'lerdeki kaynaklara erişmenize izin vermez. UDF'leri kullanarak bir VPC'deki kaynaklara erişmek için MaxCompute ile VPC arasında bir ağ bağlantısı kurmanız gerekir. İlgili işlemler hakkında daha fazla bilgi için bkz. UDF'den VPC Kaynaklarına Erişim.

  • UDF'ler, UDAF'ler veya UDTF'ler Kullanarak Tablo Verilerini Okuma

    Aşağıdaki tablo türlerinden veri okumak için UDF'leri, UDAF'leri veya UDTF'leri kullanamazsınız:

    • Şema evriminin uygulandığı tablo

    • Karmaşık veri türleri içeren tablo

    • JSON veri türleri içeren tablo

    • İşlemsel tablo

Kullanım Notları

Bir Java UDAF yazarken aşağıdaki noktalara dikkat edin:

  • Farklı UDAF'lerin JAR dosyalarında aynı ada sahip ancak farklı mantığa sahip sınıfların bulunması, beklenmeyen sonuçlara veya derleme hatalarına yol açabilir. Örneğin, UDAF1 ve UDAF2'nin sırasıyla udaf1.jar ve udaf2.jar kaynak JAR dosyalarına karşılık geldiğini varsayalım. Her iki JAR dosyası da com.aliyun.UserFunction.class adında bir sınıf içeriyor ancak uygulamaları farklıysa, aynı SQL ifadesinde hem UDAF1 hem de UDAF2 çağrıldığında MaxCompute sınıflardan birini öngörülemez bir şekilde yükler.

  • Bir Java UDAF'te giriş parametreleri ve dönüş değeri, ilkel türler (primitive types) yerine String ve Long gibi nesne türleri olmalıdır.

  • SQL'deki NULL değerleri Java NULL ile temsil edilir. Java ilkel türleri SQL'deki NULL değerlerini temsil edemez ve kullanılamaz.

@Resolve Ek Açıklaması

@Resolve ek açıklamasının biçimi aşağıdaki gibidir.

@Resolve(<signature>)

signature (imza), giriş parametrelerinin ve dönüş değerinin veri türlerini tanımlayan bir dizedir. Bir UDAF yürütüldüğünde, giriş parametrelerinin ve dönüş değerinin türleri işlev imzasında belirtilen türlerle eşleşmelidir. Anlamsal ayrıştırma sırasında sistem, işlev imzasına uymayan kullanımları kontrol eder ve bir tür uyumsuzluğu oluşursa hata bildirir. Belirli biçim aşağıdaki gibidir.

'arg_type_list -> type'

Açıklama:

  • arg_type_list: Giriş parametrelerinin veri türlerini temsil eder. Birden fazla giriş parametresi virgül (,) ile ayrılarak belirtilebilir. Desteklenen veri türleri BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(hassasiyet,ölçek), CHAR, VARCHAR, karmaşık veri türleri (ARRAY, MAP, STRUCT) ve iç içe geçmiş karmaşık veri türleridir.

    arg_type_list ayrıca yıldız işareti (*) veya boş bir dize ('') destekler.

    • arg_type_list bir yıldız işareti (*) ise, işlevin herhangi bir sayıda giriş parametresini kabul ettiğini gösterir.

    • arg_type_list boş bir dize ('') ise, işlevin hiçbir giriş parametresi olmadığını gösterir.

    Resolve ek açıklamasının genişletilmiş sözdizimi hakkında daha fazla bilgi için bkz. UDAF'ler ve UDTF'ler İçin Dinamik Parametreler.

  • type: Dönüş değerinin veri türünü temsil eder. Bir UDAF yalnızca bir sütun döndürür. Desteklenen veri türleri BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(hassasiyet,ölçek), karmaşık veri türleri (ARRAY, MAP, STRUCT) ve iç içe geçmiş karmaşık veri türlerini içerir.

Not

UDAF kodu yazarken MaxCompute projenizin veri türü sürümüne göre uygun veri türlerini seçebilirsiniz. Veri türü sürümleri ve her sürüm tarafından desteklenen veri türleri hakkında daha fazla bilgi için bkz. Veri Türü Sürümleri.

Aşağıda geçerli @Resolve ek açıklamalarına örnekler verilmiştir.


@Resolve Örneği


Açıklama


@Resolve('bigint,double->string')


Giriş parametresi türleri BIGINT ve DOUBLE, dönüş değeri türü STRING'dir.


@Resolve('*->string')


Herhangi bir sayıda giriş parametresini kabul eder ve dönüş değeri türü STRING'dir.


@Resolve('->double')


Hiçbir giriş parametresi kabul etmez ve dönüş değeri türü DOUBLE'dır.


@Resolve('array<bigint>->struct<x:string, y:int>')


Giriş parametresi türü ARRAY<BIGINT>, dönüş değeri türü STRUCT<x:STRING, y:INT>'dir.

Veri Türleri

MaxCompute tarafından desteklenen veri türleri veri türü sürümüne göre değişir. MaxCompute 2.0'dan başlayarak, ARRAY, MAP ve STRUCT gibi karmaşık türler dahil olmak üzere ek veri türleri kullanılabilir. Daha fazla bilgi için bkz. Veri Türü Sürümleri.

Java UDAF'iniz, MaxCompute'daki türlerle eşleşen veri türlerini kullanmalıdır. Aşağıdaki tabloda bu eşlemeler açıklanmaktadır.


MaxCompute Türü


Java Türü


Java Writable Türü


TINYINT


java.lang.Byte


ByteWritable


SMALLINT


java.lang.Short


ShortWritable


INT


java.lang.Integer


IntWritable


BIGINT


java.lang.Long


LongWritable


FLOAT


java.lang.Float


FloatWritable


DOUBLE


java.lang.Double


DoubleWritable


DECIMAL


java.math.BigDecimal


BigDecimalWritable


BOOLEAN


java.lang.Boolean


BooleanWritable


STRING


java.lang.String


Text


VARCHAR


com.aliyun.odps.data.Varchar


VarcharWritable


BINARY


com.aliyun.odps.data.Binary


BytesWritable


DATE


java.sql.Date


DateWritable


DATETIME


java.util.Date


DatetimeWritable


TIMESTAMP


java.sql.Timestamp


TimestampWritable


INTERVAL_YEAR_MONTH


N/A


IntervalYearMonthWritable


INTERVAL_DAY_TIME


N/A


IntervalDayTimeWritable


ARRAY


java.util.List


N/A


MAP


java.util.Map


N/A


STRUCT


com.aliyun.odps.data.Struct


N/A

Not

Bir UDAF'in giriş parametreleri veya dönüş değeri, MaxCompute projeniz MaxCompute V2.0 veri türü sürümünü kullanıyorsa yalnızca Java Writable Türünü kullanabilir.

Kullanım

Java UDAF'i geliştirme sürecini izleyerek geliştirdikten sonra, bunu MaxCompute SQL'de aşağıdaki gibi çağırabilirsiniz:

  • Bir MaxCompute projesinde UDF kullanma: Yöntemi, yerleşik işlevleri kullanmaya benzer. Kullanıcı tanımlı bir işlevi, yerleşik bir işlevi kullandığınız şekilde kullanabilirsiniz.

  • Projeler arası UDF kullanma: B Projesindeki bir UDF'yi A Projesinde kullanma. Aşağıdaki ifade bir örnek gösterir: select B:udf_in_other_project(arg0, arg1) as res from table_t;. Projeler arası paylaşım hakkında daha fazla bilgi için bkz. Paketlere Dayalı Projeler Arası Kaynak Erişimi.

MaxCompute Studio kullanarak bir Java UDAF'in nasıl geliştirileceği ve çağrılacağına ilişkin tam bir örnek için bkz. Örnek.

Örnek

Bu örnek, ortalama bir değeri hesaplayan AggrAvg adlı bir UDAF geliştirmek için MaxCompute Studio'nun nasıl kullanılacağını gösterir. Aşağıdaki şekil mantığı görselleştirir.

求平均值逻辑

  1. Giriş verisi dilimleme: MaxCompute, bir çalışanın verimli bir şekilde işleyebileceği dilimlere giriş verilerini bölmek için MapReduce işleme iş akışını takip eder.

    Dilim boyutunu odps.stage.mapper.split.size parametresini kullanarak yapılandırmanız gerekir.

  2. Ortalama hesaplamanın ilk aşaması: Her çalışan, kendi dilimindeki veri kayıtlarının sayısını sayar ve toplamlarını hesaplar. Her dilimden elde edilen sayım ve toplam, bir ara sonuç olarak kabul edilir.

  3. Ortalama hesaplamanın ikinci aşaması: İlk aşamadaki her dilimden gelen ara sonuçlar toplanır.

  4. Son çıktı: r.sum/r.count tüm giriş verilerinin ortalamasıdır.

Aşağıdaki adımlarda Java UDAF'in nasıl geliştirileceği ve çağrılacağı açıklanmaktadır:

  1. Ortamı hazırlayın.

    MaxCompute Studio'da bir UDF geliştirmeden ve hata ayıklamadan önce MaxCompute Studio'yu yüklemeniz ve bir MaxCompute projesine bağlamanız gerekir. Daha fazla bilgi için aşağıdaki konulara bakın:

    1. MaxCompute Studio'yu Yükleme

    2. Bir MaxCompute Projesine Bağlanma

    3. Bir MaxCompute Java Modülü Oluşturma

  2. UDAF kodunu yazın

    1. Project gezgininde, modülün kaynak kodu dizinine (src > main > java) sağ tıklayın ve New > MaxCompute Java öğelerini seçin.

    2. Create new MaxCompute java class iletişim kutusunda UDAF seçeneğine tıklayın, Name alanına bir ad girin ve Enter tuşuna basın. Bu örnek için Java sınıfının adını AggrAvg olarak belirleyin.

      Name, MaxCompute Java sınıfının adıdır. Bir paket oluşturmadıysanız, adı packagename.classname formatında girin. Bir paket otomatik olarak oluşturulur.

    3. Kod düzenleyicide aşağıdaki UDAF kodunu yapıştırın.

      import java.io.DataInput;
      import java.io.DataOutput;
      import java.io.IOException;
      import com.aliyun.odps.io.DoubleWritable;
      import com.aliyun.odps.io.Writable;
      import com.aliyun.odps.udf.Aggregator;
      import com.aliyun.odps.udf.UDFException;
      import com.aliyun.odps.udf.annotation.Resolve;
      @Resolve("double->double")
      public class AggrAvg extends Aggregator {
        private static class AvgBuffer implements Writable {
          private double sum = 0;
          private long count = 0;
          @Override
          public void write(DataOutput out) throws IOException {
            out.writeDouble(sum);
            out.writeLong(count);
          }
          @Override
          public void readFields(DataInput in) throws IOException {
            sum = in.readDouble();
            count = in.readLong();
          }
        }
        private DoubleWritable ret = new DoubleWritable();
        @Override
        public Writable newBuffer() {
          return new AvgBuffer();
        }
        @Override
        public void iterate(Writable buffer, Writable[] args) throws UDFException {
          DoubleWritable arg = (DoubleWritable) args[0];
          AvgBuffer buf = (AvgBuffer) buffer;
          if (arg != null) {
            buf.count += 1;
            buf.sum += arg.get();
          }
        }
        @Override
        public Writable terminate(Writable buffer) throws UDFException {
          AvgBuffer buf = (AvgBuffer) buffer;
          if (buf.count == 0) {
            ret.set(0);
          } else {
            ret.set(buf.sum / buf.count);
          }
          return ret;
        }
        @Override
        public void merge(Writable buffer, Writable partial) throws UDFException {
          AvgBuffer buf = (AvgBuffer) buffer;
          AvgBuffer p = (AvgBuffer) partial;
          buf.sum += p.sum;
          buf.count += p.count;
        }
      }
  3. UDAF'i yerel olarak hata ayıklayın

    Daha fazla hata ayıklama işlemi için bkz. UDF'leri Yerel Olarak Çalıştırarak Hata Ayıklama.

    Projenizdeki AggrAvg.java dosyasına sağ tıklayın ve Run 'AggrAvg.main()' seçeneğini belirleyin. Görünen Run/Debug Configurations iletişim kutusunda aşağıdaki parametreleri yapılandırın: MaxCompute project için local, MaxCompute table için kmeans_in, Table columns için dim1,dim2, Download Record limit için 100 ve Data Column Separator için virgül. Ardından OK düğmesine tıklayın.

    Not

    Çalıştırma parametreleri için referans olarak şekilde gösterilen verileri kullanabilirsiniz.

  4. Oluşturduğunuz UDAF'i bir JAR dosyasında paketleyin, JAR dosyasını bir MaxCompute projesine yükleyin ve işlevi kaydedin. Örneğin, işlevin adı user_udaf olsun.

    Paketleme işlemleri hakkında daha fazla bilgi için bkz. Adımlar.

    IntelliJ IDEA'da, UDAF'i içeren Java dosyasına sağ tıklayın ve Deploy to server... seçeneğini belirleyin. Package a jar, submit resource and register function iletişim kutusunda MaxCompute project, Resource name, Main class (UDAF sınıf adını girin) ve Function name seçeneklerini yapılandırın. Force update if already exists onay kutusunu seçin ve dağıtımı tamamlamak için OK düğmesine tıklayın.

  5. MaxCompute Studio'nun sol gezinme bölmesinde Project Explorer seçeneğine tıklayın, hedef MaxCompute projesine sağ tıklayın, MaxCompute istemcisini başlatın ve yeni oluşturulan UDAF'i çağırmak için bir SQL komutu yürütün.

    Hedef tablo my_table için şema ve verilerin aşağıdaki gibi olduğunu varsayalım.

    +------------+------------+
    | col0       | col1       |
    +------------+------------+
    | 1.2        | 2.0        |
    | 1.6        | 2.1        |
    +------------+------------+

    UDAF'i çağırmak için aşağıdaki SQL ifadesini çalıştırın.

    select user_udaf(col0) as c0 from my_table;

    Aşağıdaki sonuç döndürülür.

    +----+
    | c0 |
    +----+
    | 1.4|
    +----+