详解 Flink Table API 和 Flink SQL 之函数

一、系统内置函数

1. 比较函数

API函数表达式示例
Table API===,>,<,!=,>=,<=id===1001,age>18
SQL=,>,<,!=,>=,<=id=‘1001’,age>18

2. 逻辑函数

API函数表达式示例
Table API&&,||,!,.isFalse1>1 && 2>1,true.isFalse
SQLand,or,is false,not1>1 and 2>1,true is false

3. 算术函数

API函数表达式示例
Table API+,-,*,/,n1.power(n2)1 + 1,2.power(2)
SQL+,-,*,/,power(n1,n2)1 + 1,power(2,2)

4. 字符串函数

API函数表达式示例
Table APIstring1 + string2,.upperCase(),.lowerCase(),.charLength()‘a’ + ‘b’,
‘hello’.upperCase()
SQLstring1 || string2,upper(),lower(),char_length()‘a’ || ‘b’,upper(‘hello’)

5. 时间函数

API函数表达式示例
Table API.toDate,.toTimestamp,currentTime(),n.days,n.minutes‘20230107’.toDate,
2.days,10.minutes
SQLDate string,Timestamp string,current_time,interval string rangeDate ‘20230107’,interval ‘2’ hour/second/minute/day

6. 聚合函数

API函数表达式示例
Table API.count,.sum,.sum0id.count,age.sum,sum0 表示求和的所有值都为 null 则返回 0
SQLcount(),sum(),rank(),row_number()count(*),sum(age)

二、用户自定义函数(UDF)

UDF 显著地扩展了查询的表达能力,可以解决一些系统内置函数无法解决的需求。使用步骤为:自定义 UDF 函数类继承 UserDefinedFunction 抽象类;创建 UDF 实例并在环境中调用 registerFunction() 方法注册;在 Table API 或 SQL 中使用

1. 标量函数

Scalar Function,可以将 0、1 或多个标量值,映射到一个新的标量值,一进一出

/**
	用户自定义标量函数步骤:
	1.自定义函数类继承 ScalarFunction 抽象类,并在类中定义一个 public 的名为 eval 的方法
	2.创建自定义函数实例,使用 table 环境对象调用 registerFunction() 方法注册函数
	3.在 Table API 和 SQL 中使用
*/
public class TestScalarFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
        
        DataStream<String> inputStream = env.readTextFile("./sensor.txt");
        
        DataStream<SensorReading> dataStream = InputStream.map(line -> {
            String[] fields = line.split(",");
            return new SensorReading(fields[0], new Long(fields[1]), new Double(fields[2]));
        });
        
        Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp as ts, temperature as temp");
        
        tableEnv.createTemporaryView("sensor", dataTable);
        
        //使用自定义的标量函数 hashCode,查询每条数据 id 的hashCode 值
        //2.创建自定义标量函数实例
        HashCode hashCode = new HashCode(0.8);
        
        //3.在环境中注册函数
        tableEnv.registerFunction("hashCode", hashCode);
        
        //4.使用
        //4.1 Table API
        Table resultTable = sensorTable.select("id, ts, hashCode(id)");
        
        //4.2 SQL
        Table resultSqlTable = tableEnv.sqlQuery("select id, ts, hashCode(id) from sensor");
        
        tableEnv.toAppendStream(resultTable, Row.class).print("result");
        tableEnv.toAppendStream(resultSqlTable, Row.class).print("sql");
        
        env.execute();
    }
    
    //1.自定义 HashCode 函数,继承 ScalarFunction 类,并定义 eval 方法
    public static class HashCode extends ScalarFunction {
        private int factor;
        
        public HashCode(int factor) {
            this.factor = factor;
        }
        
        //该方法必须为 public 且名称必须为 eval,返回值和参数可以自定义
        public int eval(String str) {
            return str.hashCode() * factor;
        }
        
    }
}

2. 表函数

Table Function,可以将0、1或多个标量值作为输入参数,可以返回任意数量的行作为输出。一进多出

