Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 数据流大端输入中的Apache Beam_Java_Google Bigquery_Google Cloud Dataflow_Apache Beam - Fatal编程技术网

Java 数据流大端输入中的Apache Beam

Java 数据流大端输入中的Apache Beam,java,google-bigquery,google-cloud-dataflow,apache-beam,Java,Google Bigquery,Google Cloud Dataflow,Apache Beam,这是最相似的 我正在Dataflow2.x中创建一个管道,它从Pubsub队列获取流式输入。传入的每一条消息都需要通过一个非常大的数据集进行流式传输,该数据集来自Google BigQuery,并在写入数据库之前附加所有相关值(基于一个键) 问题在于BigQuery中的映射数据集非常大—任何将其用作辅助输入的尝试都会失败,数据流运行程序会抛出错误“java.lang.IllegalArgumentException:ByteString太长”。我尝试了以下策略: 1) 侧面输入 如上所述,映射

这是最相似的

我正在Dataflow2.x中创建一个管道,它从Pubsub队列获取流式输入。传入的每一条消息都需要通过一个非常大的数据集进行流式传输,该数据集来自Google BigQuery,并在写入数据库之前附加所有相关值(基于一个键)

问题在于BigQuery中的映射数据集非常大—任何将其用作辅助输入的尝试都会失败,数据流运行程序会抛出错误“java.lang.IllegalArgumentException:ByteString太长”。我尝试了以下策略:

1) 侧面输入

  • 如上所述,映射数据(显然)太大,无法进行此操作。如果我在这里错了,或者有解决办法,请让我知道,因为这将是最简单的解决方案
2) 键值对映射

  • 在这个策略中,我读取管道第一部分中的BigQuery数据和Pubsub消息数据,然后运行每个ParDo转换,将pcollection中的每个值更改为KeyValue对。然后,我运行Merge.flatte转换和GroupByKey转换,将相关映射数据附加到每条消息
  • 这里的问题是,流数据需要窗口化与其他数据合并,因此我也必须将窗口化应用于大型、有界的BigQuery数据。它还要求两个数据集上的窗口策略相同。但是对于有界数据没有窗口策略是有意义的,我所做的几次窗口尝试只是在一个窗口中发送所有BQ数据,然后再也不发送它。它需要与每个传入的pubsub消息连接
3) 在ParDo中直接呼叫BQ(DoFn)

  • 这似乎是个好主意——让每个工作人员声明地图数据的静态实例。如果它不在那里,那么直接调用BigQuery来获取它。不幸的是,每次BigQuery都会抛出内部错误(正如整个消息中所说的“内部错误”)。向谷歌提交了一份支持票,结果他们告诉我,基本上,“你不能那样做”
似乎这个任务并不真正适合“令人尴尬的并行化”模型,那么我是不是找错了方向

编辑:

即使在数据流中使用高内存机器并试图将侧面输入映射视图时,也会出现错误
java.lang.IllegalArgumentException:ByteString太长

下面是我正在使用的代码示例(psuedo):

    Pipeline pipeline = Pipeline.create(options);

    PCollectionView<Map<String, TableRow>> mapData = pipeline
            .apply("ReadMapData", BigQueryIO.read().fromQuery("SELECT whatever FROM ...").usingStandardSql())
            .apply("BQToKeyValPairs", ParDo.of(new BQToKeyValueDoFn())) 
            .apply(View.asMap());

    PCollection<PubsubMessage> messages = pipeline.apply(PubsubIO.readMessages()
            .fromSubscription(String.format("projects/%1$s/subscriptions/%2$s", projectId, pubsubSubscription)));

    messages.apply(ParDo.of(new DoFn<PubsubMessage, TableRow>() {
        @ProcessElement
        public void processElement(ProcessContext c) {
            JSONObject data = new JSONObject(new String(c.element().getPayload()));
            String key = getKeyFromData(data);
            TableRow sideInputData = c.sideInput(mapData).get(key);
            if (sideInputData != null) {
                LOG.info("holyWowItWOrked");
                c.output(new TableRow());
            } else {
                LOG.info("noSideInputDataHere");
            }
        }
    }).withSideInputs(mapData));

