Tüm Ürünler
Search
Belge Merkezi

Realtime Compute for Apache Flink:Java UDSF'leri

Son Güncelleme:Oct 04, 2026

Kullanıcı tanımlı skaler işlev (UDSF), sıfır, bir veya daha fazla skaler değeri yeni bir skaler değere eşler; böylece giriş satırları ile çıkış değerleri arasında birebir ilişki kurulur. Yerleşik Flink SQL işlevleri özel mantığınızı ifade edemediğinde UDSF kullanın.

Tüm kullanıcı tanımlı işlev (UDF) türlerine genel bakış için bkz. Kullanıcı tanımlı işlevler.

Nasıl çalışır

UDSF, Apache Flink'in ScalarFunction sınıfını genişletir ve bir veya daha fazla eval() yöntemi uygular. Flink, her giriş satırı için eval() yöntemini bir kez çağırır ve dönüş değerini çıkış skaleri olarak kullanır.

public class SubstringFunction extends ScalarFunction {
    public String eval(String s, Integer begin, Integer end) {
        return s.substring(begin, end);
    }
}

eval() yöntemi gereksinimleri:

  • public olarak bildirilmelidir

  • Yöntem aşırı yüklemeyi destekler — farklı giriş türleri için birden fazla eval() imzası tanımlayabilirsiniz

  • Değişken sayıda bağımsız değişkeni (varargs) destekler (örneğin, eval(Integer...))

  • NULL girişlerini doğru işlemek için kutulanmış ilkel türler kullanın (örneğin, int yerine Integer)

Ön koşullar

Başlamadan önce şunlara sahip olduğunuzdan emin olun:

  • IntelliJ IDEA yüklü olmalı

  • Apache Maven yüklü olmalı

  • Realtime Compute for Apache Flink çalışma alanına erişiminiz olmalı

Eşzamansız skaler işlevler (AsyncScalarFunction)

Normal bir skaler işlevin aksine, özel bir eşzamansız skaler işlev AsyncScalarFunction sınıfını genişletmeli ve sonuçları bir CompletableFuture aracılığıyla döndürmelidir.

İşlev, harici bir veritabanını sorgulamak veya bir HTTP arayüzünü çağırmak gibi G/Ç bekleme süresi içeren işlemler yürüttüğünde eşzamansız skaler işlev kullanın. İşlev, birden çok kaydı eşzamanlı olarak işleyerek bekleme süresinin iş aktarım hızı üzerindeki etkisini azaltır. Dize kısaltma ve sayısal hesaplama gibi harici hizmetler için bekleme gerektirmeyen işlemler için genellikle eşzamanlı bir skaler işlev yeterlidir.

Yapılandırma parametreleri

Aşağıdaki parametreler, eşzamansız skaler işlevlerin çalışma zamanı davranışını kontrol eder. Bir sorgu göndermeden veya yürütme planı oluşturmadan önce bu parametreleri ayarlayın.


Parametre


Varsayılan değer


Açıklama


table.exec.async-scalar.max-concurrent-operations


10


Her eşzamansız işleç örneği için izin verilen maksimum eşzamanlı eşzamansız işlem sayısı. Daha büyük bir değer, harici hizmet üzerindeki eşzamanlılık baskısını artırır.


table.exec.async-scalar.timeout


3 min


Yeniden denemeler dahil, tek bir kaydın eşzamansız olarak işlenmesi için zaman aşımı süresi.


table.exec.async-scalar.retry-strategy


FIXED_DELAY

FIXED_DELAY, başarısızlıktan sonra sabit aralıklarla yeniden dener. NO_RETRY yeniden denemeyi devre dışı bırakır.


table.exec.async-scalar.retry-delay


100 ms


Sabit aralıklı yeniden denemeler arasındaki bekleme süresi. Bu parametre yalnızca yeniden deneme stratejisi FIXED_DELAY olduğunda etkili olur.


table.exec.async-scalar.max-attempts


3


Maksimum yeniden deneme sayısı. Bu parametre yalnızca yeniden deneme stratejisi FIXED_DELAY olduğunda etkili olur.


table.exec.async-scalar.output-mode


ORDERED

ORDERED, giriş sırasını korur. ALLOW_UNORDERED, giriş ekleme amaçlı bir akış olduğunda sırasız çıktıya izin verir. Bu parametre VVR 11.8.0 ve sonraki sürümlerde desteklenir.

Sırasız çıktıyı yapılandırma

Varsayılan olarak, eşzamansız işlevler eşzamanlı olarak çalışır ancak sonraki bir kayıt için tamamlanan sonuç, yalnızca önceki kayıtlar tamamlandıktan sonra yayımlanır. Harici istek gecikme süreleri önemli ölçüde farklılık gösteriyorsa ve işiniz sırasız sonuçları tolere ediyorsa, yavaş isteklerden kaynaklanan beklemeyi azaltmak için sırasız çıktıyı etkinleştirin.

