Java Flink Left Outer JOIN:使用csv文件中的数据丰富流

Java Flink Left Outer JOIN:使用csv文件中的数据丰富流,java,left-join,flink-streaming,Java,Left Join,Flink Streaming,我正在使用Flink1.4.0 我正在将卡夫卡主题中的数据消费到数据流中。数据被转换成一个POJO,比如说Employee,最后我得到一个类似于: DataStream<Employee> employeeStream = ...; 现在,两个pojo共享一个字段(id),可用于JOIN操作。如果这些是数据集,我本来可以应用leftOuterJoin(),但它们不是。我不关心窗口设置,因为我希望任何员工都能从丰富内容中获得丰富的信息,如果其id出现在csv中。我该怎么做?忽略窗口的

我正在使用Flink
1.4.0

我正在将卡夫卡主题中的数据消费到数据流中。数据被转换成一个
POJO
,比如说
Employee
,最后我得到一个类似于:

DataStream<Employee> employeeStream = ...;
现在,两个
pojo
共享一个字段(id),可用于
JOIN
操作。如果这些是数据集,我本来可以应用
leftOuterJoin()
,但它们不是。我不关心窗口设置,因为我希望任何
员工
都能从
丰富内容
中获得丰富的信息,如果其id出现在csv中。我该怎么做?忽略窗口的联接操作是否有效?这会是资源匮乏吗?看起来像这样吗

    employeeStream 
        .join(enrichmentsStream )
        .where(new SelectKeyForEmployee())
        .equalTo(new SelectKeyForEnrichments())
        .window(?????)
        .apply(new JoinEnrichFunction());

另外,由于窗口必须由两个流共享,在应用
JOIN
函数之前如何定义它们的窗口,以及
joinEnricFunction()
的实现是什么?

在这种情况下,连接操作是多余的。流连接不是直观的,只有在共享相同窗口机制的流之间应用时才有意义

在这种情况下,map函数足以满足此处详述的浓缩目标。以下代码片段应该足够清晰:

public MainClass {
  public void main(String[] args) {
    ...
    // Some custom way of loading the csv data into a Map<POJO> format
    MetadataLoader loader = new MetadataLoader("pathToData.csv");
    Map<Employee> metadataHashMap = loader.getMetadataMap(employeeEnrichmentData);
    ...

    // Enrichment
    SingleOutputStreamOperator<Employee>> enrichedStream = rawStream
            .map(new MapMetadataToEmployees(metadataHashMap))
            .name("Enrich: with Employee Metadata");

    // Some sink opeartion
    ...

  }
}  

final class MapMetadataToEmployees implements MapFunction<Employee, Employee>, Serializable {

  private Map<Employee> metaDataMap;

  public MapMetadataToEmployees(Map<String, Employee> metaDataMap) {
      this.metaDataMap = metaDataMap;
  }

  @Override
  public Employee map(Employee employee) {

      if (metaDataMap.containsKey(employee.getId())) {

          Employee employeeWithMetaData = metaDataMap.get(employee.getId());

          employee.setSalary(employeeWithMetaData.getSalary);
          employee.setRank(employeeWithMetaData.getRank());
          employee.setBusinessTitle(employeeWithMetaData.getBusinessTitle());
      }

      return employee;
  }
}      
public类{
公共void main(字符串[]参数){
...
//将csv数据加载到地图格式的一些自定义方法
MetadataLoader=新的MetadataLoader(“pathToData.csv”);
Map metadataHashMap=loader.getMetadataMap(employeeEnrichmentData);
...
//浓缩
SingleOutputStreamOperator>enrichedStream=rawStream
.map(新映射MetadataToEmployees(metadataHashMap))
.name(“使用员工元数据进行充实”);
//一些水槽操作
...
}
}  
最后一个类MapMetadataToEmployees实现了MapFunction,可序列化{
私有映射元数据映射;
公共映射MetadataToEmployees(映射metaDataMap){
this.metaDataMap=metaDataMap;
}
@凌驾
公共员工地图(员工){
if(metaDataMap.containsKey(employee.getId())){
Employee employeeWithMetaData=metaDataMap.get(Employee.getId());
employee.setSalary(employeeWithMetaData.getSalary);
setRank(employeeWithMetaData.getRank());
employee.setBusinessTitle(employeeWithMetaData.getBusinessTitle());
}
返回员工;
}
}      

看起来不错,不过我有两个问题:1。Flink支持并行性。如果流在多台机器上运行,会发生什么情况?你的地图会存在于每个Flink worker的内存中吗?2.当您希望更新CSV文件并重新加载该数据(但在MetadataLoader工作时不会错过流中的消息)时会发生什么情况。这方面有最佳实践吗?谢谢。根据1:MapMetadataToEmployees的构造函数由一个
metaDataMap
实例调用。因此,是的,这正是将要发生的事情。因此,是的,
metaDataMap
将驻留在每个工作者的内存中,因为每个工作者使用的
MapMetadataToEmployees
的每个实例都是用它实例化的(《代码>metaDataMap)。2现在要复杂得多。这个问题的答案与模型服务的情况非常相似。请看这里的翻转:。嗯
public MainClass {
  public void main(String[] args) {
    ...
    // Some custom way of loading the csv data into a Map<POJO> format
    MetadataLoader loader = new MetadataLoader("pathToData.csv");
    Map<Employee> metadataHashMap = loader.getMetadataMap(employeeEnrichmentData);
    ...

    // Enrichment
    SingleOutputStreamOperator<Employee>> enrichedStream = rawStream
            .map(new MapMetadataToEmployees(metadataHashMap))
            .name("Enrich: with Employee Metadata");

    // Some sink opeartion
    ...

  }
}  

final class MapMetadataToEmployees implements MapFunction<Employee, Employee>, Serializable {

  private Map<Employee> metaDataMap;

  public MapMetadataToEmployees(Map<String, Employee> metaDataMap) {
      this.metaDataMap = metaDataMap;
  }

  @Override
  public Employee map(Employee employee) {

      if (metaDataMap.containsKey(employee.getId())) {

          Employee employeeWithMetaData = metaDataMap.get(employee.getId());

          employee.setSalary(employeeWithMetaData.getSalary);
          employee.setRank(employeeWithMetaData.getRank());
          employee.setBusinessTitle(employeeWithMetaData.getBusinessTitle());
      }

      return employee;
  }
}