![](/img/trans.png)
[英]Google dataflow job with Apache Beam 2.9.0 Java SDK stuck
[英]Transform a large jsonl file with unknown json properties into csv using apache beam google dataflow and java
如何使用 Apache Beam、google 数据流和 Z923F718464Z8B323C1F725A048B323C1F725A048423C1F725A048423C1F725A07B323FZ 将具有未知 json 属性的大型 jsonl 文件转换为 csv
这是我的场景:
任何帮助或指导都会有所帮助,因为我是 Apache 光束的新手,尽管我正在阅读 Apache 光束的文档。
我已经使用示例 JSONL 数据编辑了问题
{"Name":"Gilbert", "Session":"2013", "Score":"24", "Completed":"true"} {"Name":"Alexa", "Session":"2013", "Score":"29", "Completed":"true"} {"Name":"May", "Session":"2012B", "Score":"14", "Completed":"false"} {"Name":"Deloise", "Session":"2012A", "Score":"19", "Completed":"true"}
虽然 json 密钥存在于输入文件中,但在转换时不知道。 我将通过一个例子来解释,假设我有三个客户端,每个客户端都有自己的谷歌存储,所以每个客户端都上传自己的具有不同 json 属性的 jsonl 文件。
客户端1:输入Jsonl文件
{"city":"Mumbai", "pincode":"2012A"} {"city":"Delhi", "pincode":"2012N"}
客户端2:输入Jsonl文件
{"Relation":"Finance", "Code":"2012A"} {"Relation":"Production", "Code":"20XXX"}
客户端 3:输入 Jsonl 文件
{"Name":"Gilbert", "Session":"2013", "Score":"24", "Completed":"true"} {"Name":"Alexa", "Session":"2013", "Score":"29", "Completed":"true"}
问题:我如何编写一个通用光束管道来转换所有三个,如下所示
客户端 1:Output CSV 文件
["city", "pincode"] ["Mumbai","2012A"] ["Delhi", "2012N"]
客户端 2:Output CSV 文件
["Relation", "Code"] ["Finance", "2012A"] ["Production","20XXX"]
客户端 3:Output CSV 文件
["Name", "Session", "Score", "true"] ["Gilbert", "2013", "24", "true"] ["Alexa", "2013", "29", "true"]
编辑:删除了以前的答案,因为问题已通过示例进行了修改。
任何人都没有提供通用的方法来实现这样的结果。 您必须根据自己的要求以及处理管道的方式自己编写逻辑。
下面有一些示例,但您需要根据您的情况验证这些示例,因为我只在一个小的JSONL文件上尝试过这些示例。
方法一
如果能收集到 output csv 的 header 值,那就容易多了。 但是事先获得 header 本身就是另一个挑战。
//pipeline pipeline.apply("ReadJSONLines", TextIO.read().from("FILE URL")).apply(ParDo.of(new DoFn<String, String>() { @ProcessElement public void processLines(@Element String line, OutputReceiver<String> receiver) { String values = getCsvLine(line, false); receiver.output(values); } })).apply("WriteCSV", TextIO.write().to("FileName").withSuffix(".csv").withoutSharding().withDelimiter(new char[] { '\r', '\n' }).withHeader(getHeader()));
private static String getHeader() { String header = ""; //your logic to get the header line. return header; }
获得 header 线的可能方法(仅假设可能不适用于您的情况):
方法二
这是我为小型 JsonFiles(~10k 行)找到的解决方法。 下面的示例可能不适用于大文件。
final int[] count = { 0 }; pipeline.apply(//read file).apply(ParDo.of(new DoFn<String, String>() { @ProcessElement public void processLines(@Element String line, OutputReceiver<String> receiver) { // check if its the first processing element. If yes then create the header if (count[0] == 0) { String header = getCsvLine(line, true); receiver.output(header); count[0]++; } String values = getCsvLine(line, false); receiver.output(values); } })).apply(//write file)
正如Saransh在评论中提到的,使用FileIO您所要做的就是手动逐行读取 JSONL,然后将其转换为逗号分隔的格式。例如:
pipeline.apply(FileIO.match().filepattern("FILE PATH")).apply(FileIO.readMatches()).apply(FlatMapElements.into(TypeDescriptors.strings()).via((FileIO.ReadableFile f) -> { List<String> output = new ArrayList<>(); try (BufferedReader br = new BufferedReader(Channels.newReader(f.open(), "UTF-8"))) { String line = br.readLine(); while (line.= null) { if (output,size() == 0) { String header = getCsvLine(line; true). output;add(header), } String result = getCsvLine(line; false). output;add(result). line = br;readLine(), } } catch (IOException e) { throw new RuntimeException("Error while reading"; e); } return output. })) apply(//write to gcs)
在上面的示例中,我使用了getCsvLine
方法(为代码可用性而创建),它从文件中获取一行并将其转换为逗号分隔的格式。解析JSON object 我使用了ZB0AA3DCF4968BF44E701A
/** * @param line take each JSONL line * @param isHeader true: Returns output combining the JSON keys || false: * Returns output combining the JSON values **/ public static String getCsvLine(String line, boolean isHeader) { List<String> values = new ArrayList<>(); // convert the line into jsonobject JsonObject jsonObject = JsonParser.parseString(line).getAsJsonObject(); // iterate json object and collect all values for (Map.Entry<String, JsonElement> entry: jsonObject.entrySet()) { if (isHeader) values.add(entry.getKey()); else values.add(entry.getValue().getAsString()); } String result = String.join(",", values); return result; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.