/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.aliyun.odps.udf; import java.io.IOException; /** * {@link UDTF} 是 User Defined Table-generating Function 缩写,用来解决一次函数调用输出多行数据的场景,也是唯一能返回多个字段的自定义函数。<br /> * <p> * 用户代码需继承此类,编写 {@link #process(Object[])} 方法来完成具体的数据操作,实现一个 {@link UDTF} 的功能。<br /> * 行数据输出的过程通过调用 {@link #forward(Object...)} 实现。 * </p> * <br /> * 实例代码: * <pre> *@Resolve({ "string,string->string,bigint" }) public class UDTFExample extends UDTF { @Override public void process(Object[] args) throws UDFException { String a = (String) args[0]; long b = args[1] == null ? 0 : ((String)args[1]).length(); forward(a, b); } } * </pre> */ public abstract class UDTF implements ContextFunction { private UDTFCollector collector; /** * 不推荐使用 * 用于输入、输出类型 {@link OdpsType} 之间的转换 * * @param inputTypes * 输入的类型 * @return 转换后的输出类型 * @throws Exception * 任何异常均会抛出 * * 建议使用 {@link Resolve} 替代 */ @Deprecated public OdpsType[] initialize(OdpsType[] inputTypes) throws Exception { OdpsType[] ret = {OdpsType.IGNORE}; return ret; } /** * 用于输入、输出类型 {@link OdpsType} 之间的转换,默认调用 {@link #initialize(OdpsType[])} * 不存在转换问题通常不需要关心。 * * @param inputTypes * 输入的类型 * @return 转换后的输出类型 * @throws UDFException * 通用{@link UDF}异常 */ public OdpsType[] resolve(OdpsType[] inputTypes) throws UDFException { try { return initialize(inputTypes); } catch (Exception e) { throw new UDFException(e); } } /** * 在{@link UDTF}运行期,在每个Worker内{@link #setup(ExecutionContext)}会被先调用一次。 * <p> * 默认实现为空实现,用户代码可以通过覆盖此方法,在{@link #setup(ExecutionContext)}中完成初始化的工作。 * </p> * * @param ctx * {@link UDF}所在运行时上下文信息,包括{@link UDF}所在的StageID、WorkerID等信息 * @throws UDFException * 通用{@link UDF}异常 */ public void setup(ExecutionContext ctx) throws UDFException { } /** * 用户代码必须实现{@link #process(Object[])}方法。 * <p> * 对SQL中每一条记录,{@link #process(Object[])}方法都会被调用一次。 * </p> * * @param args * 参数数组,对应SQL调用时的参数。 * @throws UDFException * 通用{@link UDF}异常 */ public abstract void process(Object[] args) throws UDFException,IOException; /** * 在{@link UDTF}运行期,{@link #process(Object[])}把全部记录处理完以之后, * 即当前实例没有其它需要处理的记录了,{@link #close()}}此时会被调用一次。 * <p> * 默认实现为空实现,用户代码可以覆盖此方法。 * </p> * * @throws UDFException * 通用{@link UDF}异常 */ public void close() throws UDFException { } /** * UDTF输出,对应SQL语句UDTF的as子句指定的列。<br /> * 该方法通常是把输出行传给关联的 {@link UDTFCollector} 实例。 * * <p> * 默认实现调用 {@link UDTFCollector#collect(Object[])} * </p> * 比如:</br> * <pre> * {@code * forward(new String("Hello"), new Long(1), new Double(1.0), new Boolean(true)); * } * </pre> * 分别输出"Hello",1,1.0,true * * @param outs * {@link UDTF}输入参数构成的对象数组 * @throws UDFException * 通用{@link UDF}异常 */ protected void forward(Object... outs) throws UDFException { collector.collect(outs); } /** * 设置 {@link UDTFCollector},以便该 {@link UDTFCollector} 对象与 {@link UDTF} 实例相关联。 <br /> * 由于 {@link UDTF} 可能会在 {@link UDTFCollector} 构造之前被初始化,所以不能在 {@link UDTF} * 的构造函数中指定 {@link UDTFCollector} 。 * * <p> * 设置一个实现UDTFCollector接口的对象。注意:如果在运行期户代码通过调用此方法覆盖默认的UDTFCollector对象,将会造成UDTF无法正常输出。 * </p> * * @param collector * 一个实现了UDTFCollector接口的对象。 * @see UDTFCollector */ public void setCollector(UDTFCollector collector) { this.collector = collector; } /** * 获取{@link UDTF}的默认{@link UDTFCollector}对象。 * <p> * {@link UDTF}在运行时,会被初始化一个实现了{@link UDTFCollector}接口的对象,用户代码通过 {@link #forward(Object...)} * 间接调用 {@link UDTFCollector#collect(Object[])},将结果输出。 * </p> * * @return 一个初始化好的,实现了{@link UDTFCollector}接口的对象。 * @see UDTFCollector */ public UDTFCollector getCollector() { return collector; } }