我正在加载CSV文件,并使用自定义地图功能将每一行转换为POJO。对于我的程序逻辑,我需要每个POJO一个从0到n的唯一id(其中n是总行数)。我的问题是,我可以使用转换函数为每个POJO分配一个唯一的ID(例如初始行号)吗?理想的方法是在UDF中获取Iterable并在迭代输入元组时递增变量,最后输出相应的POJO。我的代码目前看起来像这样:
DataSet<MyType> input = env.readCsvFile("/path/file.csv")
.includeFields("1111")
.types(String.class, Double.class, Double.class,Double.class)
.map(new ParseData());
其中ParseData将元组转换为MyType POJO。
是否有实现此任务的最佳做法?
答案 0 :(得分:3)
棘手的部分是,您在分布式系统中运行代码,因此ParseData
函数的并行实例彼此独立运行。
您仍然可以使用ParseData
中的本地ID计数器分配唯一ID。避免重复的技巧是正确的初始化和计数器增量。假设你有四个并行性,你会得到四个ParseData
个实例(我们称之为PD1 ... PD4
)。您将执行以下ID分配:
PD1: 0, 4, 8, 12, ...
PD2: 1, 5, 9, 13, ...
PD3, 2, 6, 10, 14, ...
PD4: 3, 7, 11, 15, ...
您可以通过初始化具有不同值的并行实例(详情如下)来完成此操作,并通过并行性(即ID += parallelism
)增加每个实例中的计数。
在Flink中,并行函数的所有实例都会自动获得一个唯一的编号(所谓的任务索引)。您只需使用此号码初始化您的ID计数器即可。您可以通过RuntimeContext.getIndexOfThisSubtask()
获取任务索引。您还可以通过RuntimeContext.getNumberOfParallelSubtasks()
要让RuntimeContext
使用RichMapFunction
来实施ParseData
并在getRuntimeContext()
中致电open()
。
像这样(只显示相关方法):
class ParseDate extends RichMapFunction {
private long parallelism;
private long idCounter;
public void open(Configuration parameters) {
RuntimeContext ctx = getRuntimeContext();
parallelism = ctx.getNumberOfParallelSubtasks();
idCounter = ctx.getIndexOfThisSubtask();
}
public OutputDataType map(InputDataType value) {
OutputDataType output = new OutputDataType();
output.setID(idCounter);
idCounter += parallelism;
// further processing
return output;
}
}