Как реализовать функцию луча sql udf для разделения одного столбца на несколько столбцов? Я уже реализовал это в функции udf bigquery:

CREATE TEMP FUNCTION parseDescription(description STRING)
RETURNS STRUCT<msg STRING, ip STRING, source_region STRING, user_name STRING>
LANGUAGE js AS """
var arr = description.substring(0, description.length - 1).split(",");
var firstIndex = arr[0].indexOf(".");
this.msg = arr[0].substring(0, firstIndex);
this.ip = arr[0].substring(firstIndex + 2).split(": ")[1];
this.source_region = arr[1].split(": ")[1];
this.user_name = arr[2].split(": ")[1];
return this;
""";
INSERT INTO `table1` (parseDescription(event_description).* FROM `table2`;

Поддерживает ли функция beam sql udf такую ​​операцию? Я попытался вернуть объект в функции луча udf, но кажется, что луч sql не поддерживает синтаксис object. *. Я также пытался вернуть карту или массив, но все равно получал ошибку. Есть ли способ реализовать такой же udf в луче?

Я попытался использовать метод MapElement, но получил ошибку, похоже, что выходная строка ожидала ту же схему, что и входная строка, например:

import org.apache.beam.runners.direct.DirectOptions;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.extensions.sql.SqlTransform;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.schemas.Schema;
import org.apache.beam.sdk.transforms.*;
import org.apache.beam.sdk.values.PBegin;
import org.apache.beam.sdk.values.PCollection;
import org.apache.beam.sdk.values.Row;

public class BeamMain2 {
    public static void main(String[] args) {

        DirectOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
                .as(DirectOptions.class);
        Pipeline p = Pipeline.create(options);
        // Define the schema for the records.
        Schema appSchema = Schema.builder().addStringField("string1").addInt32Field("int1").build();
        Row row1 = Row.withSchema(appSchema).addValues("aaa,bbb", 1).build();
        Row row2 = Row.withSchema(appSchema).addValues("ccc,ddd", 2).build();
        Row row3 = Row.withSchema(appSchema).addValues("ddd,eee", 3).build();
        PCollection<Row> inputTable =
                PBegin.in(p).apply(Create.of(row1, row2, row3).withRowSchema(appSchema));
        Schema newSchema =
                Schema.builder()
                        .addNullableField("string2", Schema.FieldType.STRING)
                        .addInt32Field("int1")
                        .addNullableField("string3", Schema.FieldType.STRING)
                        .build();

        PCollection<Row> outputStream = inputTable.apply(
                SqlTransform.query(
                        "SELECT * "
                                + "FROM PCOLLECTION where int1 > 1"))
        .apply(MapElements.via(
                new SimpleFunction<Row, Row>() {
                    @Override
                    public Row apply(Row line) {
                        return Row.withSchema(newSchema).addValues("a", 1, "b").build();
                    }
                }));
        p.run().waitUntilFinish();
    }
}
0
Ruixue Liao 15 Апр 2020 в 22:24

1 ответ

Лучший ответ

Ссылка: https://beam.apache.org/documentation/dsls/sql/overview / Вы можете использовать элементы Emit 'Row' из преобразования, которые позже можно будет использовать в качестве таблицы.

Трубопровод будет выглядеть примерно так

Схема

Schema schema =
    Schema.of(Schema.Field.of("f0", FieldType.INT64), Schema.Field.of("f1", FieldType.INT64));

Преобразовать

private static MapElements<Row, Row> rowsToStrings() {
return MapElements.into(TypeDescriptor.of(Row.class))
    .via(
        row -> Row.withSchema(schema).addValue(1L).addValue(2L).build(););
}

Трубопровод:

  pipeline
      .apply(
          "SQL Query 1",
          SqlTransform.query(<Query string 1>))
      .apply("Transform column", rowsToStrings())
      .apply(
          "SQL Query 2",
          SqlTransform.query(<Query string 2>))
1
Ankur 16 Апр 2020 в 00:57