/**
	用户自定义表函数步骤:
	1.自定义函数类继承 TableFunction 抽象类,定义输出泛型,并在类中定义一个 public 的名为 eval,返回值为 void 的方法
	2.创建自定义函数实例,使用 table 环境对象调用 registerFunction() 方法注册函数
	3.在 Table API 和 SQL 中使用
*/
public class TestTableFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
        
        DataStream<String> inputStream = env.readTextFile("./sensor.txt");
        
        DataStream<SensorReading> dataStream = InputStream.map(line -> {
            String[] fields = line.split(",");
            return new SensorReading(fields[0], new Long(fields[1]), new Double(fields[2]));
        });
        
        Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp as ts, temperature as temp");
        
        tableEnv.createTemporaryView("sensor", dataTable);
        
        //使用自定义的表函数 Split,将每条数据的 id 分割并按 (word, length) 输出
        //2.创建自定义表函数实例
        Split split = new Split("_");
        
        //3.在环境中注册函数
        tableEnv.registerFunction("split", split);
        
        //4.使用
        //4.1 Table API
        //一进多出函数要配合 joinLateral 使用,侧写表
        Table resultTable = sensorTable.joinLateral("split(id) as (word, length)").select("id, ts, word, length");
        
        //4.2 SQL
        //一进多出函数要进行 lateral table 的关联,类似于 lateral view
        Table resultSqlTable = tableEnv.sqlQuery("select id, ts, word, length from sensor, lateral table(split(id)) as lt(word, length)");
        
        tableEnv.toAppendStream(resultTable, Row.class).print("result");
        tableEnv.toAppendStream(resultSqlTable, Row.class).print("sql");
        
        env.execute();
    }
    
    //1.自定义表函数 Split 继承 TableFunction,定义输出类型为 Tuple2<String, Integer>
    public static class Split extends TableFunction<Tuple2<String, Integer>> {
        private String separator = ",";
        
        public Split(String separator) {
            this.separator = separator;
        }
        
        //必须定义一个 public 的返回值为 void 的 eval 方法
        public void eval(String str) {
            for(String s : str.split(separator)) {
                //使用 collect() 方法输出结果
                collect(new Tuple2<>(s, s.length()));
            }
        }
    }
}

3. 聚合函数

Aggregate Function,可以把一个表中的数据,聚合成一个标量值,多进一出

/**
	用户自定义聚合函数步骤:
	1.自定义函数类继承 AggregateFunction 抽象类,定义输出和累加器的泛型,实现 createAccumulator()、accumulate()和getValue()方法
	2.创建自定义函数实例,使用 table 环境对象调用 registerFunction() 方法注册函数
	3.在 Table API 和 SQL 中使用
*/
public class TestAggregateFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
        
        DataStream<String> inputStream = env.readTextFile("./sensor.txt");
        
        DataStream<SensorReading> dataStream = InputStream.map(line -> {
            String[] fields = line.split(",");
            return new SensorReading(fields[0], new Long(fields[1]), new Double(fields[2]));
        });
        
        Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp as ts, temperature as temp");
        
        tableEnv.createTemporaryView("sensor", dataTable);
        
        //使用自定义的聚合函数 AvgTemp,按 id 分组后求最新的平均温度值
        //2.创建自定义聚合函数实例
        AvgTemp avgTemp = new AvgTemp();
        
        //3.在环境中注册函数
        tableEnv.registerFunction("avgTemp", avgTemp);
        
        //4.使用
        //4.1 Table API
        //聚合函数必须在 groupBy 后的 aggregate 方法使用
        Table resultTable = sensorTable.groupBy("id").aggregate("avgTemp(temp) as avgtemp").select("id, avgtemp");
        
        //4.2 SQL
        Table resultSqlTable = tableEnv.sqlQuery("select id, avgTemp(temp) from sensor group by id");
        
        tableEnv.toRetractStream(resultTable, Row.class).print("result");
        tableEnv.toRetractStream(resultSqlTable, Row.class).print("sql");
        
        env.execute();
    }
    
    //1.自定义聚合函数 AvgTemp 继承 AggregateFunction 类,定义输出类型为 Double,中间累加器类型为 Tuple2<Double, Integer> 并实现方法
    public static class AvgTemp extends AggregateFunction<Double, Tuple2<Double, Integer>> {
        
        @Override
        public Double getValue(Tuple2<Double, Integer> accumulator) {
            return accumulator.f0 / accumulator.f1;
        }
        
        @Override
        public Tuple2<Double, Integer> createAccumulator() {
            return new Tuple2<>(0.0, 0);
        }
        
        //必须定义一个 accumulate 方法,参数列表必须为 (accumulator, data),返回值为 void
        public void accumulate(Tuple2<Double, Integer> accumulator, Double temp) {
            accumulator.f0 += temp;
            accumulator.f1 += 1;
        }
        
    }
}

