我有一个用例,其中我初始化了一个HashMap,其中包含一组查找数据(有关IoT设备的物理位置的信息)。该查找数据用作第二数据集(作为PCollection)的参考数据。此PCollection是一个数据流,提供了IoT设备记录的数据。来自IoT设备的数据流使用Apache Beam管道,该管道利用Google Cloud pub / sub作为Google Dataflow运行。
处理PCollection(设备数据)时,我将Google Cloud发布/订阅数据链接到HashMap中的相关查找条目。
我需要基于第二个将更改数据推送到其上的发布/订阅来更新HashMap。到目前为止,这是我获取PCollection并使用HashMap进行查找的方式:
HashMap ->包含预加载的查找数据(有关IoT设备的信息)
PCollection ->包含管道数据流中的数据(物联网设备记录的数据)
我正在为物联网设备查找数据作为单例生成HashMap:
public class MyData {
private static final MyData instance = new MyData ();
private MyData () {
HashMap myDataMap = new HashMap<String, String>();
... logic to populate the map
this.referenceData = myDataMap;
}
public HashMap<Integer, DeviceReference> referenceData;
public static DeviceData getInstance(){
return instance;
}
}
然后我在另一个类中使用HashMap,我在该类中订阅数据更新(这些消息是例如为我提供与已经存储在HashMap中的实体相关的新数据)。我正在使用带有Apache Beam的Google pub / sub订阅更改:
HashMap<String, String> referenceData = MyData.getInstance().referenceData;
Pipeline pipeLine = Pipeline.create(options);
// subscribe to changes in data
org.apache.beam.sdk.values.PCollection myDataUpdates;
myDataUpdates = pipeLine.begin()
.apply(String.format("Subscribe to data updates"),
PubsubIO.readStrings().fromTopic(
String.format("myPubSubPath")));
我要做的是将数据更新有效地应用于单例HashMap(即根据我的数据订阅操作HashMap)。我该怎么办?
我对Apache Beam的了解有限,我只知道如何对管道数据进行转换以创建另一个单独的PCollection
。我认为这就是Beam的意义,它是用于将大型数据集转换为另一种形式。有没有一种方法可以使用Apache Beam来实现我所需要的(基于发布/订阅的更新数据集),或者还有另一种可以使用发布/订阅来更新HashMap的方法? (我无法轮询数据,因为它会产生过多的延迟和成本,我需要使用订阅来更新HashMap。)
Google云文档显示了一种directly subscribing to a Google Cloud pub/sub that isn't linked to an Apache Beam pipeline的方式。这有望成为一种潜在的解决方案,并且依赖于以下Maven依赖项:
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-pubsub</artifactId>
<version>1.53.0</version>
</dependency>
但是我遇到了冲突,这与Apache Beam的以下Maven依赖项冲突:
<dependency>
<groupId>com.google.cloud.dataflow</groupId>
<artifactId>google-cloud-dataflow-java-sdk-all</artifactId>
<version>2.5.0</version>
</dependency>
此问题记录在此处的另一个问题中-Maven conflict in Java app with google-cloud-core-grpc dependency。从我所看到的,看来我使用哪个版本的google-cloud-pubsub
Maven工件都没关系,因为我发现它看起来像
(我在Beam Jira中提出了这个问题-https://issues.apache.org/jira/browse/BEAM-6118)
我目前正在研究侧面输入和combine
,作为实现HashMap更新的一种方式:
https://www.programcreek.com/java-api-examples/?api=org.apache.beam.sdk.transforms.Combine
示例10显示了将.getSideInputsMap()
应用于payload
的方式。我想知道是否可以将其以某种方式应用于我对查询数据更改的订阅。如果我得到这样的PCollection
,则无法直接将.getSideInputsMap()
链接到PCollection
deviceReferenceDataUpdates = pipeLine.begin()
.apply("Get changes to the IoT device lookup data"),
PubsubIO.readMessages().fromTopic("IoT device lookup data")).
我已经问了一个单独的问题,专门关于如何使用.getSideInputsMap()
-Apache Beam - how can I apply .getSideInputsMap to a subscription to a Google pub/sub?
答案 0 :(得分:1)
我在Apache Beam框架中找到了一种方法,如下所示(未经充分测试)。
注意 -考虑到@Serg M 10对OP的评论,更好的方法可能是稍后合并数据, 而不是尝试在转换过程中加入查找数据。
在这里查看我的答案-Accessing a HashMap from a different class
main
中实现)// initialise singleton HashMap containing lookup data on bootstrap:
LookupData lookupData = LookupData.getInstance();
org.apache.beam.sdk.values.PCollection lookupDataUpdateMessage;
lookupDataUpdateMessage = pipeLine.begin()
.apply("Extract lookup update data", PubsubIO.readStrings().fromTopic("myLookupUpdatePubSubTopic"))
.apply("Transform lookup update data",
ParDo.of(new TransformLookupData.TransformFn()));
org.apache.beam.sdk.values.PCollection lookupDataMessage;
import java.io.Serializable;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubMessage;
import org.apache.beam.sdk.transforms.DoFn;
import org.json.JSONObject;
import myLookupSingletonClass;
import myLookupUpObjectClass;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.api.client.util.Strings;
public class TransformDeviceMeta
public static class TransformFn extends DoFn<String, MyLookupData> {
@ProcessElement
public void processElement(ProcessContext c)
{
LookupData lookupData = LookupData.getInstance();
MyLookupData myLookupDataUpdate = new MyLookupData();
try
{
byte[] payload = c.element().getBytes();
String myLookUpDataJson = new JSONObject(new String(payload)).toString();
ObjectMapper mapper = new ObjectMapper();
myLookUpDataUpdate = mapper.readValue(myLookUpDataJson , MyLookupData.class);
String updatedLookupDataId = updatedLookupDataId.id;
// logic for HashMap updating e.g:
lookupData.myHashMap.remove(updatedDeviceId);
}
else {
lookupData.myHashMap.put(updatedDeviceId, deviceMetaUpdate);
}
}
catch (Exception ex) {
Log.error(ex.getMessage());
System.out.println("Error " + ex.getMessage());
}
}
}
}
MyLookupData
=构成查找数据模型的类