Flink的数据类型

扫码关注系列文章

 Apache Flink 以其独特的方式来处理数据类型以及序列化,这种方式包括它自身的类型描述符、泛型类型提取以及类型序列化框架。本文档描述了它们背后的概念和基本原理。

支持的数据类型

    Flink 对可以在 DataSet 或 DataStream 中的元素类型进行了一些限制。这样做的原因是系统会分析类型以确定有效的执行策略。

  1.  Java Tuple 和 Scala Case类;

  2.  Java POJO;

  3.  基本类型;

  4. 通用类;

  5. 值;

  6. Hadoop Writables;

  7. 特殊类型

Flink之Tuple类型

Tuple类型  Tuple 是flink 一个很特殊的类型 (元组类型),是一个抽象类,共26个Tuple子类继承Tuple 他们是 Tuple0一直到Tuple25

package org.apache.flink.api.java.tuple;import java.io.Serializable;import org.apache.flink.annotation.Public;import org.apache.flink.types.NullFieldException;@Publicpublic abstract class Tuple implements Serializable {    private static final long serialVersionUID = 1L;    public static final int MAX_ARITY = 25;    private static final Class<?>[] CLASSES = new Class[]{Tuple0.class, Tuple1.class, Tuple2.class, Tuple3.class, Tuple4.class, Tuple5.class, Tuple6.class, Tuple7.class, Tuple8.class, Tuple9.class, Tuple10.class, Tuple11.class, Tuple12.class, Tuple13.class, Tuple14.class, Tuple15.class, Tuple16.class, Tuple17.class, Tuple18.class, Tuple19.class, Tuple20.class, Tuple21.class, Tuple22.class, Tuple23.class, Tuple24.class, Tuple25.class};    public Tuple() {    }    public abstract <T> T getField(int var1);    public <T> T getFieldNotNull(int pos) {        T field = this.getField(pos);        if (field != null) {            return field;        } else {            throw new NullFieldException(pos);        }    }    public abstract <T> void setField(T var1, int var2);    public abstract int getArity();    public abstract <T extends Tuple> T copy();    public static Class<? extends Tuple> getTupleClass(int arity) {        if (arity >= 0 && arity <= 25) {            return CLASSES[arity];        } else {            throw new IllegalArgumentException("The tuple arity must be in [0, 25].");        }    }    public static Tuple newInstance(int arity) {        switch(arity) {        case 0:            return Tuple0.INSTANCE;        case 1:            return new Tuple1();        case 2:            return new Tuple2();        case 3:            return new Tuple3();        case 4:            return new Tuple4();        case 5:            return new Tuple5();        case 6:            return new Tuple6();        case 7:            return new Tuple7();        case 8:            return new Tuple8();        case 9:            return new Tuple9();        case 10:            return new Tuple10();        case 11:            return new Tuple11();        case 12:            return new Tuple12();        case 13:            return new Tuple13();        case 14:            return new Tuple14();        case 15:            return new Tuple15();        case 16:            return new Tuple16();        case 17:            return new Tuple17();        case 18:            return new Tuple18();        case 19:            return new Tuple19();        case 20:            return new Tuple20();        case 21:            return new Tuple21();        case 22:            return new Tuple22();        case 23:            return new Tuple23();        case 24:            return new Tuple24();        case 25:            return new Tuple25();        default:            throw new IllegalArgumentException("The tuple arity must be in [0, 25].");        }    }}

查看源码我们看到Tuple0一直到Tuple25

我们看flink为我们为我们构造好了0-25个字段的模板类

package org.apache.flink.api.java.tuple;import java.io.ObjectStreamException;import org.apache.flink.annotation.Public;@Publicpublic class Tuple0 extends Tuple {    private static final long serialVersionUID = 1L;    public static final Tuple0 INSTANCE = new Tuple0();    public Tuple0() {    }    public int getArity() {        return 0;    }    public <T> T getField(int pos) {        throw new IndexOutOfBoundsException(String.valueOf(pos));    }    public <T> void setField(T value, int pos) {        throw new IndexOutOfBoundsException(String.valueOf(pos));    }    public Tuple0 copy() {        return new Tuple0();    }    public String toString() {        return "()";    }    public boolean equals(Object o) {        return this == o || o instanceof Tuple0;    }    public int hashCode() {        return 0;    }    private Object readResolve() throws ObjectStreamException {        return INSTANCE;    }}