Not

Eşzamansız çağrı ve sırasız çıktı iki bağımsız kavramdır. Varsayılan olarak, eşzamansız bir skaler işlev eşzamanlı olarak çağrılır ve sonuçları giriş sırasına göre yayımlar. Sırasız çıktıya izin verdikten sonra sistem, giriş verilerinin değişiklik türüne göre bunu etkinleştirip etkinleştirmeyeceğine karar verir.

Sorguyu çalıştırmadan önce aşağıdaki yapılandırmayı ekleyin:

SET 'table.exec.async-scalar.output-mode' = 'ALLOW_UNORDERED';

Özel eşzamansız skaler işlev örneği

Aşağıdaki örnek, bir ürün hizmetinin HTTP arayüzü aracılığıyla ürün adlarını sorgular. İşlev, open yönteminde bir HttpClient oluşturur ve yeniden kullanır; eval yönteminde isteği göndermek için sendAsync() yöntemini çağırır ve sonucu tamamlama geri araması aracılığıyla döndürür. sendAsync() bir CompletableFuture döndürür; bu da HTTP çağrılarını eşzamansız skaler işlevlere bağlamak için uygundur. Daha fazla bilgi için bkz. JDK HttpClient belgeleri.

Örnek, 3 saniyelik bağlantı zaman aşımı ve 5 saniyelik istek zaman aşımı kullanır; bu, yanıt gövdeleri küçük olan ürün adı sorguları için uygundur. Değerleri, arayüzünüzün gerçek yanıt süresine göre ayarlayın.

package com.example.udf;

import org.apache.flink.table.functions.AsyncScalarFunction;
import org.apache.flink.table.functions.FunctionContext;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

/**
 * Queries a product name through an asynchronous HTTP interface.
 *
 * <p>Interface contract: 200 returns a UTF-8 product name, and 404 indicates that the product does not exist.
 * This example suits read-only queries that return short text. Other status codes are treated as invocation failures and handed over to the engine.
 */
public class AsyncProductName extends AsyncScalarFunction {

    private transient HttpClient client;
    private transient URI serviceBaseUri;

    @Override
    public void open(FunctionContext context) {
        String baseUrl = context.getJobParameter("product.service.base-url", null);
        if (baseUrl == null || baseUrl.isBlank()) {
            throw new IllegalArgumentException("Configure product.service.base-url.");
        }
        serviceBaseUri = URI.create(baseUrl);
        if (!("https".equalsIgnoreCase(serviceBaseUri.getScheme())
                        || "http".equalsIgnoreCase(serviceBaseUri.getScheme()))
                || serviceBaseUri.getHost() == null
                || serviceBaseUri.getRawQuery() != null
                || serviceBaseUri.getRawFragment() != null
                || !baseUrl.endsWith("/")) {
            throw new IllegalArgumentException("The service URL must be an HTTP(S) base URL that ends with a forward slash (/).");
        }
        client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(3)).build();
    }

    @Override
    public boolean isDeterministic() {
        // Product information may change. The same ID may return different results at different times.
        return false;
    }

    public void eval(CompletableFuture<String> result, Long productId) {
        if (productId == null) {
            result.complete(null);
            return;
        }

        try {
            HttpRequest request =
                    HttpRequest.newBuilder(
                                    serviceBaseUri.resolve("products/" + productId + "/name"))
                            .timeout(Duration.ofSeconds(5))
                            .header("Accept", "text/plain")
                            .GET()
                            .build();

            client.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8))
                    .thenApply(
                            response -> {
                                if (response.statusCode() == 200) {
                                    return response.body();
                                }
                                if (response.statusCode() == 404) {
                                    return null;
                                }
                                throw new CompletionException(
                                        new IOException(
                                                "Failed to query the product. HTTP status code: " + response.statusCode()));
                            })
                    .whenComplete(
                            (name, error) -> {
                                if (error != null) {
                                    result.completeExceptionally(error);
                                } else {
                                    result.complete(name);
                                }
                            });
        } catch (RuntimeException e) {
            result.completeExceptionally(e);
        }
    }
}

