【问题标题】:Kafka Avro To BigQuery using Apache Beam in JavaKafka Avro 到 BigQuery 使用 Java 中的 Apache Beam
【发布时间】:2022-01-28 15:19:58
【问题描述】:

这是场景:

Kafka 到 BigQuery 使用 Apache Beam。这是使用 Kafka Connect 的 BigQuerySinkConnector [WePay] 的替代方案。

我已经能够阅读来自 Kafka 主题的 Avro 消息。我还能够准确地将内容打印到控制台。我正在寻求将这些 KafkaRecords 写入 BigQuery 表的帮助。

PipelineOptions options = PipelineOptionsFactory.create();
        Pipeline pipeline = Pipeline.create(options);
        //Customer is an auto generated class from avro schema using eclipse avro maven plugin
        // Read from Kafka Topic and get KafkaRecords
        @SuppressWarnings("unchecked")
        PTransform<PBegin, PCollection<KafkaRecord<String, Customer>>> input = KafkaIO.<String, Customer>read()
                    .withBootstrapServers("http://server1:9092")
                       .withTopic("test-avro")
                       .withConsumerConfigUpdates(ImmutableMap.of("specific.avro.reader", (Object)"true"))
                       .withConsumerConfigUpdates(ImmutableMap.of("auto.offset.reset", (Object)"earliest"))
                       .withConsumerConfigUpdates(ImmutableMap.of("schema.registry.url", (Object)"http://server2:8181"))
                       .withKeyDeserializer(StringDeserializer.class)
                       .withValueDeserializerAndCoder((Class)KafkaAvroDeserializer.class, AvroCoder.of(Customer.class));
        
        
        // Print kafka records to console log
        
        pipeline.apply(input)
                .apply("ExtractRecord", ParDo.of(new DoFn<KafkaRecord<String,Customer>, KafkaRecord<String,Customer>>() { 
                    @ProcessElement
                    public void processElement(ProcessContext c) {
                        KafkaRecord<String, Customer> record = (KafkaRecord<String, Customer>) c.element();
                        KV<String, Customer> log = record.getKV();
                        System.out.println("Key Obtained: " + log.getKey());
                        System.out.println("Value Obtained: " + log.getValue().toString());
                        c.output(record);
                        
                    }
                }));
                
        // Write each record to BigQuery Table 
        // Table is already available in BigQuery so create disposition would be CREATE_NEVER
        // Records to be appended to table - so write disposition would be WRITE_APPEND
        // All fields in the Customer object have corresponding column names and datatypes - so it is one to one mapping
        
        // Connection to BigQuery is through service account JSON file. This file has been set as environment variable in run config of eclipse project
        // Set table specification for BigQuery
          String bqTable = "my-project:my-dataset:my-table";

当前可用的示例 - 展示了如何手动设置架构并逐字段分配值。我正在寻找一种自动方法来推断 Customer Avro 对象并将其直接分配给列,而无需逐个字段分配这种手动字段。

这可能吗?

【问题讨论】:

    标签: java apache-kafka google-bigquery apache-beam avro


    【解决方案1】:

    经过多次反复试验,我能够完成以下工作。

    我欢迎评论 cmets 分享问题/提出更好的解决方案。

            SchemaRegistryClient registryClient = new CachedSchemaRegistryClient(http://server2:8181,10);
            SchemaMetadata latestSchemaMetadata;
            Schema avroSchema = null; 
            try {
                // getLatestSchemaMetadata takes the subject name which is topic-value format where "-value" is suffixed to topic
                // so if topic is "test-avro" then subject is "test-avro-value"
                latestSchemaMetadata = registryClient.getLatestSchemaMetadata("test-avro-value");
                avroSchema = new Schema.Parser().parse(latestSchemaMetadata.getSchema());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                System.out.println("IO Exception while obtaining registry data");
                e.printStackTrace();
            } catch (RestClientException e) {
                // TODO Auto-generated catch block
                System.out.println("Client Exception while obtaining registry data");
                e.printStackTrace();
                
            }
            
            // Printing avro schema obtained
            System.out.println("---------------- Avro schema ----------- " + avroSchema.toString());
            
            PipelineOptions options = PipelineOptionsFactory.create();
            Pipeline pipeline = Pipeline.create(options);
            
            
            // Read from Kafka Topic and get KafkaRecords
            // Create KafkaIO.Read with Avro schema deserializer
            @SuppressWarnings("unchecked")
            KafkaIO.Read<String, GenericRecord> read = KafkaIO.<String, GenericRecord>read()
                .withBootstrapServers("http://server1:9092")
                .withTopic(KafkaConfig.getInputTopic())
                .withConsumerConfigUpdates(ImmutableMap.of("schema.registry.url", "http://server2:8181"))
                .withConsumerConfigUpdates(ImmutableMap.of("specific.avro.reader", (Object)"true"))
                .withConsumerConfigUpdates(ImmutableMap.of("auto.offset.reset", (Object)"earliest"))
                .withKeyDeserializer(StringDeserializer.class)
                .withValueDeserializerAndCoder((Class) KafkaAvroDeserializer.class, AvroCoder.of(avroSchema));
            
            
            // Set Beam Schema
            
            org.apache.beam.sdk.schemas.Schema beamSchema = AvroUtils.toBeamSchema(avroSchema); 
            
            // Print kafka records to console log
                            
            // Write each record to BigQuery Table 
            // Table is already available in BigQuery so create disposition would be CREATE_NEVER
            // Records to be appended to table - so write disposition would be WRITE_APPEND
            // All fields in the Customer object have corresponding column names and datatypes - so it is one to one mapping
            
            // Connection to BigQuery is through service account JSON file. This file has been set as environment variable in run config of eclipse project
            // Set table specification for BigQuery
              String bqTable = "my-project:my-dataset:my-table";
            
            p.apply(read)
            .apply("ExtractRecord", ParDo.of(new DoFn<KafkaRecord<String,GenericRecord>, KV<String, GenericRecord>>() { 
                /**
                 * 
                 */
                private static final long serialVersionUID = 1L;
    
                @ProcessElement
                public void processElement(ProcessContext c) {
                    KafkaRecord<String, GenericRecord> record = (KafkaRecord<String, GenericRecord>) c.element();
                    KV<String, GenericRecord> log = record.getKV();
                    System.out.println("Key Obtained: " + log.getKey());
                    System.out.println("Value Obtained: " + log.getValue().toString());
                    c.output(log);
                    
                }
            }))
            .apply(Values.<GenericRecord>create()).setSchema(beamSchema, TypeDescriptor.of(GenericRecord.class) ,AvroUtils.getToRowFunction(GenericRecord.class, avroSchema), AvroUtils.getFromRowFunction(GenericRecord.class))
            .apply(BigQueryIO.<GenericRecord>write()
                    .to(tableSpec)
                    .useBeamSchema()
                    .withCreateDisposition(CreateDisposition.CREATE_NEVER)
                    .withWriteDisposition(WriteDisposition.WRITE_APPEND));
            
            p.run().waitUntilFinish();
    
    

    以上内容也适用于 CREATE_IF_NEEDED。

    【讨论】:

      猜你喜欢
      • 2019-07-12
      • 1970-01-01
      • 2018-11-18
      • 2018-12-29
      • 1970-01-01
      • 2018-12-07
      • 2021-02-25
      • 1970-01-01
      • 2021-06-14
      相关资源
      最近更新 更多