Flink Core --- 算子函数

本文介绍了Flink数据流处理中的三个关键算子:Map用于转化数据形成新数据流;FlatMap用于将整体拆分为个体,产生零到多个元素;Filter则用于根据条件过滤数据流中的元素。

目录

 

 

1. Map: 将数据流中的数据进行转化

2.FlatMap : 将数据流中的整体拆分个体使用

3.Filter 对流中的元素进行过滤,瞒住条件的返回, 不满足条件的过滤掉

 

 

 

1. Map: 将数据流中的数据进行一个转化,形成一个新的数据流,消费一个元素,并且产生一个元素

package com.wudl.core;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
 * @version v1.0
 * @ProjectName Flinklearning
 * @ClassName WordMap
 * @Description TODO map 算子实例
 * @Author wudl
 * @Date 2020/10/29 10:15
 */
public class WordMap {
    /**
     * @param args
     * Map 函数的用法
     * 映射:将数据流中的数据进行一个转化,形成一个新的数据流,消费一个元素,并且产生一个元素
     *参数: Lambda 表达式或者,new MapFunction实现类
     * 返回值:DataStream
     */
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setMaxParallelism(1);
        env.socketTextStream("10.204.125.140", 8899)
                .map(new MapFunction<String, String>() {
                    @Override
                    public String map(String s) throws Exception {
                        String[] split = s.split(",");
                        return split[0] + "---" + split[1];
                    }
                }).print();
        env.execute();
    }
}
"C:\Program Files\Java\jdk1.8.0_241\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2023.3.4\lib\idea_rt.jar=60962:D:\IntelliJ IDEA 2023.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar;C:\Users\18795\IdeaProjects\demo11\target\classes;D:\Maven安装\Maven_Repository\org\apache\flink\flink-scala_2.12\1.14.0\flink-scala_2.12-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-core\1.14.0\flink-core-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-annotations\1.14.0\flink-annotations-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-metrics-core\1.14.0\flink-metrics-core-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\commons\commons-lang3\3.3.2\commons-lang3-3.3.2.jar;D:\Maven安装\Maven_Repository\com\esotericsoftware\kryo\kryo\2.24.0\kryo-2.24.0.jar;D:\Maven安装\Maven_Repository\com\esotericsoftware\minlog\minlog\1.2\minlog-1.2.jar;D:\Maven安装\Maven_Repository\org\objenesis\objenesis\2.1\objenesis-2.1.jar;D:\Maven安装\Maven_Repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;D:\Maven安装\Maven_Repository\org\apache\commons\commons-compress\1.21\commons-compress-1.21.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-guava\30.1.1-jre-14.0\flink-shaded-guava-30.1.1-jre-14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-java\1.14.0\flink-java-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\commons\commons-math3\3.5\commons-math3-3.5.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-asm-7\7.1-14.0\flink-shaded-asm-7-7.1-14.0.jar;D:\Maven安装\Maven_Repository\org\scala-lang\scala-reflect\2.12.7\scala-reflect-2.12.7.jar;D:\Maven安装\Maven_Repository\org\scala-lang\scala-compiler\2.12.7\scala-compiler-2.12.7.jar;D:\Maven安装\Maven_Repository\org\scala-lang\modules\scala-xml_2.12\1.0.6\scala-xml_2.12-1.0.6.jar;D:\Maven安装\Maven_Repository\com\twitter\chill_2.12\0.7.6\chill_2.12-0.7.6.jar;D:\Maven安装\Maven_Repository\com\twitter\chill-java\0.7.6\chill-java-0.7.6.jar;D:\Maven安装\Maven_Repository\org\slf4j\slf4j-api\1.7.15\slf4j-api-1.7.15.jar;D:\Maven安装\Maven_Repository\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-force-shading\14.0\flink-shaded-force-shading-14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-streaming-scala_2.12\1.14.0\flink-streaming-scala_2.12-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-streaming-java_2.12\1.14.0\flink-streaming-java_2.12-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-file-sink-common\1.14.0\flink-file-sink-common-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-connector-kafka\1.17.2\flink-connector-kafka-1.17.2.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-connector-base\1.17.2\flink-connector-base-1.17.2.jar;D:\Maven安装\Maven_Repository\org\apache\kafka\kafka-clients\3.2.3\kafka-clients-3.2.3.jar;D:\Maven安装\Maven_Repository\com\github\luben\zstd-jni\1.5.2-1\zstd-jni-1.5.2-1.jar;D:\Maven安装\Maven_Repository\org\lz4\lz4-java\1.8.0\lz4-java-1.8.0.jar;D:\Maven安装\Maven_Repository\org\xerial\snappy\snappy-java\1.1.8.4\snappy-java-1.1.8.4.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-clients_2.12\1.14.0\flink-clients_2.12-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-runtime\1.14.0\flink-runtime-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-rpc-core\1.14.0\flink-rpc-core-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-rpc-akka-loader\1.14.0\flink-rpc-akka-loader-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-queryable-state-client-java\1.14.0\flink-queryable-state-client-java-1.14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-hadoop-fs\1.14.0\flink-hadoop-fs-1.14.0.jar;D:\Maven安装\Maven_Repository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-netty\4.1.65.Final-14.0\flink-shaded-netty-4.1.65.Final-14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-jackson\2.12.4-14.0\flink-shaded-jackson-2.12.4-14.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-zookeeper-3\3.4.14-14.0\flink-shaded-zookeeper-3-3.4.14-14.0.jar;D:\Maven安装\Maven_Repository\org\javassist\javassist\3.24.0-GA\javassist-3.24.0-GA.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-optimizer\1.14.0\flink-optimizer-1.14.0.jar;D:\Maven安装\Maven_Repository\commons-cli\commons-cli\1.3.1\commons-cli-1.3.1.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-connector-jdbc_2.12\1.14.0\flink-connector-jdbc_2.12-1.14.0.jar;D:\Maven安装\Maven_Repository\com\h2database\h2\1.4.200\h2-1.4.200.jar;D:\Maven安装\Maven_Repository\io\github\jeff-zou\flink-connector-redis\1.4.3\flink-connector-redis-1.4.3.jar;D:\Maven安装\Maven_Repository\io\lettuce\lettuce-core\6.2.1.RELEASE\lettuce-core-6.2.1.RELEASE.jar;D:\Maven安装\Maven_Repository\io\netty\netty-common\4.1.82.Final\netty-common-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-handler\4.1.82.Final\netty-handler-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-resolver\4.1.82.Final\netty-resolver-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-codec\4.1.82.Final\netty-codec-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-transport\4.1.82.Final\netty-transport-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\projectreactor\reactor-core\3.4.23\reactor-core-3.4.23.jar;D:\Maven安装\Maven_Repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\Maven安装\Maven_Repository\io\netty\netty-transport-native-epoll\4.1.82.Final\netty-transport-native-epoll-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-buffer\4.1.82.Final\netty-buffer-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-transport-native-unix-common\4.1.82.Final\netty-transport-native-unix-common-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\io\netty\netty-transport-classes-epoll\4.1.82.Final\netty-transport-classes-epoll-4.1.82.Final.jar;D:\Maven安装\Maven_Repository\org\apache\bahir\flink-connector-redis_2.11\1.0\flink-connector-redis_2.11-1.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-streaming-java_2.11\1.2.0\flink-streaming-java_2.11-1.2.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-runtime_2.11\1.2.0\flink-runtime_2.11-1.2.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-shaded-hadoop2\1.2.0\flink-shaded-hadoop2-1.2.0.jar;D:\Maven安装\Maven_Repository\org\tukaani\xz\1.0\xz-1.0.jar;D:\Maven安装\Maven_Repository\xmlenc\xmlenc\0.52\xmlenc-0.52.jar;D:\Maven安装\Maven_Repository\commons-codec\commons-codec\1.4\commons-codec-1.4.jar;D:\Maven安装\Maven_Repository\commons-net\commons-net\3.1\commons-net-3.1.jar;D:\Maven安装\Maven_Repository\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar;D:\Maven安装\Maven_Repository\org\mortbay\jetty\jetty-util\6.1.26\jetty-util-6.1.26.jar;D:\Maven安装\Maven_Repository\com\sun\jersey\jersey-core\1.9\jersey-core-1.9.jar;D:\Maven安装\Maven_Repository\commons-el\commons-el\1.0\commons-el-1.0.jar;D:\Maven安装\Maven_Repository\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;D:\Maven安装\Maven_Repository\com\jamesmurty\utils\java-xmlbuilder\0.4\java-xmlbuilder-0.4.jar;D:\Maven安装\Maven_Repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\Maven安装\Maven_Repository\commons-configuration\commons-configuration\1.7\commons-configuration-1.7.jar;D:\Maven安装\Maven_Repository\commons-digester\commons-digester\1.8.1\commons-digester-1.8.1.jar;D:\Maven安装\Maven_Repository\org\codehaus\jackson\jackson-core-asl\1.8.8\jackson-core-asl-1.8.8.jar;D:\Maven安装\Maven_Repository\org\codehaus\jackson\jackson-mapper-asl\1.8.8\jackson-mapper-asl-1.8.8.jar;D:\Maven安装\Maven_Repository\org\apache\avro\avro\1.7.7\avro-1.7.7.jar;D:\Maven安装\Maven_Repository\com\thoughtworks\paranamer\paranamer\2.3\paranamer-2.3.jar;D:\Maven安装\Maven_Repository\com\jcraft\jsch\0.1.42\jsch-0.1.42.jar;D:\Maven安装\Maven_Repository\commons-beanutils\commons-beanutils-bean-collections\1.8.3\commons-beanutils-bean-collections-1.8.3.jar;D:\Maven安装\Maven_Repository\commons-daemon\commons-daemon\1.0.13\commons-daemon-1.0.13.jar;D:\Maven安装\Maven_Repository\javax\xml\bind\jaxb-api\2.2.2\jaxb-api-2.2.2.jar;D:\Maven安装\Maven_Repository\javax\xml\stream\stax-api\1.0-2\stax-api-1.0-2.jar;D:\Maven安装\Maven_Repository\javax\activation\activation\1.1\activation-1.1.jar;D:\Maven安装\Maven_Repository\io\netty\netty-all\4.0.27.Final\netty-all-4.0.27.Final.jar;D:\Maven安装\Maven_Repository\com\data-artisans\flakka-actor_2.11\2.3-custom\flakka-actor_2.11-2.3-custom.jar;D:\Maven安装\Maven_Repository\com\typesafe\config\1.2.1\config-1.2.1.jar;D:\Maven安装\Maven_Repository\com\data-artisans\flakka-remote_2.11\2.3-custom\flakka-remote_2.11-2.3-custom.jar;D:\Maven安装\Maven_Repository\io\netty\netty\3.8.0.Final\netty-3.8.0.Final.jar;D:\Maven安装\Maven_Repository\org\uncommons\maths\uncommons-maths\1.2.2a\uncommons-maths-1.2.2a.jar;D:\Maven安装\Maven_Repository\com\data-artisans\flakka-slf4j_2.11\2.3-custom\flakka-slf4j_2.11-2.3-custom.jar;D:\Maven安装\Maven_Repository\org\clapper\grizzled-slf4j_2.11\1.0.2\grizzled-slf4j_2.11-1.0.2.jar;D:\Maven安装\Maven_Repository\com\github\scopt\scopt_2.11\3.2.0\scopt_2.11-3.2.0.jar;D:\Maven安装\Maven_Repository\com\fasterxml\jackson\core\jackson-core\2.7.4\jackson-core-2.7.4.jar;D:\Maven安装\Maven_Repository\com\fasterxml\jackson\core\jackson-databind\2.7.4\jackson-databind-2.7.4.jar;D:\Maven安装\Maven_Repository\com\fasterxml\jackson\core\jackson-annotations\2.7.0\jackson-annotations-2.7.0.jar;D:\Maven安装\Maven_Repository\org\apache\zookeeper\zookeeper\3.4.6\zookeeper-3.4.6.jar;D:\Maven安装\Maven_Repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;D:\Maven安装\Maven_Repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;D:\Maven安装\Maven_Repository\jline\jline\0.9.94\jline-0.9.94.jar;D:\Maven安装\Maven_Repository\junit\junit\3.8.1\junit-3.8.1.jar;D:\Maven安装\Maven_Repository\com\twitter\chill_2.11\0.7.4\chill_2.11-0.7.4.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-clients_2.11\1.2.0\flink-clients_2.11-1.2.0.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-optimizer_2.11\1.2.0\flink-optimizer_2.11-1.2.0.jar;D:\Maven安装\Maven_Repository\org\apache\sling\org.apache.sling.commons.json\2.0.6\org.apache.sling.commons.json-2.0.6.jar;D:\Maven安装\Maven_Repository\org\apache\flink\force-shading\1.2.0\force-shading-1.2.0.jar;D:\Maven安装\Maven_Repository\redis\clients\jedis\2.8.0\jedis-2.8.0.jar;D:\Maven安装\Maven_Repository\org\apache\commons\commons-pool2\2.3\commons-pool2-2.3.jar;D:\Maven安装\Maven_Repository\org\scala-lang\scala-library\2.12.17\scala-library-2.12.17.jar;D:\Maven安装\Maven_Repository\com\mysql\mysql-connector-j\8.0.33\mysql-connector-j-8.0.33.jar;D:\Maven安装\Maven_Repository\com\google\protobuf\protobuf-java\3.21.9\protobuf-java-3.21.9.jar;D:\Maven安装\Maven_Repository\org\apache\flink\flink-json\1.14.0\flink-json-1.14.0.jar;D:\Maven安装\Maven_Repository\org\slf4j\slf4j-simple\1.7.36\slf4j-simple-1.7.36.jar" FlinkWriteToMySQL SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/D:/Maven%e5%ae%89%e8%a3%85%e5%8c%85/Maven_Repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/D:/Maven%e5%ae%89%e8%a3%85%e5%8c%85/Maven_Repository/org/slf4j/slf4j-simple/1.7.36/slf4j-simple-1.7.36.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] log4j:WARN No appenders could be found for logger (org.apache.flink.api.java.ClosureCleaner). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. Exception in thread "main" org.apache.flink.api.common.InvalidProgramException: The implementation of the RichOutputFormat is not serializable. The object probably contains or references non serializable fields. at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:164) at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:132) at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:69) at org.apache.flink.streaming.api.environment.StreamExecutionEnvironment.clean(StreamExecutionEnvironment.java:2139) at org.apache.flink.streaming.api.datastream.DataStream.clean(DataStream.java:203) at org.apache.flink.streaming.api.datastream.DataStream.addSink(DataStream.java:1243) at org.apache.flink.streaming.api.scala.DataStream.addSink(DataStream.scala:1133) at FlinkWriteToMySQL$.main(FlinkWriteToMySQL.scala:38) at FlinkWriteToMySQL.main(FlinkWriteToMySQL.scala) Caused by: java.io.NotSerializableException: Non-serializable lambda at FlinkWriteToMySQL$$$Lambda$92/715378067.writeObject(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1140) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.apache.flink.util.InstantiationUtil.serializeObject(InstantiationUtil.java:632) at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:143) ... 8 more 进程已结束,退出代码为 1
最新发布
09-23
<think> 我们遇到了一个异常:`org.apache.flink.api.common.InvalidProgramException: The implementation of the RichOutputFormat is not serializable. The object probably contains or references non serializable fields.` 这个异常通常是由于在Flink算子中使用了非可序列化的对象。在我们的代码中,我们使用了`JdbcSink.sink`,它可能含了一些非可序列化的部分(比如`JdbcConnectionOptions`),而Flink需要将整个算子序列化以分发到各个TaskManager上执行。 具体来看,我们的代码中,`JdbcSink.sink`方法返回的sink function可能含了一个`RichOutputFormat`(或者类似的内部类),而我们在`addSink`方法中直接使用了这个sink function。但是,在构建这个sink function时,我们传入了一个lambda表达式和一个`JdbcConnectionOptions`对象。如果这个lambda表达式捕获了任何非可序列化的对象,或者`JdbcConnectionOptions`本身不可序列化,就会导致问题。 然而,根据Flink的文档,`JdbcConnectionOptions`是可序列化的,所以问题可能出在lambda表达式上。在Scala中,lambda表达式有时会捕获外部的非可序列化对象,但在这个例子中,我们的lambda表达式只引用了`tuple`,它是可序列化的。 但是,仔细看异常堆栈,它提到“Non-serializable lambda”,所以可能是Flink在序列化整个sink function时,lambda表达式无法被正确序列化。 解决方案: 1. 我们可以尝试将这个lambda表达式提取出来,变成一个可序列化的类(比如一个实现了`Serializable`接口的类)。 2. 另一种方法是使用Flink的`RichSinkFunction`来重写这个sink。 这里我们选择第二种方法,因为`JdbcSink`内部已经处理了连接,我们也可以选择使用`RichSinkFunction`来手动管理连接。但是,Flink提供了`JdbcSink`作为工具方法,我们更希望直接使用它。因此,我们尝试将构建sink的部分装在一个可序列化的类中。 但是,我们也可以尝试另一种方法:确保lambda表达式不捕获任何外部不可序列化的对象。在我们的代码中,lambda表达式只使用了传入的参数(tuple)和已经定义好的常量(如连接选项),连接选项在构建时已经传入,并且它应该是可序列化的。 为什么还会报错呢?可能是因为在构建过程中,这个lambda表达式被转换成了一个内部类,而内部类隐式捕获了外部类的引用(即`FlinkWriteToMySQL$`对象),而外部类是不可序列化的(因为Scala对象默认是可序列化的吗?实际上,Scala的object是单例,通常不建议序列化整个object)。所以,我们需要避免lambda捕获外部类的引用。 我们可以通过将连接选项定义为本地变量,并且确保lambda表达式不引用任何外部类的成员(即不引用`this`)来解决。但是我们的代码中,lambda表达式并没有引用外部类的成员啊?实际上,在Scala中,如果我们使用的是在方法内部定义的局部变量,那么lambda表达式就不会捕获外部类。 我们目前的代码中,连接选项的构建是在`addSink`方法内部完成的,所以lambda表达式只捕获了方法内部的变量(即连接选项和SQL字符串),这些变量在构建时已经创建,并且连接选项是可序列化的。 那么问题可能出在Scala的lambda表达式的序列化机制上。我们可以尝试将lambda表达式替换为一个显式的函数类,并确保这个类是可序列化的。 根据Flink官方文档,建议对于这种问题,可以使用显式的类来代替lambda表达式。 我们修改如下: 将: ```scala (ps: PreparedStatement, tuple: (Int, String)) => { ps.setInt(1, tuple._1) ps.setString(2, tuple._2) } ``` 替换为一个实现了`JdbcStatementBuilder`并且可序列化的类。 修改后代码(主要修改部分): ```scala // 定义一个可序列化的类 class StudentJdbcStatementBuilder extends JdbcStatementBuilder[(Int, String)] with Serializable { override def accept(ps: PreparedStatement, t: (Int, String)): Unit = { ps.setInt(1, t._1) ps.setString(2, t._2) } } // 然后在sink中使用这个类的实例 tupleStream.addSink( JdbcSink.sink[(Int, String)]( "INSERT INTO student (Id, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name)", new StudentJdbcStatementBuilder, new JdbcConnectionOptions.JdbcConnectionOptionsBuilder() .withUrl("jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC") .withDriverName("com.mysql.cj.jdbc.Driver") .withUsername("root") .withPassword("12345678") .withConnectionCheckTimeoutSeconds(5) .build ) ) ``` 这样,我们避免了使用lambda表达式,而是使用了一个显式的可序列化的类。 另外,我们还需要注意,整个`FlinkWriteToMySQL$`对象(Scala的object)在序列化时会被捕获吗?在`addSink`方法中,我们使用的是本地变量,所以不会捕获外部对象。但是,如果我们的`StudentJdbcStatementBuilder`是一个内部类,那么它就会捕获外部类的引用(即`FlinkWriteToMySQL$`)。因此,为了避免这个问题,我们应该将这个类定义在方法内部(局部内部类)或者定义为顶级类。但是Scala中,我们可以在方法内部定义内部类吗?可以,但是这样这个内部类就会捕获方法所在对象的引用。所以我们最好将其定义在对象内部,并标记为`static`(在Scala中,内部类默认是依赖外部类实例的,除非我们将其定义为`class`在另一个对象中或者使用`@SerialVersionUID`并确保不引用外部类)。 然而,Scala中没有静态内部类,我们可以将`StudentJdbcStatementBuilder`定义在`FlinkWriteToMySQL`对象内部,但是不捕获外部成员。只要它不引用外部类的任何成员,那么即使捕获了外部类的引用,外部类(object)也是可序列化的(因为Scala对象在序列化时会被当作单例处理,但反序列化时可能会有问题)。所以为了安全起见,我们可以将这个类定义在方法内部,这样它只会捕获方法内的局部变量(如果方法内有局部变量被使用,则同样会有问题)。或者,我们将其定义在伴生对象的外部,作为一个独立的类。 由于我们只是一个小例子,为了方便,我们可以直接定义在对象内部,并确保它不引用外部类的成员(即不使用`FlinkWriteToMySQL`的任何成员变量或方法)。 修改后的完整代码: ```scala import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, createTypeInformation} import org.apache.flink.connector.jdbc.{JdbcSink, JdbcConnectionOptions, JdbcStatementBuilder} import java.sql.PreparedStatement object FlinkWriteToMySQL { // 定义在对象内部的内部类 class StudentJdbcStatementBuilder extends JdbcStatementBuilder[(Int, String)] with Serializable { override def accept(ps: PreparedStatement, t: (Int, String)): Unit = { ps.setInt(1, t._1) ps.setString(2, t._2) } } def main(args: Array[String]): Unit = { val namePrefix = "luyifan" // 修改为你的名字拼音 val env = StreamExecutionEnvironment.getExecutionEnvironment val studentData = Seq( s"100,${namePrefix}100", s"101,${namePrefix}101", s"102,${namePrefix}102_Math", s"103,${namePrefix}103_CS", s"104,${namePrefix}104_Physics" ) val dataStream = env.fromCollection(studentData) val tupleStream = dataStream.map { line => val parts = line.split(",", 2) (parts(0).trim.toInt, parts(1).trim) } tupleStream.addSink( JdbcSink.sink( "INSERT INTO student (Id, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name)", new StudentJdbcStatementBuilder, // 使用内部类的实例 new JdbcConnectionOptions.JdbcConnectionOptionsBuilder() .withUrl("jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC") .withDriverName("com.mysql.cj.jdbc.Driver") .withUsername("root") .withPassword("12345678") .withConnectionCheckTimeoutSeconds(5) .build ) ) println(s"开始写入 ${studentData.size} 条学生数据到MySQL...") env.execute("Flink Write to MySQL - luyifan") } } ``` 注意:这里我们将`StudentJdbcStatementBuilder`定义在了`FlinkWriteToMySQL`对象内部,并且它没有引用外部对象的任何成员(即没有使用`FlinkWriteToMySQL`的字段或方法),所以即使它持有对外部对象的引用,外部对象(单例)在序列化时也是安全的(因为单例对象在反序列化时并不会真的反序列化,而是返回已有的单例)。但是,为了确保万无一失,我们也可以将这个类定义在方法内部(即`main`方法内部),这样它就不会捕获外部对象。修改如下: ```scala def main(args: Array[String]): Unit = { // ... 其他代码 ... // 在main方法内部定义内部类 class StudentJdbcStatementBuilder extends JdbcStatementBuilder[(Int, String)] with Serializable { override def accept(ps: PreparedStatement, t: (Int, String)): Unit = { ps.setInt(1, t._1) ps.setString(2, t._2) } } tupleStream.addSink( JdbcSink.sink( "INSERT INTO student (Id, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name)", new StudentJdbcStatementBuilder, // 使用内部类的实例 // ... 连接选项 ... ) ) } ``` 但是,在方法内部定义类,这个类会捕获方法所在对象的引用(即`FlinkWriteToMySQL$`),所以还是会有同样的问题。因此,我们更推荐将这个类定义在对象外部(作为顶级类),或者使用匿名内部类并确保不引用外部成员(实际上,匿名内部类也会捕获外部类引用)。 所以,最安全的方式是将其定义为一个顶级类。但是为了代码简洁,我们可以将其定义在`FlinkWriteToMySQL`对象内部,并加上`@SerialVersionUID`注解,并确保它不引用外部类的成员。因为实际上它没有引用,所以应该是安全的。 另外,注意在Flink中,通常要求所有在算子中使用的函数都是可序列化的。我们这里使用内部类,只要确保内部类是静态的(在Scala中,没有静态内部类,但是嵌套类不持有外部类的引用,除非使用`outer`)。实际上,在Scala中,定义在对象内部的类默认就是静态的(类似于Java的静态内部类),所以不会持有外部类实例的引用(因为对象本身就是单例,没有实例)。所以,这里定义在对象内部是安全的。 因此,我们采用第一种修改方式:将`StudentJdbcStatementBuilder`定义在`FlinkWriteToMySQL`对象内部,作为一个嵌套类。 运行修改后的代码,应该可以避免序列化异常。 另外,我们还看到程序输出了关于SLF4J和log4j的警告,这可能会导致日志无法输出。我们可以添加log4j的配置文件来解决。在资源目录下添加`log4j.properties`文件,内容如下: ``` log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %-60c %x - %m%n ``` 这样,日志就可以正常输出了。 综上所述,修改后的完整代码如下: </think> ### 解决 Flink 序列化异常问题 #### 问题分析: 异常信息表明 `RichOutputFormat` 实现不可序列化,具体原因是 lambda 表达式 `FlinkWriteToMySQL$$$Lambda$92` 不可序列化。在 Flink 中,所有需要在任务管理器之间传输的函数括 Sink)必须实现 `Serializable` 接口。 #### 解决方案: 需要将 lambda 表达式替换为显式实现 `JdbcStatementBuilder` 接口的序列化类: ```scala import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, createTypeInformation} import org.apache.flink.connector.jdbc.{JdbcSink, JdbcConnectionOptions, JdbcStatementBuilder} import java.sql.PreparedStatement import java.io.Serializable // 显式实现可序列化的语句构建器 class SerializableStatementBuilder extends JdbcStatementBuilder[(Int, String)] with Serializable { override def accept(ps: PreparedStatement, tuple: (Int, String)): Unit = { ps.setInt(1, tuple._1) ps.setString(2, tuple._2) } } object FlinkWriteToMySQL { def main(args: Array[String]): Unit = { val namePrefix = "luyifan" val env = StreamExecutionEnvironment.getExecutionEnvironment // 添加学生数据 val studentData = Seq( s"100,${namePrefix}100", s"101,${namePrefix}101", s"102,${namePrefix}102_Math", s"103,${namePrefix}103_CS", s"104,${namePrefix}104_Physics" ) val dataStream = env.fromCollection(studentData) val tupleStream = dataStream.map { line => val parts = line.split(",", 2) (parts(0).trim.toInt, parts(1).trim) } // 使用可序列化的语句构建器 val statementBuilder = new SerializableStatementBuilder tupleStream.addSink( JdbcSink.sink[(Int, String)]( "INSERT INTO student (Id, name) VALUES (?, ?) " + "ON DUPLICATE KEY UPDATE name = VALUES(name)", statementBuilder, // 使用显式的可序列化类 new JdbcConnectionOptions.JdbcConnectionOptionsBuilder() .withUrl("jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC") .withDriverName("com.mysql.cj.jdbc.Driver") .withUsername("root") .withPassword("12345678") .withConnectionCheckTimeoutSeconds(5) .build ) ) println(s"开始写入 ${studentData.size} 条学生数据到MySQL...") env.execute("Flink Write to MySQL - luyifan") } } ``` ### 关键修改说明: 1. **可序列化的语句构建器**: ```scala class SerializableStatementBuilder extends JdbcStatementBuilder[(Int, String)] with Serializable { override def accept(ps: PreparedStatement, tuple: (Int, String)): Unit = { ps.setInt(1, tuple._1) ps.setString(2, tuple._2) } } ``` - 显式实现 `Serializable` 接口 - 替代不可序列化的 lambda 表达式 - 保持与原始逻辑相同的功能 2. **JDBC Sink 使用方式**: ```scala val statementBuilder = new SerializableStatementBuilder tupleStream.addSink(JdbcSink.sink(..., statementBuilder, ...)) ``` - 创建可序列化构建器的实例 - 避免使用匿名内部类或 lambda ### 额外优化建议: #### 1. 解决 SLF4J 绑定冲突: 在 `src/main/resources` 添加 `log4j.properties` 文件: ```properties log4j.rootLogger=ERROR, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n # 禁用无关日志 log4j.logger.org.apache.flink=ERROR log4j.logger.org.apache.zookeeper=ERROR log4j.logger.org.apache.hadoop=ERROR log4j.logger.org.apache.kafka=ERROR ``` #### 2. Maven 依赖管理: 确保 `pom.xml` 中只有一个 SLF4J 绑定: ```xml <dependencies> <!-- 移除冲突的绑定 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.36</version> <scope>provided</scope> <!-- 或完全移除 --> </dependency> <!-- 保留需要的绑定 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.36</version> </dependency> </dependencies> ``` ### 原理解释: 1. **Flink 序列化要求**: - 分布式执行需要序列化任务图 - Lambda 表达式使用合成类(synthetic classes)可能导致序列化问题 - 显式实现 `Serializable` 保证稳定序列化 2. **日志冲突根源**: ```plaintext SLF4J: Found binding in [slf4j-log4j12.jar] SLF4J: Found binding in [slf4j-simple.jar] ``` - 多个 SLF4J 实现在类路径中冲突 - 需要明确指定单一日志实现 3. **Flink 最佳实践**: - 避免在算子中使用匿名内部类 -函数显式声明序列化版本 UID - 保持函数无状态(减少序列化负担)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值