Geliştirme sırasında aşağıdaki hususlara dikkat edin:

  • Sonuç döndürmek için result.complete(value) yöntemini çağırın. Bir SQL NULL değeri döndürmek için result.complete(null) yöntemini çağırın.

  • Bir çağrı başarısız olduğunda, özel durumu döndürmek için result.completeExceptionally(exception) yöntemini çağırın. Motor ardından bu özel durumu yeniden deneme stratejisine göre işler.

  • eval yöntemi, istek gönderildikten hemen sonra döner. Sonuçları sendAsync() yönteminin tamamlama geri araması aracılığıyla iletin. Engelleyen send(), get() veya join() yöntemlerini çağırmayın; eval yönteminde veya geri aramada zaman alıcı hesaplamalar yapmayın.

  • Her işlev örneği, her kayıt için istemci oluşturmayı önlemek amacıyla open yönteminde istemciyi başlatır ve yeniden kullanır. JDK 11 ve JDK 17'deki HttpClient genel bir close() yöntemi sunmaz ve dahili kaynakları JDK tarafından yönetilir. Kapatma yöntemi sağlayan başka bir eşzamansız istemci kullanıyorsanız, istemciyi işlevin close yönteminde serbest bırakın.

  • Ürün bilgileri zamanla değiştiğinden örnek, isDeterministic() yöntemini false olarak ayarlar. Güncelleme akışları söz konusu olduğunda, sorgu anlambilimine göre deterministik olmayan sonuçları işleyin.

UDSF geliştirme

Flink, geliştirme ortamını önceden yapılandıran UDF örnekleri sunar. Örnekler UDSF'leri, kullanıcı tanımlı toplama işlevlerini (UDAF) ve kullanıcı tanımlı tablo değerli işlevleri (UDTF) kapsar.
  1. ASI_UDX_Demo örneğini indirin ve yerel makinenizde açın. Açma işleminden sonra aşağıdaki yapıya sahip ASI_UDX-main klasörü oluşturulur:

    • pom.xml: Maven proje yapılandırma dosyası. Projenin koordinatlarını, bağımlılıklarını, derleme kurallarını ve ilgili meta verilerini tanımlar.

    • \ASI_UDX-main\src\main\java\ASI_UDF\ASI_UDF.java: UDSF'nin örnek Java uygulaması.

    ASI_UDX_Demo üçüncü taraf bir web sitesinde barındırılmaktadır. Erişim hataları veya gecikmeler yaşayabilirsiniz.
  2. IntelliJ IDEA'da File > Open seçeneğine tıklayın ve ASI_UDX-main klasörünü seçin.

  3. \ASI_UDX-main\src\main\java\ASI_UDF\ASI_UDF.java dosyasını açın ve eval() yöntemini özel mantığınızla güncelleyin. Örnek uygulama, her giriş dizesinin begin konumundan end konumuna kadar karakterleri çıkarır:

    package ASI_UDF;
    
    import org.apache.flink.table.functions.ScalarFunction;
    
    public class ASI_UDF extends ScalarFunction {
        public String eval(String s, Integer begin, Integer end) {
            return s.substring(begin, end);
        }
    }
  4. \ASI_UDX-main\pom.xml dosyasını açın ve Flink sürümünüz için Maven bağımlılıklarını yapılandırın. Aşağıdaki örnek, Flink 1.11 için ana JAR paketi bağımlılıklarını gösterir. UDSF'niz ek JAR paketlerine bağımlı değilse bu adımı atlayın.

    <dependencies>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-java_2.12</artifactId>
            <version>1.11.0</version>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table</artifactId>
            <version>1.11.0</version>
            <type>pom</type>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-core</artifactId>
            <version>1.11.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table-common</artifactId>
            <version>1.11.0</version>
        </dependency>
    </dependencies>
  5. pom.xml dosyasını içeren dizinde projeyi paketlemek için aşağıdaki komutu çalıştırın:

    mvn package -Dcheckstyle.skip

    Derleme tamamlandıktan sonra \ASI_UDX-main\target\ dizininde ASI_UDX-1.0-SNAPSHOT.jar dosyası oluşturulur.

UDSF kaydetme

JAR paketini UDSF olarak kaydetmek için bkz. Kullanıcı tanımlı işlevleri (UDF) yönetme.

UDSF kullanma

Kayıttan sonra UDSF'yi bir Flink SQL işinde çağırın.

  1. Bir Flink SQL işi oluşturun. Rehberlik için bkz. İş geliştirme haritası. Aşağıdaki örnek SQL, ASI_UDSF_Source tablosunun a alanındaki dizenin ikinci konumundan dördüncü konumuna kadar karakterleri çıkarır ve sonuçları ASI_UDSF_Sink tablosuna yazar:

    CREATE TEMPORARY TABLE ASI_UDSF_Source (
      a VARCHAR,
      b INT,
      c INT
    ) WITH (
      'connector' = 'datagen'
    );
    
    CREATE TEMPORARY TABLE ASI_UDSF_Sink (
      a VARCHAR
    ) WITH (
      'connector' = 'blackhole'
    );
    
    INSERT INTO ASI_UDSF_Sink
    SELECT ASI_UDSF(a, 2, 4)
    FROM ASI_UDSF_Source;
  2. Operation Center > Job O&M sayfasında işinizi bulun ve Actions sütununda Start seçeneğine tıklayın. İş başladıktan sonra, ASI_UDSF_Source tablosundaki her satırın a alanının ikinci konumundan dördüncü konumuna kadar karakterler ASI_UDSF_Sink tablosuna eklenir.