针对Hazelcast Jet中map中的有限项,将来自流源的单个项与来自map的有限项进行MapReduce

针对Hazelcast Jet中map中的有限项,将来自流源的单个项与来自map的有限项进行MapReduce,hazelcast,hazelcast-jet,Hazelcast,Hazelcast Jet,作为Hazelcast Jet的新手,我尝试构建一个设置,其中来自无限源的单个项目(即用户请求的地图日志)被映射到一个(可能不断变化的)巨大的参考项目地图上 具体地说,对于这个例子,我想确定向量映射(参考)中最小欧几里德距离的向量ID(读取:float[]),给定使用的定义输入向量(查询) 如果在一台机器上简单地实现,这将遍历引用的映射项,并确定每个引用到查询的欧几里德距离,同时保持k-最小匹配,其中输入来自用户请求(HTTPPOST,按钮单击等)计算完成后,结果集立即可用 我最近的做法是:

作为Hazelcast Jet的新手,我尝试构建一个设置,其中来自无限源的单个项目(即用户请求的地图日志)被映射到一个(可能不断变化的)巨大的参考项目地图上

具体地说,对于这个例子,我想确定向量映射(参考)中最小欧几里德距离的向量ID(读取:
float[]
),给定使用的定义输入向量(查询)

如果在一台机器上简单地实现,这将遍历引用的映射项,并确定每个引用到查询的欧几里德距离,同时保持k-最小匹配,其中输入来自用户请求(HTTP
POST
,按钮单击等)计算完成后,结果集立即可用

我最近的做法是:

  • 在地图日志上侦听请求
  • .distributed().broadcast()
    映射作业的请求
  • 让映射作业获取参考向量的
    .localKeySet()
  • 发射k最小向量的ID(按欧几里德距离)
  • 通过
    .partitioned(item->item.requestId)
    分区减少/收集单个节点上的结果
  • 将结果存储到客户端具有密钥侦听器的映射中
从概念上讲,这里的每个查询都是一个大小为
1
的批,我实际上是在处理这些批。但是,我在让映射器和还原器知道批处理何时完成,以便收集器知道批处理何时完成(以便它们可以发出最终结果)方面遇到了巨大的困难

我尝试使用带有真时间戳和假时间戳的水印(通过
AtomicLong
实例自动获得)并从
tryProcessWm
函数发出,但是,这似乎是一个非常脆弱的解决方案,因为一些事件被丢弃。我还需要确保没有两个请求是交错的(即在请求ID上使用分区),但同时让映射程序在所有节点上运行

我将如何处理此任务


编辑#1:

现在,我的地图绘制程序如下所示:

私有静态类EuclideAndInstanceApp扩展了AbstractProcessor{
私有IMap参考向量;
最终计分比较器=新计分比较器();
@凌驾
受保护的void init(@Nonnull上下文)引发异常{
this.referenceVectors=context.jetInstance().getMap(REFERENCE\u VECTOR\u MAP\u NAME);
super.init(上下文);
}
@凌驾
受保护的布尔色进程0(@Nonnull对象项){
最终Tuple3查询=(Tuple3)项;
final long requestId=query.f0();
最终长时间戳=query.f1();
最终浮点[]queryVector=query.f2();
最终树集缓冲区=新树集(比较器);
for(长向量键:referenceVectors.localKeySet()){
float[]referenceVector=referenceVectors.get(vectorKey);
浮动距离=0.0f;
对于(int i=0;i=0){
继续;
}
//否则,我们将在添加新条目后删除最大条目。
缓冲区。添加(分数);
buffer.pollLast();
}
返回tryEmit(Tuple3.Tuple3(requestId,timestamp,buffer.toArray());
}
私有静态类ScoreComparator实现Comparator{
@凌驾
公共整数比较(tuple2a,tuple2b){
返回Float.compare(a.f1(),b.f1());
}
}
}
减速机实际上是在复制(当然,减去向量计算)


编辑#2:

这是DAG设置。当前,当并发请求超过几个时,它会失败。由于水印,大多数项目都会被删除

DAG DAG=new DAG();
Vertex sourceStream=dag.newVertex(“源”,
SourceProcessors.streamMapP(查询向量映射名称,
e->e.getType()==EntryEventType.ADDED | | e.getType()==EntryEventType.UPDATED,
e->Tuple2.Tuple2(e.getKey(),e.getNewValue()),true);
//使用原子长创建时间戳的simple map()
顶点addTimestamps=dag.newVertex(“addTimestamps”,AddTimestampMapP::new);
//上面显示的类。
顶点映射=dag.newVertex(“映射”,欧几里德和斯坦应用程序::新建);
Vertex insertWatermarks=dag.newVertex(“insertWatermarks”,
insertWatermarksP((tuple3t)->t.f1(),带有fixedlag(0),emitByMinStep(1));
顶点合并=dag.newVertex(“合并”,CombineP::新建);
//删除时间戳的简单映射()
顶点removeTimestamps=dag.newVertex(“removeTimestamps”,RemoveTimestampMapP::new);
//使用此处的列表进行测试。
顶点sink=dag.newVertex(“sink”,SinkProcessors.writeList(sink_NAME));
dag.edge(介于(sourceStream、addTimestamps)之间)
.edge(介于(addTimestamps、map.localParallelism(1))之间)
.广播(
.distributed())
.edge(介于(映射、插入水印).isolated()之间)
.edge(介于(插入水印、合并.localParallelism(1))之间)
.已分发()
.partitioned((Tuple2项)->item.f0()
.边缘(在(合并、移除)之间)
.partitioned((Tuple3项)->item.f0()
.edge(在(除去时间戳、水槽、局部平行度(1))之间);

编辑#3: