我需要根据UDF的评估填充字段。 UDF的输入将是输入中的一些其他字段以及csv表。目前,我采取的方法是加载CSV文件,将其分组ALL,然后将其作为包传递给UDF以及其他必需参数。然而,它需要很长时间来完成170k记录的源数据以及大约150k的csv记录的过程(大约3小时)。
我确信必须有更好的有效方法来处理这个问题,因此需要你的投入。
source_alias = LOAD 'src.csv' USING
PigStorage(',') AS (f1:chararray,f2:chararray,f3:chararray);
csv_alias = LOAD 'csv_file.csv' USING
PigStorage(',') AS (c1:chararray,c2:chararray,c3:chararray);
grpd_csv_alias = GROUP csv_alias ALL;
final_alias = FOREACH source_alias GENERATE f1 AS f1,
myUDF(grpd_csv_alias, f2) AS derived_f2;
这是我的UDF的高级别。
public class myUDF extends EvalFunc<String> {
public String exec(Tuple input) throws IOException {
String f2Response = "N";
DataBag csvAliasBag = (DataBag)input.get(0);
String f2 = (String) input.get(1);
try {
Iterator<Tuple> bagIterator = csvAliasBag.iterator();
while (bagIterator.hasNext()) {
Tuple localTuple = (Tuple)bagIterator.next();
String col1 = ((String)localTuple.get(1)).trim().toLowerCase();
String col2 = ((String)localTuple.get(2)).trim().toLowerCase();
String col3 = ((String)localTuple.get(3)).trim().toLowerCase();
String col4 = ((String)localTuple.get(4)).trim().toLowerCase();
<Custom logic to populate f2Response based on the value in f2 and as well as col1, col2, col3 and col4>
}
}
return f2Response;
}
catch(Exception e){
throw new IOException("Caught exception processing input row ", e);
}
}
}
我认为该过程花费的时间太长,因为为源文件中的每一行构建并将csv_alias传递给UDF。
有没有更好的方法来解决这个问题?
由于
答案 0 :(得分:2)
对于小文件,您可以将它们放在分布式缓存上。这会将文件作为本地文件复制到每个任务节点,然后您自己加载它。以下是Pig docs UDF section的示例。但是,我不建议每次解析文件。将结果存储在类变量中,并检查它是否已初始化。如果csv位于本地文件系统上,请使用getShipFiles。如果您使用的csv在HDFS上,则使用getCachedFiles方法。请注意,对于HDFS,文件路径后跟#和一些文本。 #左侧是HDFS路径,右侧是您希望在将其复制到本地文件系统时调用的名称。
public class Udfcachetest extends EvalFunc<String> {
public String exec(Tuple input) throws IOException {
String concatResult = "";
FileReader fr = new FileReader("./smallfile1");
BufferedReader d = new BufferedReader(fr);
concatResult +=d.readLine();
fr = new FileReader("./smallfile2");
d = new BufferedReader(fr);
concatResult +=d.readLine();
return concatResult;
}
public List<String> getCacheFiles() {
List<String> list = new ArrayList<String>(1);
list.add("/user/pig/tests/data/small#smallfile1"); // This is hdfs file
return list;
}
public List<String> getShipFiles() {
List<String> list = new ArrayList<String>(1);
list.add("/home/hadoop/pig/smallfile2"); // This local file
return list;
}
}