查看本文中名为“模式:流模式大型查找表”的部分(这可能是唯一可行的解决方案,因为您的端输入不适合内存):

说明:

大型(以GB为单位)查找表必须准确,并且经常或经常更改 不适合记忆

示例:

您从零售商处获得了销售点信息,需要 将产品项的名称与 包含productID。有成千上万的物品 存储在可不断更改的外部数据库中。还有,所有 必须使用正确的值处理元素

解决方案:

使用“”模式 但与其调用微服务,不如调用读优化的NoSQL 直接访问数据库(如云数据存储或云Bigtable)

对于要查找的每个值,使用KV创建一个键值对 实用类。执行GroupByKey以创建相同密钥类型的批 对数据库进行调用。在DoFn中,向 该键的数据库,然后按将该值应用于所有值 穿过这片森林。与客户一起遵循最佳实践 如“调用外部服务获取数据”中所述的实例化 浓缩”

本文介绍了其他相关模式:

  • 模式:缓慢更改查找缓存
  • 模式:调用外部服务以丰富数据

您使用的是哪种侧输入视图?你能分享一个你是如何使用它的例子吗?你考虑过使用有状态的ParDo吗?如果您在全局窗口中处理,这将允许您将来自BigQuery的值存储在state中,并使用它来处理来自另一个流的每个值。您需要使用与您提到的相同的Merge.flant方法,因为有状态DoFn仅适用于单个输入集合。对于您来说,第一个注释@BenChambers侧输入是一个大型映射表。每行中都有一个键字符串,该字符串可能与传入Pubsub消息中的数据相匹配。映射数据集每周都会更改,但当前约为4000万行(约10 GB),并且在一周中完全是静态的,不变的。我现在正在查看有状态的pardo文档,看看是否可行……对于侧输入,您是否使用
View.asSingleton
View.asMap
等。?例如--
View.asSingleton
将使用单个元素获取PCollection,并使其对ParDo可见<代码>视图。asMap将采用
PCollection
并将其作为
Map
提供,但将仅读取您需要的键。有相关消息吗?面对同样的问题
java.lang.IllegalArgumentException: ByteString would be too long: 644959474+1551393497
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.concat(ByteString.java:524)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.balancedConcat(ByteString.java:576)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.balancedConcat(ByteString.java:575)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.balancedConcat(ByteString.java:575)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.balancedConcat(ByteString.java:575)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString.copyFrom(ByteString.java:559)
        com.google.cloud.dataflow.worker.repackaged.com.google.protobuf.ByteString$Output.toByteString(ByteString.java:1006)
        com.google.cloud.dataflow.worker.WindmillStateInternals$WindmillBag.persistDirectly(WindmillStateInternals.java:575)
        com.google.cloud.dataflow.worker.WindmillStateInternals$SimpleWindmillState.persist(WindmillStateInternals.java:320)
        com.google.cloud.dataflow.worker.WindmillStateInternals$WindmillCombiningState.persist(WindmillStateInternals.java:951)
        com.google.cloud.dataflow.worker.WindmillStateInternals.persist(WindmillStateInternals.java:216)
        com.google.cloud.dataflow.worker.StreamingModeExecutionContext$StepContext.flushState(StreamingModeExecutionContext.java:513)
        com.google.cloud.dataflow.worker.StreamingModeExecutionContext.flushState(StreamingModeExecutionContext.java:363)
        com.google.cloud.dataflow.worker.StreamingDataflowWorker.process(StreamingDataflowWorker.java:1000)
        com.google.cloud.dataflow.worker.StreamingDataflowWorker.access$800(StreamingDataflowWorker.java:133)
        com.google.cloud.dataflow.worker.StreamingDataflowWorker$7.run(StreamingDataflowWorker.java:771)
        java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        java.lang.Thread.run(Thread.java:745)