在Google数据流(java)中创建复杂的BigQuery模式

在Google数据流(java)中创建复杂的BigQuery模式,java,google-cloud-platform,google-bigquery,google-cloud-dataflow,apache-beam,Java,Google Cloud Platform,Google Bigquery,Google Cloud Dataflow,Apache Beam,我有一个无限的复杂对象流,我想加载到BigQuery中。这些对象的结构表示BigQuery中目标表的模式 问题是,由于POJO中有很多嵌套字段,因此将其转换为TableSchema对象是一个非常困难的过程,我正在寻找一种快速/自动的方法,在写入BigQuery时将POJO转换为TableSchema对象 我对Apache Beam API不太熟悉,如有任何帮助,将不胜感激。如果您在PubSub中使用JSON进行消息序列化,您可以使用提供的模板之一: 该模板的代码如下所示: 在管道中,我从GCS

我有一个无限的复杂对象流,我想加载到BigQuery中。这些对象的结构表示BigQuery中目标表的模式

问题是,由于POJO中有很多嵌套字段,因此将其转换为
TableSchema
对象是一个非常困难的过程,我正在寻找一种快速/自动的方法,在写入BigQuery时将POJO转换为
TableSchema
对象


我对Apache Beam API不太熟悉,如有任何帮助,将不胜感激。

如果您在PubSub中使用JSON进行消息序列化,您可以使用提供的模板之一:

该模板的代码如下所示:


在管道中,我从GCS加载模式列表。我将它们保留为字符串格式,因为表模式是不可序列化的。但是,我将它们加载到TableSchema中进行验证。 然后我将它们以字符串格式添加到选项对象中的映射中

String schema = new String(blob.getContent());
// Decorate list of fields for allowing a correct parsing
String targetSchema = "{\"fields\":" + schema + "}";
try {
    //Preload schema to ensure validity, but then use string version
    Transport.getJsonFactory().fromString(targetSchema, TableSchema.class);

    String tableName = blob.getName().replace(SCHEMA_FILE_PREFIX, "").replace(SCHEMA_FILE_SUFFIX, "");
    tableSchemaStringMap.put(tableName, targetSchema);
} catch (IOException e) {
    logger.warn("impossible to read schema " + blob.getName() + " in bucket gs://" + options.getSchemaBucket());
}

当我开发这个时,我没有找到另一个解决方案。

在我的公司,我创建了一种ORM(我们称之为OBQM)来实现这一点。我们期待着向公众发布它。代码相当大(特别是因为我创建了注释等),但我可以与您分享一些用于快速生成架构的代码片段:

public TableSchema generateTableSchema(@Nonnull final Class cls) {

        final TableSchema tableSchema = new TableSchema();
        tableSchema.setFields(generateFieldsSchema(cls));

        return tableSchema;
    }

public List<TableFieldSchema> generateFieldsSchema(@Nonnull final Class cls) {

        final List<TableFieldSchema> schemaFields = new ArrayList<>();
        final Field[] clsFields = cls.getFields();

        for (final Field field : clsFields) {
            schemaFields.add(fromFieldToSchemaField(field));
        }

        return schemaFields;
    }
现在是返回BigQuery字段类型的方法

public static String getFieldTypeString(@Nonnull final Field field) {
   // On my side this code is much complex but this is a short version of that
   final Class<?> cls = (Class<?>) field.getGenericType()
   if (cls.isAssignableFrom(String.class)) {
            return "STRING";
        } else if (cls.isAssignableFrom(Integer.class) || cls.isAssignableFrom(Short.class)) {
            return "INT64";
        } else if (cls.isAssignableFrom(Double.class)) {
            return "NUMERIC";
        } else if (cls.isAssignableFrom(Float.class)) {
            return "FLOAT64";
        } else if (cls.isAssignableFrom(Boolean.class)) {
            return "BOOLEAN";
        } else if (cls.isAssignableFrom(Double.class)) {
            return "BYTES";
        } else if (cls.isAssignableFrom(Date.class)
                || cls.isAssignableFrom(DateTime.class)) {
            return "TIMESTAMP";
        } else {
            return "STRUCT";
        }
    }
公共静态字符串getFieldTypeString(@Nonnull final Field){
//就我而言,这段代码非常复杂,但这是它的一个简短版本
最终类cls=(类)字段。getGenericType()
if(cls.isAssignableFrom(String.class)){
返回“字符串”;
}else if(cls.isAssignableFrom(Integer.class)| | cls.isAssignableFrom(Short.class)){
返回“INT64”;
}else if(cls.isAssignableFrom(Double.class)){
返回“数字”;
}else if(cls.isAssignableFrom(Float.class)){
返回“FLOAT64”;
}else if(cls.isAssignableFrom(Boolean.class)){
返回“布尔”;
}else if(cls.isAssignableFrom(Double.class)){
返回“字节”;
}else if(cls.isAssignableFrom(Date.class)
||cls.isAssignableFrom(DateTime.class)){
返回“时间戳”;
}否则{
返回“STRUCT”;
}
}

请记住,我并没有展示如何识别基元类型或数组。但这是代码的良好开端:)。如果您需要任何帮助,请告诉我。

可能值得一看pubsubbigquery.java,看看是否可以用无限制的源代码替换PubSub。
public static String getFieldTypeString(@Nonnull final Field field) {
   // On my side this code is much complex but this is a short version of that
   final Class<?> cls = (Class<?>) field.getGenericType()
   if (cls.isAssignableFrom(String.class)) {
            return "STRING";
        } else if (cls.isAssignableFrom(Integer.class) || cls.isAssignableFrom(Short.class)) {
            return "INT64";
        } else if (cls.isAssignableFrom(Double.class)) {
            return "NUMERIC";
        } else if (cls.isAssignableFrom(Float.class)) {
            return "FLOAT64";
        } else if (cls.isAssignableFrom(Boolean.class)) {
            return "BOOLEAN";
        } else if (cls.isAssignableFrom(Double.class)) {
            return "BYTES";
        } else if (cls.isAssignableFrom(Date.class)
                || cls.isAssignableFrom(DateTime.class)) {
            return "TIMESTAMP";
        } else {
            return "STRUCT";
        }
    }