我正在用Flink编写一个项目,该项目涉及在批处理数据上流式传输一组查询点,并执行完整的顺序扫描以找到最近的邻居。对单个Float值的简单排序操作应该违反常规合同错误。主要方法定义为:
object StreamingDeCP{
var points: Vector[Point] = _
def main(args: Array[String]): Unit = {
val queryPointsVec: Vector[Point] = ... // Read from file
val pointsVec: Vector[Point] = ... // Read from file
val streamEnv: StreamExecutionEnvironment =
StreamExecutionEnvironment.getExecutionEnvironment
val queryPoints = streamEnv.fromCollection(queryPointsVec)
points = pointsVec
queryPoints.map(new StreamingSequentialScan)
streamEnv.execute("StreamingDeCP")
}
final class StreamingSequentialScan
extends MapFunction[Point, (Point, Vector[Point])] {
def map(queryPoint: Point): (Point, Vector[Point]) = {
val nn = points
.map{ _.eucDist(queryPoint) }
.sorted
(queryPoint, nn)
}
}
}
Point
类和伴随对象是:
case class Point(pointID: Long,
descriptor: Vector[Float]) extends Serializable {
var distance: Float = Float.MaxValue
def eucDist(that: Point): Point = {
// Simple arithmetic to calculate and set the distance variable
}
}
object Point{
implicit def orderByDistance[A <: Point]: Ordering[A] =
Ordering.by(_.distance)
}
这里有一些关于我尝试过的事情的注释,以便查明原因:
distance
值都在Float.MaxValue和Float.MinValue之间,并且不存在负零值distance
变量(我的用例允许这样做,但我想我会检查以防万一)Point
上添加了显式排序,而不是使用隐式pointID
而不是distance
进行排序,这虽然有效,但对于该问题的上下文没有用。我还注意到,执行相同的代码并不总是能够可靠地重现该错误。我正在以一种完全确定性的方式阅读Vector[Points]
,因此导致此行为的唯一可能原因必须是Flink调度程序或排序方法中的某些状态计算。
同一主题上的其他帖子似乎在自定义比较器中涉及一种遗漏的情况,但这应该是对单个Float值的简单排序操作,因此我不知道是什么原因引起的。
答案 0 :(得分:1)
我对Flink并不熟悉,但是我没有任何理由假设它会以顺序单线程的方式执行每个embarrassingly parallel MapFunction
任务。
由于您的Point
包含var
,并且这些var
在map
的{{1}}方法中发生了突变,因此代码必须以“以并行方式MapFunction
执行MapFunction
时,“比较方法违反了其一般约定” 例外。
为避免在!= 1
函数内部产生任何副作用,可以按如下所示修改代码:
map
中删除所有var
,将main
设为不变的points
。val
中删除任何类型的var
实现方法
Point
可以简单地计算到另一个点的距离(不改变任何东西)。
使用def eucDist(other: Point): Double
:
sortBy
或者,如果您希望避免在排序过程中多次重新计算欧几里得距离,请预先计算一次距离,然后再将距离扔掉:
val nn = points.sortBy(_.eucDist(queryPoint))