使用SideInput加入收藏

时间:2019-07-24 11:33:08

标签: google-cloud-dataflow apache-beam

尝试使用SideInput转换加入两个Pcollection。在ParDo函数中,在映射值时,可以从sideinput集合中获取多个映射记录作为一个集合。在这种情况下,如何处理该集合以及如何将这些值的集合返回给PCollection。

如果有人帮助解决这个问题,那将是很好的。这是我尝试过的代码段。

PCollection<TableRow> pc1 = ...;
PCollection<Row> pc1Rows = pc1.apply(
    ParDo.of(new fnConvertTableRowToRow())).setRowSchema(schemaPc1);
PCollection<KV<Integer, Row>> keyed_pc1Rows = pc1Rows.apply(
    WithKeys.of(new SerializableFunction<Row, Integer>() {
       public Integer apply(Row s) {
         return Integer.parseInt(s.getValue("LOCATION_ID").toString());
       }
    }));

PCollection<TableRow> pc2 = ...;

PCollection<Row> pc2Rows = pc2.apply(
    ParDo.of(new fnConvertTableRowToRow())).setRowSchema(schemaPc2);

PCollection<KV<Integer, Iterable<Row>>> keywordGroups = pc2Rows.apply(
    new fnGroupKeyWords());

PCollectionView<Map<Integer, Iterable<Row>>> sideInputView =
    keywordGroups.apply("Side Input",
       View.<Integer, Iterable<Row>>asMap());

PCollection<Row> finalResultCollection = keyed_pc1Rows.apply("Process",
  ParDo.of(new DoFn<KV<Integer,Row>, Row>() {

    @ProcessElement
    public void processElement(ProcessContext c) {

      Integer key = Integer.parseInt(c.element().getKey().toString());

      Row leftRow = c.element().getValue();

      Map<Integer, Iterable<Row>> key2Rows = c.sideInput(sideInputView);

      Iterable<Row> rightRowsIterable = key2Rows.get(key);

      for (Iterator<Row> i = rightRowsIterable.iterator(); i.hasNext(); ) {
        Row suit = (Row) i.next();
        Row targetRow = Row.withSchema(schemaOutput)
                           .addValues(leftRow.getValues())
                           .addValues(suit.getValues())
                           .build();
        c.output(targetRow);
      }
    }
}).withSideInputs(sideInputView));
public static class fnGroupKeyWords extends
  PTransform<PCollection<Row>, PCollection<KV<Integer, Iterable<Row>>>> {

  @Override
  public PCollection<KV<Integer, Iterable<Row>>> expand(
    PCollection<Row> rows) {

      PCollection<KV<Integer, Row>> kvs = rows.apply(
          ParDo.of(new TransferKeyValueFn()));
      PCollection<KV<Integer, Iterable<Row>>> group = kvs.apply(
          GroupByKey.<Integer, Row> create());
      return group;
  }
}

public static class TransferKeyValueFn extends
  DoFn<Row, KV<Integer, Row>> {

  @ProcessElement
  public void processElement(ProcessContext c) throws ParseException {
    Row tRow = c.element();

    c.output(
       KV.of(
          Integer.parseInt(tRow.getValue("DW_LOCATION_ID").toString()),
          tRow));
  }
}

1 个答案:

答案 0 :(得分:0)

我认为,如果您有一个很小的集合可以容纳到内存中,那么使用SideInput建议效果会很好。您可以将其用作view.asMultimap的辅助输入。然后在ParDo中处理较大的PCollection(在完成GBK之后,为您提供密钥的所有元素的迭代方法),从侧面输入中查找您感兴趣的密钥。这是一个example test pipeline,它使用了多图pcollection。

但是,如果您的集合很大,那么使用Flatten将两个pcollections组合在一起将是更好的方法。然后再使用GroupByKey,这将为您提供在同一键下可迭代的element元素。这仍将顺序处理。不过,除非您消除热键,否则我相信您会遇到性能问题。 Please see the explanation of using combiners to alleviate this