Tuple的使用

方式一:初始化元组

    可使用静态方法 newInstance进行元组构造 指定元组空间大小;

ex: 1 则元组只有一个空间,则实际使用的Tuple1 字段只有f0

ex: 12 则元组只有两个空间,则实际使用的Tuple2 字段只有f0,f1

指定  Tuple元组空间大小 (可理解为字段个数)

Tuple tuple = Tuple.newInstance(1);

方式一:构造元组

    使用Tuple.newInstance(xx),指定元组空间大小的话,这样存取虽然能够实现,但会存在存储索引位置使用不正确的情况,可能由于失误操作编写出索引越界异常,而且使用不太方便,使用Tuplex.of(数据)方法构造Tuple元组

Tuple3<String, String, String> tuple3 = Tuple3.of("test0", "test1", "test2");System.out.println(tuple3.f0); // test0System.out.println(tuple3.f1); // test1System.out.println(tuple3.f2); // test2

Flink之POJO类型

Java和Scala的类在满足下列条件时,将会被Flink视作特殊的POJO数据类型专门进行处理:

1.是公共类;

2.无参构造是公共的;

3.所有的属性都是可获得的(声明为公共的,或提供get,set方法);

4.字段的类型必须是Flink支持的。Flink会用Avro来序列化任意的对象。

Flink会分析POJO类型的结构获知POJO的字段。POJO类型要比一般类型好用。此外,Flink访问POJO要比一般类型更高效。

public class WordWithCount {    public String word;    public int count;    public WordWithCount() {}    public WordWithCount(String word, int count) { this.word = word; this.count = count; }}    DataStream<WordWithCount> wordCounts = env.fromElements(    new WordWithCount("hello", 1),    new WordWithCount("world", 2));    wordCounts.keyBy("word");

Flink之基本类型

Flink支持Java和Scala所有的基本数据类型,比如 Integer,String,和Double。

Flink之通用类型

    Flink支持大多数的Java,Scala类(API和自定义)。包含不能序列化字段的类在增加一些限制后也可支持。遵循Java Bean规范的类一般都可以使用。

    所有不能视为POJO的类Flink都会当做一般类处理。这些数据类型被视作黑箱,其内容是不可见的。通用类使用Kryo进行序列/反序列化。

Flink之值类型Values

     通过实现org.apache.flinktypes.Value接口的read和write方法提供自定义代码来进行序列化/反序列化,而不是使用通用的序列化框架。

Flink预定义的值类型与原生数据类型是一一对应的(例如:ByteValue, ShortValue, IntValue, LongValue, FloatValue, DoubleValue, StringValue, CharValue, BooleanValue)。这些值类型作为原生数据类型的可变变体,他们的值是可以改变的,允许程序重用对象从而缓解GC的压力。

Flink之Hadoop的Writable类

   它实现org.apache.hadoop.Writable接口的类型,该类型的序列化逻辑在write()和readFields()方法中实现。

Flink之特殊类型

Flink比较特殊的类型有以下两种:

1.Scala的 Either、Option和Try。

2.Java ApI有自己的Either实现。

Java Api 与 Scala 的 类似Either,它表示两种可能类型的值,LeftRightEither对于错误处理或需要输出两种不同类型的记录的运算符很有用。

 

类型擦除和类型推理

    Java编译器在编译之后会丢弃很多泛型类型信息。这在Java中称为类型擦除。这意味着在运行时,对象的实例不再知道其泛型类型。

例如,在JVM中,DataStream<String>和DataStream<Long>的实例看起来是相同的。

List<String> l1 = new ArrayList<String>();List<Integer> l2 = new ArrayList<Integer>();System.out.println(l1.getClass() == l2.getClass());

    泛型:一种较为准确的说法就是为了参数化类型,或者说可以将类型当作参数传递给一个类或者是方法。Flink 的Java API会试图去重建(可以做类型推理)这些被丢弃的类型信息,并将它们明确地存储在数据集以及操作中。你可以通过DataStream.getType()方法来获取类型,这个方法将返回一个TypeInformation的实例,这个实例是Flink内部表示类型的方式。

​如果觉得文章能帮到您,欢迎关注微信公众号:“蓝天Java大数据” ,共同进步!