4. 表聚合函数

Table Aggregate Function,可以把一个表中数据,聚合为具有多行和多列的结果表,多进多出

/**
	用户自定义表聚合函数步骤:
	1.自定义函数类继承 TableAggregateFunction 抽象类,定义输出和累加器的泛型,实现 createAccumulator()、accumulate()和 emitValue()方法
	2.创建自定义函数实例,使用 table 环境对象调用 registerFunction() 方法注册函数
	3.在 Table API 和 SQL 中使用
*/
public class TestAggregateFunction {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
        
        DataStream<String> inputStream = env.readTextFile("./sensor.txt");
        
        DataStream<SensorReading> dataStream = InputStream.map(line -> {
            String[] fields = line.split(",");
            return new SensorReading(fields[0], new Long(fields[1]), new Double(fields[2]));
        });
        
        Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp as ts, temperature as temp");
        
        tableEnv.createTemporaryView("sensor", dataTable);
        
        //使用自定义的表聚合函数 Top2Temp,按 id 分组后求最新的 top2 温度值
        //2.创建自定义表聚合函数实例
        Top2Temp top2Temp = new Top2Temp();
        
        //3.在环境中注册函数
        tableEnv.registerFunction("top2Temp", top2Temp);
        
        //4.使用
        //Table API
        //表聚合函数必须在 groupBy 后的 flatAggregate 方法使用
        Table resultTable = sensorTable.groupBy("id").flatAggregate("top2Temp(temp) as (temp, irank)").select("id, temp, irank");
        
        //表聚合函数目前不能在 SQL 中使用
        
        tableEnv.toRetractStream(resultTable, Row.class).print("result");
        
