一堆驾驶汽车产生痕迹(有序位置序列)
car_id order_id position
car1 0 (x0,y0)
car1 1 (x1,y1)
car1 2 (x2,y2)
car2 0 (x0,y0)
car2 1 (x1,y1)
car2 2 (x2,y2)
car2 3 (x3,y3)
car2 4 (x4,y4)
car3 0 (x0,y0)
我想计算汽车驱动的距离(路径长度)。
核心是,我需要逐行处理所有记录。如果 前一行的car_id与我需要的当前行相同 计算到前一个位置的距离并将其添加到聚合位置 值。如果前一行的car_id与当前行不同 然后我需要输出前一个car_id的聚合,并初始化 当前car_id的总和为零。
hadoop程序的架构应该如何?是否有可能 以下是:
解决方案(1):
(a)每个映射器计算跟踪的聚合距离(每个物理 块)
(b)每个映射器在跟踪分裂的情况下进一步聚合距离 在多个块和节点之间
评论:此解决方案需要知道我是否在最后一条记录(行) 块。这些信息是否可用?
解决方案(2)
(a)映射器逐行读取数据(不进行计算)并发送 基于car_id的数据到reducer。
(b)Reducer根据order_id对各个car_id的数据进行排序, 计算距离,并汇总它们
评论:由于映射器的懒惰导致的高网络负载
解决方案(3)
(a)实现自定义阅读器以读取将逻辑记录定义为整体 一辆车的痕迹
(b)每个映射器计算距离和聚合
(c)并不真正需要reducer,因为映射器完成了所有操作
注释:由于需要将整个跟踪加载到main中,因此主内存成本较高 记忆(虽然一次只使用两行)。
答案 0 :(得分:2)
我会选择Solution(2),因为它是最干净的实现和重用。
您当然希望根据car_id AND order_id进行排序,这样您就可以动态计算距离,而无需将它们全部加载到内存中。
您对高网络使用率的关注是有效的,但是,您可以在合并器中预先聚合距离。
看起来如何,让我们采取一些伪代码:
Mapper:
foreach record:
emit((car_id, order_id), (x,y))
Combiner:
if(prev_order_id + 1 == order_id): // subsequent measures
// compute distance and emit that as the last possible order
emit ((car_id, MAX_VALUE), distance(prev, cur))
else:
// send to the reducer, since it is probably crossing block boundaries
emit((car_id, order_id), (x,y))
减速机有两个主要部分:
您可以通过网络使用POV获得最佳功能。
从软件POV中,更好地使用Spark-你的逻辑将是五行,而不是三行类文件中的100行。
对于您的其他问题:
此解决方案需要知道我是否在最后一条记录(行) 块。这些信息是否可用?
Hadoop只保证在阅读时不会分割记录,很可能你的记录已经触及下面的两个不同的块。找到它的方法基本上是重写输入格式,使这些信息可供映射器使用,甚至更好 - 在分割块时考虑逻辑。