
# Spark DAG设计规范说明
#### 操作场景
合理的设计程序结构，可以优化执行效率。在程序编写过程中要尽量减少shuffle操作，合并窄依赖操作。
#### 操作步骤
以"同行车判断"例子讲解DAG设计的思路。
- **数据格式：**通过收费站时间、车牌号、收费站编号......
- **逻辑：** 以下两种情况下判定这两辆车是同行车：
  - 如果两辆车都通过相同序列的收费站，
  
  - 通过同一收费站之间的时间差小于一个特定的值。
   
该例子有两种实现模式，其中实现1的逻辑如[图1]所示，实现2的逻辑如[图2]所示。
图1实现1逻辑   
![](https://support.huaweicloud.com/cmpntguide-mrs/zh-cn_image_0000001234019578.png)
实现1的逻辑说明 ：
1. 根据车牌号聚合该车通过的所有收费站并排序，处理后数据如下： 车牌号1，\[（通过时间，收费站3），（通过时间，收费站2），（通过时间，收费站4），（通过时间，收费站5）\]
   
2. 标识该收费站是这辆车通过的第几个收费站。 （收费站3，（车牌号1，通过时间，通过的第1个收费站））
   （收费站2，（车牌号1，通过时间，通过的第2个收费站））
   （收费站4，（车牌号1，通过时间，通过的第3个收费站））
   （收费站5，（车牌号1，通过时间，通过的第4个收费站））
   
3. 根据收费站聚合数据。 收费站1，\[（车牌号1，通过时间，通过的第1个收费站），（车牌号2，通过时间，通过的第5个收费站），（车牌号3，通过时间，通过的第2个收费站）\]
   
4. 判断两辆车通过该收费站的时间差是否满足同行车的要求，如果满足则取出这两辆车。 （车牌号1，车牌号2），（通过的第1个收费站，通过的第5个收费站）
   （车牌号1，车牌号3），（通过的第1个收费站，通过的第2个收费站）
   
5. 根据通过相同收费站的两辆车的车牌号聚合数据，如下： （车牌号1，车牌号2），\[（通过的第1个收费站，通过的第5个收费站），（通过的第2个收费站，通过的第6个收费站），（通过的第1个收费站，通过的第7个收费站），（通过的第3个收费站，通过的第8个收费站）\]
   
6. 如果车牌号1和车牌号2通过相同收费站是顺序排列的（比如收费站3、4、5是车牌1通过的第1、2、3个收费站，是车牌2通过的第6、7、8个收费站）且数量大于同行车要求的数量则这两辆车是同行车。
实现1逻辑的缺点 ：
- 逻辑复杂
- 实现过程中shuffle操作过多，对性能影响较大。
图2实现2逻辑   
![](https://support.huaweicloud.com/cmpntguide-mrs/zh-cn_image_0000001233707378.png)
实现2的逻辑说明 ：
1. 根据车牌号聚合该车通过的所有收费站并排序，处理后数据如下： 车牌号1，\[（通过时间，收费站3），（通过时间，收费站2），（通过时间，收费站4），（通过时间，收费站5）\]
   
2. 根据同行车要通过的收费站数量（例子里为3）分段该车通过的收费站序列，如上面的数据被分解成 ： 收费站3-\>收费站2-\>收费站4， （车牌号1，\[收费站3时间，收费站2时间，收费站4时间\]）
   收费站2-\>收费站4-\>收费站5， （车牌号1，\[收费站2时间，收费站4时间，收费站5时间\]）
   
3. 把通过相同收费站序列的车辆聚合，如下： 收费站3-\>收费站2-\>收费站4，\[（车牌号1，\[收费站3时间，收费站2时间，收费站4时间\]），（车牌号2，\[收费站3时间，收费站2时间，收费站4时间\]），（车牌号3，\[收费站3时间，收费站2时间，收费站4时间\]）\]
   
4. 判断通过相同序列收费站的车辆通过相同收费站的时间差是不是满足同行车的要求，如果满足则说明是同行车。
实现2的优点如下：
- 简化了实现逻辑。
- 减少了一个groupByKey，也就减少了一次shuffle操作，提升了性能。
 