        env.execute();
    }
    
    //定义一个 Accumulator
    public static class Top2TempAcc {
        private Double highestTemp = Double.MIN_VALUE;
        private Double secondHighestTemp = Double.MIN_VALUE;
        
        public Double getHighestTemp() {
            return highestTemp;
        }
        
        public void setHighestTemp(Double highestTemp) {
            this.highestTemp=highestTemp;
        }
        
        public Double getSecondHighestTemp() {
            return secondHighestTemp;
        }
        
        public void setSecondHighestTemp(Double secondHighestTemp) {
            this.secondHighestTemp=secondHighestTemp;
        }
    }
    
    //1.自定义表聚合函数 Top2Temp 继承 TableAggregateFunction 类,定义输出类型为 Tuple2<Double, Integer>,中间累加器类型为自定义的 Top2TempAcc 类并实现方法
    public static class Top2Temp extends TableAggregateFunction<Tuple2<Double, Integer>, Top2TempAcc> {
        
        @Override
        public void emitValue(Top2TempAcc acc, Collector<Tuple2<Double, Integer>> out) {
            out.collect(new Tuple2<>(acc.getHighestTemp(), 1));
            out.collect(new Tuple2<>(acc.getSecondHighestTemp(), 2));
        }
        
        @Override
        public Top2TempAcc createAccumulator() {
            return new Top2TempAcc();
        }
        
        //必须定义一个 accumulate 方法,参数列表必须为 (accumulator, data),返回值为 void
        public void accumulate(Top2TempAcc acc, Double temp) {
            if(acc.getHighestTemp() < temp) {
                acc.setSecondHighestTemp(acc.getHighestTemp());
                acc.setHighestTemp(temp);
            } else if(acc.getSecondHighestTemp() < temp) {
                acc.setSecondHighestTemp(temp);
            }
        }
        
    }
}
  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Flink 1.14的Table APISQL教程可以在Flink官方文档中找到,其中包括了Table APISQL的基础概念、语法、操作符、函数等内容,还有详细的示例代码和实战案例,非常适合初学者学习和入门。另外,Flink社区也有很多优秀的博客和视频教程,可以帮助大家更深入地理解和应用Table APISQL。 ### 回答2: Flink是一个分布式计算引擎,是Apache Hadoop生态圈中用于处理流式数据的一种解决方案。Flink支持表格APISQL语言,使得用户可以更加简单地实现流处理任务。而在Flink 1.14中,TableAPISQL引擎则得到了进一步的增强。 TableAPISQL将无需掌握Java或Scala编程语言就可以操作表格数据。TableAPI API支持Java和Scala,SQL则支持标准的SQL语言。如果你熟悉SQL语言,那么你很容易上手使用TableAPISQL引擎。 Flink TableAPISQL支持各种类型的表格操作,包括选择、过滤、分组、排序、连接等。此外,它们还支持窗口和聚合操作。这使得用户在处理流式数据时可以更加简单易懂地进行复杂的操作。 在Flink 1.14中,TableAPISQL引擎还提供了一系列新功能,包括: 1. 时间特征支持——TableAPISQL中的数据时间戳可以通过时间特征进行定义和控制。通过时间特征,用户可以定义数据的时间属性,例如事件时间或处理时间。 2. 详细的窗口管理——当窗口中的数据到期时,Flink 1.14会自动清除过期数据,避免数据量过大导致性能下降。 3. 支持更多的流数据源——在Flink 1.14中,TableAPISQL引擎可以直接从Kafka、Kinesis、Hive等数据源中读取数据。这可以让用户更加方便地读取数据,而无需编写额外的代码。 TableAPISQL引擎对于Flink用户来说是非常重要的工具,无需掌握Java或Scala编程语言即可操作表格数据。并且在Flink 1.14中,这两个工具得到了进一步的增强,包括更好的窗口管理和更多的数据源支持。因此,学习TableAPISQL引擎对于想要使用Flink进行流处理的人来说是非常有益的。 ### 回答3: Flink 1.14 TableAPISQL是一个非常好用的数据处理工具,可帮助数据分析师快速进行数据查询、聚合和处理。下面详细介绍一下Flink 1.14的TableAPISQL教程。 1. 如何配置Flink 1.14的TableAPISQL环境? 在进行Flink 1.14的TableAPISQL开发之前,需要先进行环境的配置。可以在官网下载Flink的安装包,解压后找到/bin目录下的start-cluster.sh脚本进行启动。启动之后,即可通过WebUI的页面查看Flink的运行状态。 2. TableAPI的基本操作 TableAPIFlink的一个高层次数据处理API,可以通过编写代码来进行数据的处理。TableAPI的基本操作有以下几个: (1) 创建Table,可以使用StreamTableEnvironment的fromDataStream或fromTableSource方法,将DataStream或TableSource转换成Table。 (2) Table的转换,可以使用多种转换操作,包括filter、select、orderBy、groupBy、join等。 (3) 将Table转化为DataStream,可以使用StreamTableEnvironment的toDataStream方法。 3. SQL的基本操作 SQLFlink提供的一种快速数据处理方式,用户只需要编写SQL语句即可完成数据处理。SQL的基本操作有以下几个: (1) 注册Table,可以使用StreamTableEnvironment的registerTable或registerTableSource方法,将TableTableSource注册到环境中。 (2) 执行SQL,可以使用StreamTableEnvironment的executeSql方法,执行SQL语句并返回结果。 (3) 将结果转换为DataStream,可以使用StreamTableEnvironment的toDataStream方法。 4. 如何优化Flink 1.14的TableAPISQL的执行效率? 在进行TableAPISQL开发时,为了保证其执行效率,需要注意以下几点: (1) 避免使用复杂的JOIN操作,可以使用Broadcast和TableFunction等方式来避免JOIN操作。 (2) 注意Table的Schema定义,Schema的设计合理与否直接影响SQL性能。 (3) 避免使用无限制的聚合操作,可以进行分批次聚合来避免。 总的来说,Flink 1.14的TableAPISQL是非常强大的数据处理工具,能够帮助开发者快速高效的进行数据处理。上述内容是入门级别的教程,如果想要更深入的了解,可以参考官方文档进行学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值