<think>嗯,用户想了解ApacheFlink支持的数据类型。根据引用内容,Flink数据类型分为基础类型、复合类型和自定义类型等类别。用户可能正在学习Flink或准备开发Flink应用,需要系统了解类型体系。 从引用[1]看,Flink的基础数据类型包括Java和Scala的原始类型,比如Integer、String这些。引用[2]提到POJO类型的使用限制和Tuple的替代方案,说明复合类型需要特别注意。引用[3][4]虽然侧重流处理和时间概念,但间接印证Flink类型系统需适应流批一体场景。用户没提具体使用场景,但询问"哪些"表明需要完整分类。我应当:1.分层列举:基础/复合/特殊类型2.强调POJO规则(引用[2]的关键点) 3.补充自定义类型接口(引用[1]提及但未展开) 4.用$$包裹独立公式示例(如Row类型表达式)5.按系统指令生成相关问题需注意引用[1]明确提到"基础类型、复合类型和自定义类型"的三分法,这应是回答主框架。对于POJO的特殊要求,引用[2]的示例代码虽未展示,但指出Tuple可替代不满足条件的POJO,这点必须强调。最后生成的问题要覆盖类型选择策略(如引用[2]的实践问题)、序列化影响(引用[1]隐含点)和特殊场景(如引用[4]的时间类型关联)</think>Apache Flink 支持丰富的数据类型,以满足流/批处理的需求,主要分为以下几类: ### 一、基础数据类型 1. **原始类型** 支持 Java/Scala 的所有基本类型: - `Integer`、`int`(对应 `Types.INT()`) - `Long`、`long`(`Types.LONG()`) - `Double`、`double`(`Types.DOUBLE()`) - `Float`、`float`(`Types.FLOAT()`) - `Boolean`、`boolean`(`Types.BOOLEAN()`) - `String`(`Types.STRING()`) - `Byte`、`byte[]`(`Types.BYTE()`) 2. **通用类型** - `BigInteger`、`BigDecimal` - `Date`、`java.sql.Timestamp` - `java.time` 包中的时间类型(如 `Instant`、`LocalDateTime`) --- ### 二、复合数据类型 1. **元组(Tuple)** 固定长度的强类型容器,如 `Tuple2<String, Integer>`: ```java DataStream<Tuple2<String, Integer>> stream = env.fromElements( Tuple2.of("A", 1), Tuple2.of("B", 2) ); ``` 2. **POJO 类型** **规则**: - 类必须是 `public` - 字段需 `public` 或提供 `getter/setter` - 必须有空构造器 - 字段类型需 Flink 支持 **示例**: ```java public class User { public String name; public int age; public User() {} // 必须有无参构造器 } DataStream<User> users = env.fromElements(new User("Alice", 30)); ``` 3. **行类型(Row)** 灵活但弱类型的结构,常用于 Table API: ```java Row row = Row.of("Alice", 25); DataStream<Row> rowStream = env.fromElements(row); ``` 4. **集合类型** - `List<T>`、`Map<K,V>`、`Set<T>` - 元素类型需 Flink 支持 --- ### 三、特殊类型 1. **值类型(Value)** 实现 `org.apache.flink.types.Value` 接口,支持自定义序列化(如 `IntValue`)。 2. **枚举类型(Enum)** 支持 Java/Scala 的枚举类。 3. **数组类型** 基础类型数组(如 `int[]`)或对象数组(如 `String[]`)。 --- ### 四、自定义类型 通过 `TypeInformation` 扩展: 1. 实现 `TypeInformation` 接口定义序列化逻辑 2. 使用 `createTypeInformation` 注册 ```java env.registerType(User.class); // 显式注册 POJO ``` --- ### 关键约束 - **类型推断**:Flink 会尝试自动推断类型信息,复杂结构需显式声明(如 `returns()` 方法)[^1]。 - **序列化要求**:所有类型必须支持高效序列化(POJO 需满足字段可访问)[^2]。 - **避免泛型擦除**:需通过 `TypeHint` 保留泛型信息: ```java DataStream<List<String>> stream = env.fromElements( Arrays.asList("a", "b"), Types.LIST(Types.STRING) // 显式指定 ); ``` > 示例:POJO 字段访问规则 > 若字段 `age` 为 `private`,需提供 `public int getAge()` 和 `public void setAge(int age)`。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值