├── README.md
├── README_20200423.md
├── README_JAVA.md
├── eleme_round2_dispatch_master_20200420
├── .gitignore
├── Dockerfile
├── DockerfileJudge
├── Makefile
├── README.md
├── deploy.png
├── dispatch-api
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── dispatch
│ │ │ ├── api
│ │ │ ├── DispatchClient.java
│ │ │ ├── dto
│ │ │ │ ├── ActionNode.java
│ │ │ │ ├── Courier.java
│ │ │ │ ├── CourierPlan.java
│ │ │ │ ├── DispatchRequest.java
│ │ │ │ ├── DispatchSolution.java
│ │ │ │ ├── Location.java
│ │ │ │ ├── Order.java
│ │ │ │ └── Response.java
│ │ │ ├── exception
│ │ │ │ └── DispatchException.java
│ │ │ └── impl
│ │ │ │ ├── HttpClientManager.java
│ │ │ │ └── HttpDispatchClientImpl.java
│ │ │ └── judge
│ │ │ ├── CourierRecord.java
│ │ │ ├── DispatchContext.java
│ │ │ ├── DispatchJudge.java
│ │ │ ├── DispatchLog.java
│ │ │ ├── IllegalMsg.java
│ │ │ ├── JudgeUtil.java
│ │ │ ├── OrderRecord.java
│ │ │ ├── RawData.java
│ │ │ ├── Score.java
│ │ │ └── SequentialJudge.java
│ │ └── test
│ │ └── java
│ │ └── dispatch
│ │ └── api
│ │ └── impl
│ │ └── HttpDispatchClientImplTest.java
├── dispatch-demo-go
│ ├── dispatch
│ │ ├── cmd.go
│ │ ├── dispatcher.go
│ │ ├── dto.go
│ │ ├── log.go
│ │ └── server.go
│ ├── go.mod
│ └── main.go
├── dispatch-demo-py
│ ├── app.py
│ ├── demo
│ │ ├── __init__.py
│ │ └── dto.py
│ └── setup.py
├── dispatch-demo
│ ├── .gitignore
│ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ ├── src
│ │ ├── main
│ │ │ ├── .DS_Store
│ │ │ ├── java
│ │ │ │ ├── .DS_Store
│ │ │ │ └── dispatch
│ │ │ │ │ ├── .DS_Store
│ │ │ │ │ └── demo
│ │ │ │ │ ├── DispatchDemoApplication.java
│ │ │ │ │ ├── controller
│ │ │ │ │ └── DispatchController.java
│ │ │ │ │ ├── core
│ │ │ │ │ ├── DispatchService.java
│ │ │ │ │ ├── context
│ │ │ │ │ │ └── DispatchContext.java
│ │ │ │ │ ├── pool
│ │ │ │ │ │ ├── CourierPool.java
│ │ │ │ │ │ └── OrderPool.java
│ │ │ │ │ ├── route
│ │ │ │ │ │ ├── Planner.java
│ │ │ │ │ │ └── TailAppendPlan.java
│ │ │ │ │ └── solver
│ │ │ │ │ │ └── BaseSolver.java
│ │ │ │ │ ├── dto
│ │ │ │ │ ├── ActionNode.java
│ │ │ │ │ ├── Courier.java
│ │ │ │ │ ├── CourierPlan.java
│ │ │ │ │ ├── DispatchRequest.java
│ │ │ │ │ ├── DispatchSolution.java
│ │ │ │ │ ├── Location.java
│ │ │ │ │ ├── Order.java
│ │ │ │ │ └── Response.java
│ │ │ │ │ └── utils
│ │ │ │ │ └── DistanceUtils.java
│ │ │ └── resources
│ │ │ │ └── application.properties
│ │ └── test
│ │ │ └── java
│ │ │ └── dispatch
│ │ │ └── dispatchdemo
│ │ │ └── DispatchDemoApplicationTests.java
│ └── target
│ │ └── dispatch-demo.jar
├── open_test
│ ├── 680507
│ │ ├── courier
│ │ └── order
│ ├── 725011
│ │ ├── courier
│ │ └── order
│ └── 730221
│ │ ├── courier
│ │ └── order
├── pom.xml
├── run.sh
└── start_judge.sh
├── eleme_round2_dispatch_master_20200421
├── .gitignore
├── Dockerfile
├── DockerfileJ
├── Makefile
├── README.md
├── base-dockerfile
│ ├── java-dockerfile
│ └── python-dockerfile
├── deploy.png
├── dispatch-api
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── dispatch
│ │ │ ├── api
│ │ │ ├── DispatchClient.java
│ │ │ ├── dto
│ │ │ │ ├── ActionNode.java
│ │ │ │ ├── Courier.java
│ │ │ │ ├── CourierPlan.java
│ │ │ │ ├── DispatchRequest.java
│ │ │ │ ├── DispatchSolution.java
│ │ │ │ ├── Location.java
│ │ │ │ ├── Order.java
│ │ │ │ └── Response.java
│ │ │ ├── exception
│ │ │ │ └── DispatchException.java
│ │ │ └── impl
│ │ │ │ ├── HttpClientManager.java
│ │ │ │ └── HttpDispatchClientImpl.java
│ │ │ └── judge
│ │ │ ├── CourierRecord.java
│ │ │ ├── DispatchContext.java
│ │ │ ├── DispatchJudge.java
│ │ │ ├── DispatchLog.java
│ │ │ ├── IllegalMsg.java
│ │ │ ├── JudgeUtil.java
│ │ │ ├── OrderRecord.java
│ │ │ ├── RawData.java
│ │ │ ├── Score.java
│ │ │ └── SequentialJudge.java
│ │ └── test
│ │ └── java
│ │ └── dispatch
│ │ └── api
│ │ └── impl
│ │ └── HttpDispatchClientImplTest.java
├── dispatch-demo-go
│ ├── dispatch
│ │ ├── cmd.go
│ │ ├── dispatcher.go
│ │ ├── dto.go
│ │ ├── log.go
│ │ └── server.go
│ ├── go.mod
│ └── main.go
├── dispatch-demo-py
│ ├── app.py
│ ├── demo
│ │ ├── __init__.py
│ │ ├── context.py
│ │ ├── dto.py
│ │ ├── plan.py
│ │ ├── pool.py
│ │ ├── service.py
│ │ ├── solver.py
│ │ └── util.py
│ ├── dispatch-judge-jar-with-dependencies.jar
│ ├── local_judge.py
│ ├── open_test
│ │ ├── 680507
│ │ │ ├── courier
│ │ │ └── order
│ │ ├── 725011
│ │ │ ├── courier
│ │ │ └── order
│ │ └── 730221
│ │ │ ├── courier
│ │ │ └── order
│ ├── open_test_small
│ │ └── 680507
│ │ │ ├── courier
│ │ │ └── order
│ └── setup.py
├── dispatch-demo
│ ├── .gitignore
│ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── dispatch
│ │ │ │ └── demo
│ │ │ │ ├── DispatchDemoApplication.java
│ │ │ │ ├── controller
│ │ │ │ └── DispatchController.java
│ │ │ │ ├── core
│ │ │ │ ├── DispatchService.java
│ │ │ │ ├── context
│ │ │ │ │ └── DispatchContext.java
│ │ │ │ ├── pool
│ │ │ │ │ ├── CourierPool.java
│ │ │ │ │ └── OrderPool.java
│ │ │ │ ├── route
│ │ │ │ │ ├── Planner.java
│ │ │ │ │ └── TailAppendPlan.java
│ │ │ │ └── solver
│ │ │ │ │ └── BaseSolver.java
│ │ │ │ ├── dto
│ │ │ │ ├── ActionNode.java
│ │ │ │ ├── Courier.java
│ │ │ │ ├── CourierPlan.java
│ │ │ │ ├── DispatchRequest.java
│ │ │ │ ├── DispatchSolution.java
│ │ │ │ ├── Location.java
│ │ │ │ ├── Order.java
│ │ │ │ └── Response.java
│ │ │ │ └── utils
│ │ │ │ └── DistanceUtils.java
│ │ └── resources
│ │ │ └── application.properties
│ │ └── test
│ │ └── java
│ │ └── dispatch
│ │ └── dispatchdemo
│ │ └── DispatchDemoApplicationTests.java
├── pom.xml
├── run.sh
├── run_py.sh
├── run_py_dev.sh
└── start_judge.sh
└── 复赛 Baseline 流程部署分享
├── Screen Shot 2020-04-21 at 6.06.29 AM.png
├── Screen Shot 2020-04-21 at 6.55.34 AM.png
└── deploy.png
/README.md:
--------------------------------------------------------------------------------
1 | # 复赛 Baseline - Python 移植版本
2 | https://tianchi.aliyun.com/forum/postDetail?spm=5176.12586969.1002.3.1f7f48c8KyMyxa&postId=104509
3 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777)
4 |
5 | 智慧物流:新冠期间饿了么骑士行为预估 复赛
6 | 复赛 Baseline - Python 移植版本 **已经获得线上baseline 结果**
7 |
8 | ## 版本更新
9 |
10 | **23/04/2020 -2**
11 |
12 | 实现docker化配置,镜像构建以及达到官方Java线上baseline结果
13 |
14 | **23/04/2020**
15 |
16 | - 修复`local_judge.py` 调用 import module 以及异常输出问题,实现本地一体化评测
17 | - 修复Demo后台挂起时异常输出问题
18 |
19 | 旧版 Readme 见同目录
20 |
21 | ## 前情提要
22 |
23 | **23/04/2020-2**
24 |
25 | 分析发现按照之前配置,返回code127报错。本地进入docker镜像实验,猜测可能官方评测包位置差异,导致java命令没找到,抛出127错误。通过反向分析 java版本基础镜像,Dockerfile直接对环境安装 jdk 13, 线上实验达到baseline结果。全链路畅通。
26 |
27 | **23/04/2020**
28 |
29 | 更新修复了调试时候配置, 镜像生成配置,由于我在国外镜像上传太慢,有jar包存在比较大还不能走自动构建,镜像的准确性有待继续测试
30 |
31 | **22/04/2020**
32 |
33 | 其实在准备考试了,但是有时候想起这个题目,遗憾没有 python 版本进行实验。于是抽出一天进行了移植。我本身不是 python 企业级开发,之前 python 也仅限于写 pytorch,基本上是官方 Java 版本的移植。我已经本地测试通了,但是没有镜像上传。不保证代码质量。(json之间传值其实花费我挺久。。)
34 |
35 | ## 路径
36 |
37 | demo: `eleme_round2_dispatch_master_20200421/dispatch-demo-py`
38 |
39 | demo 挂起(非后台版本,不用杀进程)`eleme_round2_dispatch_master_20200421/run_py_dev.sh`
40 |
41 | demo 挂起(后台版本)`eleme_round2_dispatch_master_20200421/run_py.sh`
42 |
43 | 评测数据:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test`
44 |
45 | 评测数据(少量,我debug用的)`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small`
46 |
47 | 本地一体评测(需要JDK环境), `local_judge.py`
48 |
49 | 评测 jar 包:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar`
50 |
51 | ## 流程
52 |
53 | ### 本地调用
54 |
55 | #### Dev 推荐流程
56 |
57 | 启动 Demo
58 |
59 | ```shell
60 | cd eleme_round2_dispatch_master_20200421
61 | bash run_py_dev.sh
62 | ```
63 |
64 | 启动评测
65 |
66 | ```shell
67 | cd eleme_round2_dispatch_master_20200421
68 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/
69 | ```
70 |
71 | 测试完,关闭进程
72 |
73 | #### 一体化评测流程
74 |
75 | 直接调用 local_judge.py
76 |
77 | ```shell
78 | cd eleme_round2_dispatch_master_20200421/dispatch-demo-py
79 | python local_judge.py
80 | ```
81 |
82 | #### 使用镜像
83 |
84 | 如果之前已经构建镜像了,也可以使用镜像
85 |
86 | ```
87 | docker run -t -i registry.cn-shenzhen.aliyuncs.com/${name}:${tag} /bin/bash
88 | ```
89 |
90 | 进入容器,下载本项目
91 |
92 | ```
93 | git clone https://github.com/NorwinYu/eleme_round2_baseline_py
94 | ```
95 |
96 | 启动镜像里之前复制进去的run.sh
97 |
98 | ```
99 | /run.sh
100 | ```
101 |
102 | ctrl c 关闭,但是还在后台运行。打开评测包
103 |
104 | ```
105 | cd eleme_round2_dispatch_master_20200421
106 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/
107 | ```
108 |
109 | 测试完成
110 |
111 | exit 退出镜像
112 |
113 | ### 线上
114 |
115 | 之前线上返回一直报错127,所以猜测是java环境问题,之前那种方法可能会导致 java命令找不到(仅仅猜测)。因为不知道官方评测包路径,曲线救国,直接逆向查看 java 基础镜像的构建过程,将部分java环境构建copy到本项目的构建中,实现 python java 环境同时存在
116 |
117 | 逆向代码
118 |
119 | ```
120 | docker history --no-trunc=true registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 > java-dockerfile
121 | docker history --no-trunc=true registry.cn-shanghai.aliyuncs.com/tcc-public/python:3 > python-dockerfile
122 | ref:http://dockone.io/article/527
123 | ```
124 |
125 | java、python 基础镜像逆向结果在 `eleme_round2_dispatch_master_20200421/base-dockerfile` 下
126 |
127 | 因此 对 `Dockerfile` 进行了更新
128 |
129 | #### 镜像打包
130 |
131 | - 下载 https://download.java.net/java/GA/jdk13.0.2/d4173c853231432d94f001e99d882ca7/8/GPL/openjdk-13.0.2_linux-x64_bin.tar.gz
132 |
133 | - 重命名为 `openjdk.tgz`
134 |
135 | - 把 jdk 包放到 `eleme_round2_dispatch_master_20200421` 目录下
136 |
137 | - 没有登录的先登录
138 |
139 | ```shell
140 | docker build -t registry.cn-shenzhen.aliyuncs.com/${name}:${tag} .
141 | docker push registry.cn-shenzhen.aliyuncs.com/${name}:${tag}
142 | ```
143 |
144 | #### 线上测试
145 |
146 | 已到达我之前 用 官方 Java 版本的结果,移植结束。
147 |
--------------------------------------------------------------------------------
/README_20200423.md:
--------------------------------------------------------------------------------
1 | # 复赛 Baseline - Python 移植版本
2 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777)
3 |
4 | 智慧物流:新冠期间饿了么骑士行为预估 复赛
5 | 复赛 Baseline - Python 移植版本
6 |
7 | ## 前情提要
8 |
9 | 其实在准备考试了,但是有时候想起这个题目,遗憾没有 python 版本进行实验。于是抽出一天进行了移植。我本身不是 python 企业级开发,之前 python 也仅限于写 pytorch,基本上是官方 Java 版本的移植。我已经本地测试通了,但是没有镜像上传。不保证代码质量。(json之间传值其实花费我挺久。。)
10 |
11 | ## 路径
12 |
13 | demo: `eleme_round2_dispatch_master_20200421/dispatch-demo-py`
14 |
15 | 评测包:``eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar`
16 |
17 | demo 挂起(非后台版本,不用杀进程)`eleme_round2_dispatch_master_20200421/run_py_dev.sh`
18 |
19 | 评测数据:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test`
20 |
21 | 评测数据(少量,我debug用的)`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small`
22 |
23 | 我用的 Java 进行评测的, `local_judge.py` 没调整,实在不想看了,移植太费精力
24 |
25 | ## 流程
26 |
27 | 启动 Demo
28 |
29 | ```shell
30 | cd eleme_round2_dispatch_master_20200421
31 | bash run_py_dev.sh
32 | ```
33 |
34 | 启动评测
35 |
36 | ```shell
37 | cd eleme_round2_dispatch_master_20200421
38 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/
39 | ```
40 |
41 | 测试完,关闭进程
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/README_JAVA.md:
--------------------------------------------------------------------------------
1 | # 复赛 Baseline 流程部署分享
2 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777)
3 |
4 | 智慧物流:新冠期间饿了么骑士行为预估 复赛
5 | Baseline 流程部署分享
6 |
7 | ## 官方源码更新 4.21版本
8 | * 我起来发现官方源码更新了,需要官网重新下载,相关描述是基于 4.20版本,可能有出入
9 | * 由于我没找到更新日志,错过直播,我用 git 比较了两个版本源码,详情见https://github.com/NorwinYu/eleme_round2_baseline/commit/f7ad6ea50cd9fcdcefcd650cf5d940896589d09e
10 | * 根据比对,主要更新是 py 版本的评测程序的联动,docker化,优化交互,更新少量描述和配置,具体如下,个人见解,具体见官方源码
11 | * 更新 解决了我之前提到的 run.sh 替换问题
12 | * 更新 增加 DockerfileP,应该是用于python demo docker 化
13 | * 更新 README.md 相关说明
14 | * 更新了 Java 里的 HttpDispatchClientImplTest.java 这个影响不大,测试文件
15 | * 更新了 dispatch-demo-py/app.py
16 | * 更新了 dispatch-demo-py/demo/dto.py
17 | * 把 dispatch-judge-jar-with-dependencies.jar open_test 数据 放入了 py 版本中
18 | * 更新了 DispatchController.java
19 | * 更新了 run.sh 配置
20 |
21 | ## 数据下载
22 | * 下载 官方 Baseline 源码 `eleme_round2_dispatch_master_20200420.zip` , 解压在目录
23 | `eleme_round2_dispatch_master_20200420` 下
24 | * 下载 官方 线下测试数据池 `eleme_round2_open_test_20200420.zip` , 解压在目录
25 | `eleme_round2_dispatch_master_20200420/open_test` 下
26 | * 官方 Baseline 并没有对数据进行挖掘,可供挖掘历史订单数据可于 比赛页面下载
27 | `eleme_round2_order_history_20200419.zip`
28 |
29 | ## 结构剖析
30 | 
31 | 上图为官方给的交互时序图。在 `eleme_round2_dispatch_master_20200420` 中, 也给了一个 POD 示例图。
32 | 
33 |
34 | **Module说明 (来自官方 Readme)**
35 | dispatch-api 官方评测程序,Java DTO等
36 | dispatch-demo Java版本的Http Server框架和Demo实现,选手可以任意实现,仅做参考
37 | dispatch-py python版本简单Http Server框架,没有实现逻辑,选手可以任意修改
38 | dispatch-go go版本简单Http Server框架,没有实现逻辑,选手可以任意修改
39 |
40 | * 也就是说,官方给了 Java (SpringBoot), go, py (flask) 版本的Http Server框架,但是只实现了 Java 的 Demo实现。因此我昨天先尝试了打通 Java 版本的提交。
41 |
42 | * `选手Restful Sever` = `eleme_round2_dispatch_master_20200420/dispatch-demo` or `eleme_round2_dispatch_master_20200420/dispatch-py` or `eleme_round2_dispatch_master_20200420/dispatch-go` or `S调度程序(选手) + Http通信`
43 | * `评测程序 Http Client` = `eleme_round2_dispatch_master_20200420/dispatch-api` or `M发单器 + J评测程序 + Http通信 + 文件存储读取`
44 | * `D文件存储` =`eleme_round2_dispatch_master_20200420/open_test`
45 | * 通俗来讲,评测程序就好像一个模拟的环境,模拟生成状态下实时订单需求和骑手运力。选手Restful Sever就好像生成系统线上程序,一个智能体,对于所收到的信息,进行智能配单的决策。
46 | ## Baseline 流程部署
47 | 我尝试写这篇分享的原因是觉得这个提交过程对于非这个生态的开发者跨度有点大,看到群里好多同学都在问相关的(甚至提到了我提交的,其实我就是测试了下 Baseline, 第一次参赛)。我之前是做 Java Web 开发的,现在在学 NLP 相关,希望这篇分享能帮助大家关注算法上,而不是繁琐的配置。由于我目前在国外,上传镜像速度慢,部分步骤我基于我的情况进行了改动。
48 |
49 | 官方有 Readme ,有很多信息,不全部复制了,可以自行查看。以下只是个人见解。
50 |
51 | 我的这次部署尝试是基于 Java 版本, 也就是没有改过代码,本地编译出 jar 包以后,将 jar 包上传 git,然后通过镜像自动构建进行的。
52 |
53 | ### 环境
54 | 所有需要的环境我都安装过了,我这里就列下环境需求,主要是针对 Mac OS 用户。
55 | * Cmake(gcc) 应该可以Homebrew 装
56 | * Java
57 | * Maven 应该可以Homebrew 装
58 | * docker 可以Homebrew 装
59 | * Mac OS
60 | ```
61 | $ brew install docker docker-machine
62 | $ brew cask install virtualbox
63 | -> need password
64 | -> possibly need to address System Preference setting
65 | $ docker-machine create --driver virtualbox default
66 | $ docker-machine env default
67 | $ eval "$(docker-machine env default)"
68 | $ docker run hello-world
69 | $ docker-machine stop default
70 | ```
71 |
72 | https://medium.com/@yutafujii_59175/a-complete-one-by-one-guide-to-install-docker-on-your-mac-os-using-homebrew-e818eb4cfc3
73 | * 可能有遗漏
74 |
75 | ### 本地调试 官方的其中一种方式
76 | `cd eleme_round2_dispatch_master_20200420`
77 | #### 编译
78 | `make build-java`
79 | #### 开一个终端,启动选手 http server
80 | ```
81 | java -jar dispatch-demo/target/dispatch-demo.jar
82 | ```
83 | #### 开另一个终端,启动评测程序,进行评测
84 | ```
85 | java -jar dispatch-api/target/dispatch-judge-jar-with-dependencies.jar `pwd`/open_test/
86 | ```
87 | #### 关闭 选手 http server Ctrl C
88 |
89 | ### 构建镜像并上传
90 | ! 如果大家在国内,可以按照 https://tianchi.aliyun.com/competition/entrance/231759/tab/174 进行部署
91 | ? 我有对 `eleme_round2_dispatch_master_20200420/Dockerfile` 进行更改,把所有 `start.sh` 换成了`run.sh` ,按照说明要求。不过不确定会不会影响,但是如果不改,由于目录下没有 `start.sh`, 会出现问题。
92 | 。 如果有同样在国外的同学,可以参照我的步骤,选择通过代码进行自动构建。
93 | * 自动构建和官方说明类似,只是在创建时候选取通过代码进行自动构建,然后我关联了Github,本来想关联阿里云的代码托管,结果发现 git push 也很慢。
94 | * 自动构建可以设置构建触发规则已经目录,目录一定要设置正确。
95 | 
96 | 图中是我自己的Private 项目,本个分享的话 文件目录是 `/eleme_round2_dispatch_master_20200420/` , 文件名还是 `Dockerfile` , 版本号可以自己设置或者通过触发的参量。如果经常改代码的不如关了 代码变更自动构建镜像 功能,一键构建。建议版本号每次构建进行更改,或者通过触发规则参量传递每次构建更新版本号,这样可以体现镜像的功能。
97 | * 有一点,由于构建需要 jar 包,之前编译完后,需要把 jar git add force, 因为一般是 git ignore
98 |
99 | ```
100 | git add dispatch-demo/target/dispatch-demo.jar -f
101 | git commit -m "Your message"
102 | git push
103 | ```
104 |
105 | * 然后手动开始构建。
106 | * 构建成功在提交界面输入镜像地址和用户密码即可。
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | __pycache__
3 | dispatch-demo/dispatch-demo.iml
4 | dispatch-server/dispatchserver.iml
5 | dispatch-demo-py/dispatch-demo-py.iml
6 | dispatch-demo-py/venv
7 | dispatch-demo-go/dispatch-demo-go.iml
8 | target/
9 | dispatch-api/target
10 | dispatch-demo/target
11 | dispatch-server/target
12 | *.iml
13 | dispatch-demo-go/go.sum
14 |
15 | .DS_Store
16 | dispatch-demo-py/demo/__init__.pyc
17 | dispatch-demo-py/demo/dto.pyc
18 | jdk11.tar.gz
19 | go1.14.1.linux-amd64.tar.gz
20 | dispatch-demo-py/build/
21 | dispatch-demo-go/dispatch-demo-go
22 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
2 | #FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
3 | MAINTAINER annoymous
4 |
5 | WORKDIR /data
6 |
7 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在run.sh中指定$JAVA_HOME
8 | #ADD jdk11.tar.gz /data
9 | # 根据需要打包
10 | #ADD go1.14.1.linux-amd64.tar.gz /data
11 |
12 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话,
13 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令
14 | COPY dispatch-demo/target/dispatch-demo.jar /data/
15 |
16 | # 按照run.sh文件中说明,提供run.sh 脚本
17 | COPY run.sh /data/
18 |
19 | EXPOSE 8080
20 |
21 | RUN chmod u+x /data/run.sh
22 |
23 | CMD ["/bin/bash","/data/run.sh"]
24 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/DockerfileJudge:
--------------------------------------------------------------------------------
1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
2 | MAINTAINER annoymous
3 |
4 | WORKDIR /data
5 |
6 | RUN mkdir -p /data/mock
7 |
8 | # copy 官方评测包到/data目录
9 | COPY dispatch-api/target/dispatch-judge-jar-with-dependencies.jar /data/
10 |
11 | COPY open_test /data/mock/data
12 |
13 | COPY start_judge.sh /data/
14 |
15 | ENV API_SERVER "http://172.17.0.1:8080"
16 | ENV MOCK_DATA_DIR "/data/mock/data"
17 |
18 | RUN chmod u+x start_judge.sh
19 |
20 | CMD ["/bin/bash","start_judge.sh"]
21 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all build build-java build-py build-go build-image build-image-judge clean clean-java clean-py clean-go
2 |
3 | NOW=$(shell date '+%Y-%m-%d_%H:%M:%S')
4 | USER=${shell whoami}
5 |
6 | all: build
7 |
8 | build: build-java build-py build-go build-image build-image-judge
9 |
10 | clean: clean-java clean-py clean-go
11 |
12 | build-java:
13 | echo "start build java" && \
14 | mvn -f pom.xml clean package install -DskipTests && mvn -f dispatch-demo/pom.xml clean package -DskipTests
15 |
16 | build-py:
17 | echo "start build python" && \
18 | cd dispatch-demo-py && python setup.py build
19 |
20 | build-go:
21 | echo "start build go" && \
22 | cd dispatch-demo-go && go build
23 |
24 | build-image:
25 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} .
26 |
27 | build-image-judge:
28 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} -f DockerfileJudge
29 |
30 | clean-java:
31 | mvn clean && mvn clean -f dispatch-demo/pom.xml
32 |
33 | clean-py:
34 | cd dispatch-demo-py && python setup.py clean && rm -rf dispatch_demo_py.egg-info
35 |
36 | clean-go:
37 | cd dispatch-demo-go && go mod tidy && rm -rf dispatch-demo-go
38 |
39 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/deploy.png
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | dispatch
7 | dispatch
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | tianchi-dispatch-api
13 |
14 |
15 |
16 | org.projectlombok
17 | lombok
18 |
19 |
20 |
21 | com.alibaba
22 | fastjson
23 |
24 |
25 | com.google.guava
26 | guava
27 | 28.1-jre
28 |
29 |
30 | org.apache.commons
31 | commons-lang3
32 | 3.9
33 |
34 |
35 | joda-time
36 | joda-time
37 | 2.10.3
38 |
39 |
40 | org.apache.httpcomponents
41 | httpclient
42 | 4.5.12
43 |
44 |
45 | org.slf4j
46 | slf4j-api
47 |
48 |
49 | ch.qos.logback
50 | logback-classic
51 | 1.2.3
52 |
53 |
54 |
55 | ch.qos.logback
56 | logback-core
57 | 1.2.3
58 |
59 |
60 |
61 | junit
62 | junit
63 | 4.12
64 | test
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | org.apache.maven.plugins
73 | maven-assembly-plugin
74 | 2.5.5
75 |
76 |
77 |
78 | dispatch.judge.DispatchJudge
79 |
80 |
81 |
82 | jar-with-dependencies
83 |
84 |
85 |
86 |
87 | make-assembly
88 | package
89 |
90 | single
91 |
92 |
93 |
94 |
95 |
96 | dispatch-judge
97 |
98 |
99 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/DispatchClient.java:
--------------------------------------------------------------------------------
1 | package dispatch.api;
2 |
3 | import dispatch.api.dto.DispatchRequest;
4 | import dispatch.api.dto.DispatchSolution;
5 | import dispatch.api.dto.Response;
6 | import dispatch.api.exception.DispatchException;
7 |
8 | import java.io.Closeable;
9 |
10 | /**
11 | * @author fangyu.fu
12 | */
13 | public interface DispatchClient extends Closeable {
14 | Response dispatch(DispatchRequest dispatchRequest) throws DispatchException;
15 |
16 | Response ping() throws DispatchException;
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/ActionNode.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ActionNode {
7 | private String orderId;
8 | private int actionType;
9 | private long actionTime;
10 | }
11 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Courier.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 |
7 | @Data
8 | @Accessors(chain = true)
9 | public class Courier {
10 | private String areaId;
11 | private String id;
12 | private Location loc;
13 | private Double speed;
14 | private Integer maxLoads;
15 | }
16 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/CourierPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class CourierPlan {
9 | private String courierId;
10 | private List planRoutes;
11 | }
12 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/DispatchRequest.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.util.List;
7 |
8 | @Data
9 | @Accessors(chain = true)
10 | public class DispatchRequest {
11 | private long requestTime;
12 | private String areaId;
13 | private boolean isFirstRound;
14 | private boolean isLastRound;
15 | private List couriers;
16 | private List orders;
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/DispatchSolution.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class DispatchSolution {
9 | private List courierPlans;
10 | }
11 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Location.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Location {
7 | private Double latitude;
8 | private Double longitude;
9 |
10 | public Location(Double latitude, Double longitude) {
11 | this.latitude = latitude;
12 | this.longitude = longitude;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Order.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | @Data
7 | @Accessors(chain = true)
8 | public class Order {
9 | private String areaId;
10 | private String id;
11 | private Location srcLoc;
12 | private Location dstLoc;
13 | private long createTime;
14 | private long promiseDeliverTime;
15 | private long estimatedPrepareCompletedTime;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Response.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | @Data
7 | @NoArgsConstructor
8 | public class Response {
9 |
10 | private int code;
11 | private T result;
12 | private String message;
13 |
14 |
15 | public Response(T result) {
16 | this.code = 200;
17 | this.result = result;
18 | }
19 |
20 | public Response(int code, T result, String message) {
21 | this.code = code;
22 | this.result = result;
23 | this.message = message;
24 | }
25 |
26 | public Response(int code, T result) {
27 | this.code = code;
28 | this.result = result;
29 | }
30 |
31 | public static Response NewErrResponse(String message) {
32 | return new Response(500, message);
33 | }
34 |
35 | public static Response NewErrResponse(int code, String message) {
36 | return new Response(500, message);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/exception/DispatchException.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.exception;
2 |
3 | public class DispatchException extends Exception {
4 | public DispatchException(int code, String message) {
5 | super(message);
6 | }
7 |
8 | public DispatchException(int code, String message, Throwable t) {
9 | super(message, t);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/impl/HttpClientManager.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.impl;
2 |
3 | import lombok.Setter;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.http.HttpHost;
6 | import org.apache.http.client.HttpClient;
7 | import org.apache.http.client.HttpRequestRetryHandler;
8 | import org.apache.http.client.config.RequestConfig;
9 | import org.apache.http.client.methods.HttpGet;
10 | import org.apache.http.client.methods.HttpPost;
11 | import org.apache.http.conn.routing.HttpRoute;
12 | import org.apache.http.entity.StringEntity;
13 | import org.apache.http.impl.client.CloseableHttpClient;
14 | import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
15 | import org.apache.http.impl.client.HttpClientBuilder;
16 | import org.apache.http.impl.client.HttpClients;
17 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
18 | import org.apache.http.protocol.HttpContext;
19 | import org.apache.http.util.EntityUtils;
20 |
21 | import java.io.IOException;
22 | import java.util.function.Function;
23 |
24 | /**
25 | * @author fangyu.fu
26 | */
27 | @Slf4j
28 | public class HttpClientManager {
29 | private static final String LEFT_SLASH = "/";
30 | private PoolingHttpClientConnectionManager connectionManager;
31 | private HttpClientBuilder httpBuilder;
32 | private RequestConfig requestConfig;
33 | @Setter
34 | private int maxConnection = 10;
35 | @Setter
36 | private String hostPort = "http://localhost:8080";
37 |
38 | private HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
39 | @Override
40 | public boolean retryRequest(IOException exception,
41 | int executionCount, HttpContext context) {
42 | return false;
43 | }};
44 |
45 | private HttpRequestRetryHandler requestRetryHandler = myRetryHandler;
46 |
47 | public HttpClientManager(String hostPort, RequestConfig requestConfig) {
48 | this(hostPort, requestConfig, 0);
49 | }
50 |
51 | public HttpClientManager(String hostPort, RequestConfig requestConfig, int retry) {
52 | this.hostPort = hostPort;
53 | this.requestConfig = requestConfig;
54 |
55 | if (hostPort.endsWith(LEFT_SLASH)) {
56 | this.hostPort = hostPort.substring(0, hostPort.length() - 1);
57 | }
58 | HttpHost target = new HttpHost(this.hostPort);
59 | connectionManager = new PoolingHttpClientConnectionManager();
60 | connectionManager.setMaxTotal(maxConnection);
61 | connectionManager.setDefaultMaxPerRoute(maxConnection);
62 | connectionManager.setMaxPerRoute(new HttpRoute(target), maxConnection);
63 | httpBuilder = HttpClients.custom();
64 | httpBuilder.setConnectionManager(connectionManager);
65 | if (retry > 0) {
66 | requestRetryHandler = new DefaultHttpRequestRetryHandler(retry, false);
67 | httpBuilder.setRetryHandler(requestRetryHandler);
68 | }else{
69 | httpBuilder.setRetryHandler(myRetryHandler);
70 | }
71 | }
72 |
73 | public HttpClientManager(String hostPort, int connectionTimeInMillis, int readTimeInMillis,
74 | int connectionRequestTimeInMillis, int retry) {
75 | this(hostPort, RequestConfig.custom()
76 | .setSocketTimeout(readTimeInMillis)
77 | .setConnectTimeout(connectionTimeInMillis)
78 | .setConnectionRequestTimeout(connectionRequestTimeInMillis)
79 | .build(), retry);
80 | }
81 |
82 | public HttpClient getConnection() {
83 | CloseableHttpClient httpClient = httpBuilder.setRetryHandler(myRetryHandler).build();
84 | return httpClient;
85 | }
86 |
87 | public T get(String url, Function function) throws Exception {
88 | HttpClient client = getConnection();
89 | HttpGet get = new HttpGet(String.format("%s%s", this.hostPort, url));
90 | get.setConfig(requestConfig);
91 | return client.execute(get, (httpResponse) -> {
92 | String body = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
93 | return function.apply(body);
94 | });
95 | }
96 |
97 | public T post(String url, String request, Function function) throws Exception {
98 | HttpClient client = getConnection();
99 | HttpPost post = new HttpPost(String.format("%s%s", this.hostPort, url));
100 | post.setConfig(requestConfig);
101 | String json = request;
102 | StringEntity requestEntity = new StringEntity(json, "utf-8");
103 | requestEntity.setContentEncoding("UTF-8");
104 | post.setHeader("Content-type", "application/json");
105 | post.setEntity(requestEntity);
106 | return client.execute(post, (httpResponse) -> {
107 | String body = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
108 | return function.apply(body);
109 | });
110 | }
111 |
112 | public void close() {
113 | try {
114 | connectionManager.close();
115 | } finally {
116 | //ignore exception.
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/impl/HttpDispatchClientImpl.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.impl;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.TypeReference;
5 | import dispatch.api.DispatchClient;
6 | import dispatch.api.dto.DispatchRequest;
7 | import dispatch.api.dto.DispatchSolution;
8 | import dispatch.api.dto.Response;
9 | import dispatch.api.exception.DispatchException;
10 | import lombok.Data;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.apache.http.HttpStatus;
13 | import org.apache.http.client.config.RequestConfig;
14 |
15 | import java.io.Closeable;
16 | import java.io.IOException;
17 |
18 | /**
19 | * @author fangyu.fu
20 | */
21 | @Data
22 | @Slf4j
23 | public class HttpDispatchClientImpl implements DispatchClient, Closeable {
24 |
25 | private static final String DISPATCH_PATH_V1 = "/api/v1/dispatch";
26 | private static final String PING_PATH_V1 = "/api/v1/ping";
27 | private static String DEFAULT_URL = "http://localhost:8080";
28 | private HttpClientManager httpClientManager;
29 |
30 | public HttpDispatchClientImpl(String url) {
31 | httpClientManager = new HttpClientManager(url, 5000, 5000,5000,0);
32 | }
33 |
34 | public HttpDispatchClientImpl() {
35 | httpClientManager = new HttpClientManager(DEFAULT_URL, 5000, 5000, 5000, 0);
36 | }
37 |
38 | public HttpDispatchClientImpl(String url, RequestConfig requestConfig, int retry) {
39 | httpClientManager = new HttpClientManager(url, requestConfig, retry);
40 | }
41 |
42 | @Override
43 | public Response dispatch(DispatchRequest dispatchRequest) throws DispatchException {
44 | try {
45 | return httpClientManager.post(DISPATCH_PATH_V1, JSON.toJSONString(dispatchRequest), (body) ->
46 | JSON.parseObject(body, new TypeReference>() {
47 | })
48 | );
49 | } catch (Exception e) {
50 | log.error("", e);
51 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e);
52 | }
53 | }
54 |
55 | @Override
56 | public Response ping() throws DispatchException {
57 | try {
58 | return httpClientManager.get(PING_PATH_V1, (body) ->
59 | JSON.parseObject(body, new TypeReference>() {
60 | })
61 | );
62 | } catch (Exception e) {
63 | log.error("", e);
64 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e);
65 | }
66 | }
67 |
68 | @Override
69 | public void close() throws IOException {
70 | httpClientManager.close();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/CourierRecord.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Lists;
4 | import dispatch.api.dto.Courier;
5 | import dispatch.api.dto.CourierPlan;
6 | import dispatch.api.dto.Location;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 |
10 | import java.util.List;
11 |
12 | @Getter
13 | public class CourierRecord {
14 | private Courier courier;
15 | @Setter
16 | private Location location;
17 | private Long courierTime;
18 | private List courierPlans;
19 |
20 | public CourierRecord(Courier courier, Long courierTime) {
21 | this.courier = courier;
22 | this.location = courier.getLoc();
23 | this.courierTime = courierTime;
24 | this.courierPlans = Lists.newArrayList();
25 | }
26 |
27 | public void timeChange(Long time) {
28 | if (time > courierTime) {
29 | courierTime = time;
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/DispatchJudge.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.DispatchClient;
4 | import dispatch.api.impl.HttpDispatchClientImpl;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | import java.io.File;
8 |
9 | @Slf4j
10 | public class DispatchJudge {
11 |
12 | public static void main(String[] args) {
13 | String directory = "";
14 | String api = "http://localhost:8080";
15 | if (args.length > 0) {
16 | directory = args[0];
17 | log.error(String.format("Data directory is %s", directory));
18 | }
19 | if (args.length > 1) {
20 | api = args[1];
21 | log.error(String.format("Api is %s", api));
22 | }
23 | File rootDirectory = new File(directory);
24 | if(!rootDirectory.isDirectory()){
25 | log.error("Input path must be a directory.");
26 | System.exit(1);
27 | }
28 | File[] dataFiles = rootDirectory.listFiles((f)->f.isDirectory() && f.getName().matches("\\d+"));
29 | for(File dataFile:dataFiles){
30 | String orderPath = String.format("%s/%s",dataFile.getAbsolutePath(),"order");
31 | String courierPath = String.format("%s/%s",dataFile.getAbsolutePath(), "courier");
32 | DispatchClient dispatchClient = new HttpDispatchClientImpl(api);
33 | // 从文件读取订单骑士数据
34 | RawData rawData = new RawData(orderPath, courierPath);
35 |
36 | SequentialJudge sequentialJudge = new SequentialJudge(dispatchClient, rawData);
37 | sequentialJudge.doDispatch();
38 |
39 | Score score = sequentialJudge.getScore();
40 | log.error(String.format("AreaId %s overtimeCount: %f", dataFile.getName(), score.getOvertimeCount()));
41 | log.error(String.format("AreaId %s avgDeliveryTime: %f", dataFile.getName(), score.getAvgServiceTime()));
42 | if (score.getIllegalMsg().isIllegal()) {
43 | log.error(String.format("AreaId %s error Msg %s", dataFile.getName(), score.getIllegalMsg().getMsg()));
44 | }
45 | }
46 | //Merge result
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/DispatchLog.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.DispatchRequest;
4 | import dispatch.api.dto.DispatchSolution;
5 | import lombok.Getter;
6 |
7 | @Getter
8 | public class DispatchLog {
9 | private DispatchRequest request;
10 | private DispatchSolution solution;
11 |
12 | public DispatchLog(DispatchRequest request, DispatchSolution solution) {
13 | this.request = request;
14 | this.solution = solution;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/IllegalMsg.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class IllegalMsg {
7 | private boolean illegal;
8 | private String msg = "";
9 |
10 | public IllegalMsg(String msg) {
11 | this.illegal = true;
12 | this.msg = msg;
13 | }
14 |
15 | public IllegalMsg() {
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/JudgeUtil.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.Location;
4 | import org.joda.time.DateTime;
5 |
6 | public class JudgeUtil {
7 | /**
8 | * 地球半径
9 | */
10 | private static final double RADIUS = 6367000.0;
11 |
12 | /**
13 | * 导航距离/路面距离 经验系数
14 | */
15 | private static final double COEFFICIENT = 1.4;
16 |
17 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */
18 | public static double getDistance(Location from, Location to) {
19 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT;
20 | }
21 |
22 | /** 简化版球面距离 */
23 | public static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) {
24 | // 经度差值
25 | double deltaLng = lng2 - lng1;
26 | // 纬度差值
27 | double deltaLat = lat2 - lat1;
28 | // 平均纬度
29 | double b = (lat1 + lat2) / 2.0;
30 | // 东西距离
31 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b));
32 | // 南北距离
33 | double y = RADIUS * Math.toRadians(deltaLat);
34 | // 用平面的矩形对角距离公式计算总距离
35 | return Math.sqrt(x * x + y * y);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/OrderRecord.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.Order;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class OrderRecord {
8 | private Order order;
9 | private int status;
10 | private boolean overTime;
11 | private Long deliveryTime;
12 |
13 | public OrderRecord(Order order) {
14 | this.order = order;
15 | this.status = 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/RawData.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.google.common.collect.Maps;
5 | import dispatch.api.dto.Courier;
6 | import dispatch.api.dto.Location;
7 | import dispatch.api.dto.Order;
8 | import lombok.Getter;
9 |
10 | import java.io.File;
11 | import java.util.*;
12 |
13 | @Getter
14 | public class RawData {
15 |
16 | private String areaId;
17 | private List orders;
18 | private List couriers;
19 | private Map courierOnlineTime;
20 |
21 | public RawData(String orderFilePath, String courierFilePath) {
22 | this.orders = Lists.newArrayList();
23 | this.couriers = Lists.newArrayList();
24 | this.courierOnlineTime = Maps.newHashMap();
25 |
26 | try {
27 | Scanner orderScanner = new Scanner(new File(orderFilePath));
28 | orderScanner.nextLine();
29 | while (orderScanner.hasNextLine()) {
30 | this.orders.add(orderLine2Order(getRecordFromLine(orderScanner.nextLine())));
31 | }
32 | Scanner courierScanner = new Scanner(new File(courierFilePath));
33 | courierScanner.nextLine();
34 | while (courierScanner.hasNextLine()) {
35 | List courierLine = getRecordFromLine(courierScanner.nextLine());
36 | this.courierOnlineTime.put(courierLine.get(1), Long.parseLong(courierLine.get(2)));
37 | this.couriers.add(courierLine2Courier(courierLine));
38 | }
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | }
42 | this.orders.sort(Comparator.comparingLong(Order::getCreateTime));
43 | this.couriers.sort(Comparator.comparingLong(c -> courierOnlineTime.get(c.getId())));
44 | this.areaId = orders.get(0).getAreaId();
45 | }
46 |
47 |
48 | private static final String COMMA_DELIMITER = "\t";
49 |
50 | private static List getRecordFromLine(String line) {
51 | List values = new ArrayList<>();
52 | try (Scanner rowScanner = new Scanner(line)) {
53 | rowScanner.useDelimiter(COMMA_DELIMITER);
54 | while (rowScanner.hasNext()) {
55 | values.add(rowScanner.next());
56 | }
57 | }
58 | return values;
59 | }
60 |
61 | private static Order orderLine2Order(List orderLine) {
62 | return new Order().setAreaId(orderLine.get(0))
63 | .setId(orderLine.get(1))
64 | .setCreateTime(Long.parseLong(orderLine.get(2)))
65 | .setEstimatedPrepareCompletedTime(Long.parseLong(orderLine.get(3)))
66 | .setPromiseDeliverTime(Long.parseLong(orderLine.get(4)))
67 | .setSrcLoc(new Location(Double.parseDouble(orderLine.get(5)), Double.parseDouble(orderLine.get(6))))
68 | .setDstLoc(new Location(Double.parseDouble(orderLine.get(7)), Double.parseDouble(orderLine.get(8))));
69 | }
70 |
71 | private static Courier courierLine2Courier(List courierLine) {
72 | return new Courier().setAreaId(courierLine.get(0))
73 | .setId(courierLine.get(1))
74 | .setMaxLoads(Integer.parseInt(courierLine.get(3)))
75 | .setSpeed(Double.parseDouble(courierLine.get(4)))
76 | .setLoc(new Location(Double.parseDouble(courierLine.get(5)), Double.parseDouble(courierLine.get(6))));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/Score.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Score {
7 | private IllegalMsg illegalMsg = new IllegalMsg();
8 | private double avgServiceTime;
9 | private double overtimeCount;
10 | private long serviceTimeSum;
11 | private long orderSum;
12 |
13 | public void setIllegalMsg(IllegalMsg illegalMsg) {
14 | this.illegalMsg = illegalMsg;
15 | }
16 |
17 | public void setIllegalMsg(String illegalMsg) {
18 | this.illegalMsg = new IllegalMsg(illegalMsg);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/SequentialJudge.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Iterables;
4 | import com.google.common.collect.Lists;
5 | import com.google.common.collect.Queues;
6 | import dispatch.api.DispatchClient;
7 | import dispatch.api.dto.*;
8 | import lombok.Getter;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Queue;
13 |
14 | public class SequentialJudge {
15 | private DispatchClient dispatchClient;
16 | private int intervalSecond;
17 |
18 | private RawData rawData;
19 | private Queue orderQueue;
20 | private Queue courierQueue;
21 |
22 | private long currentTime;
23 | private long endTime;
24 |
25 | @Getter
26 | private Score score;
27 | private List dispatchLogs = new ArrayList<>(0);
28 |
29 |
30 | public SequentialJudge(DispatchClient client, RawData rawData) {
31 | this(client, rawData, 60);
32 | }
33 |
34 | public SequentialJudge(DispatchClient client, RawData rawData, int intervalSecond) {
35 | this.dispatchClient = client;
36 | this.rawData = rawData;
37 | this.intervalSecond = intervalSecond;
38 | this.orderQueue = Queues.newArrayDeque(rawData.getOrders());
39 | this.courierQueue = Queues.newArrayDeque(rawData.getCouriers());
40 | this.score = new Score();
41 |
42 | this.currentTime = orderQueue.element().getCreateTime() + intervalSecond;
43 | this.endTime = Iterables.getLast(rawData.getOrders()).getCreateTime();
44 |
45 | }
46 |
47 | public void doDispatch() {
48 | DispatchContext dispatchContext = new DispatchContext();
49 | boolean isFirstRound = true;
50 | while (currentTime <= endTime) {
51 | DispatchRequest request = new DispatchRequest()
52 | .setAreaId(rawData.getAreaId())
53 | .setRequestTime(currentTime);
54 |
55 | List dispatchingOrders = Lists.newArrayList();
56 | List onlineCourier = Lists.newArrayList();
57 | while (!orderQueue.isEmpty() && orderQueue.element().getCreateTime() <= currentTime) {
58 | dispatchingOrders.add(orderQueue.remove());
59 | }
60 | while (!courierQueue.isEmpty() &&
61 | rawData.getCourierOnlineTime().get(courierQueue.element().getId()) <= currentTime) {
62 | onlineCourier.add(courierQueue.remove());
63 | }
64 |
65 | request.setCouriers(onlineCourier);
66 | request.setOrders(dispatchingOrders);
67 |
68 | currentTime += intervalSecond;
69 | request.setFirstRound(isFirstRound);
70 | request.setLastRound(currentTime > endTime);
71 |
72 | if (isFirstRound) {
73 | isFirstRound = false;
74 | }
75 |
76 | Response solutionResponse;
77 | try {
78 | solutionResponse = dispatchClient.dispatch(request);
79 | } catch (Exception e) {
80 | score.setIllegalMsg(e.getMessage());
81 | return;
82 | }
83 |
84 | if (null == solutionResponse) {
85 | score.setIllegalMsg("no response");
86 | return;
87 | } else if (solutionResponse.getCode() != 200) {
88 | score.setIllegalMsg(solutionResponse.getMessage());
89 | return;
90 | } else {
91 | DispatchLog dispatchLog = new DispatchLog(request, solutionResponse.getResult());
92 | this.dispatchLogs.add(dispatchLog);
93 | IllegalMsg illegalMsg = dispatchContext.allocate(dispatchLog);
94 | if (illegalMsg.isIllegal()) {
95 | score.setIllegalMsg(illegalMsg.getMsg());
96 | return;
97 | }
98 | }
99 | }
100 | this.score = dispatchContext.checkAndScore();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-api/src/test/java/dispatch/api/impl/HttpDispatchClientImplTest.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.impl;
2 |
3 | import dispatch.api.DispatchClient;
4 | import dispatch.api.exception.DispatchException;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.junit.AfterClass;
7 | import org.junit.BeforeClass;
8 | import org.junit.Test;
9 |
10 | import java.io.IOException;
11 |
12 | import static org.junit.Assert.assertEquals;
13 |
14 | @Slf4j
15 | public class HttpDispatchClientImplTest {
16 | private static DispatchClient dispatchClient;
17 |
18 | @BeforeClass
19 | public static void init() {
20 | dispatchClient = new HttpDispatchClientImpl();
21 | }
22 |
23 | @AfterClass
24 | public static void destroy() throws IOException {
25 | dispatchClient.close();
26 | }
27 |
28 | @Test
29 | public void testPing() throws DispatchException, InterruptedException {
30 | assertEquals(dispatchClient.ping().getResult(), "PONG");
31 | Thread.sleep(100);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/cmd.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "github.com/sirupsen/logrus"
5 | "github.com/spf13/cobra"
6 | "os"
7 | "os/signal"
8 | "syscall"
9 | )
10 |
11 | var (
12 | debug bool
13 | clientId string
14 | shutdownWaitSecs int
15 | )
16 |
17 | func init() {
18 | Cmd.PersistentFlags().BoolVar(&debug, "debug", true, "debug mode")
19 | Cmd.PersistentFlags().StringVar(&clientId, "clientId", "", "Id of your tianchi account")
20 | Cmd.PersistentFlags().IntVar(&shutdownWaitSecs, "shutdownWait", 10, "shutdown wait seconds")
21 | }
22 |
23 | var (
24 | // Cmd is the sub command for running as an api server
25 | Cmd = &cobra.Command{
26 | Use: "run",
27 | Short: "Start player's dispatching http server at port 8080.",
28 | Long: "Start player's dispatching http server at port 8080.",
29 | Run: func(cmd *cobra.Command, args []string) {
30 | if debug {
31 | logrus.SetLevel(logrus.DebugLevel)
32 | }
33 |
34 | server, err := NewServer(shutdownWaitSecs, debug, clientId)
35 | if err != nil {
36 | logrus.Fatalf("Starting player's server failed: %v\n", err)
37 | }
38 |
39 | err = server.Start()
40 | if err != nil {
41 | logrus.Fatalf("Starting player's server failed: %v\n", err)
42 | }
43 |
44 | signals := make(chan os.Signal)
45 | signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
46 | <-signals
47 | err = server.Shutdown()
48 | if err != nil {
49 | logrus.Fatalf("Shutdown client server failed: %v\n", err)
50 | }
51 | },
52 | }
53 | )
54 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/dispatcher.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | type Dispatcher interface {
4 | Ping() string
5 | Dispatch(request *DispatchRequest) ([]DispatchSolution, error)
6 | }
7 |
8 | type GreedyDispatcher struct {
9 | routes []DispatchSolution
10 | }
11 |
12 | func NewGreedyDispatcher() *GreedyDispatcher {
13 | return &GreedyDispatcher{}
14 | }
15 |
16 | func (*GreedyDispatcher) Ping() string {
17 | return "PONG"
18 | }
19 |
20 | func (*GreedyDispatcher) Dispatch(request *DispatchRequest) ([]DispatchSolution, error) {
21 | return nil, nil
22 | }
23 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/dto.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | const (
4 | Status_OK = 200
5 | Status_BAD_REQUEST = 400
6 | Status_UNKNOWN = 500
7 | Status_TIMEOUT = 510
8 | )
9 |
10 | type ActionNode struct {
11 | OrderId string `json:"orderId"`
12 | ActionType int `json:"actionType"`
13 | ActionTimestamp int64 `json:"ActionTimestamp"`
14 | }
15 |
16 | type Location struct {
17 | Latitude float64 `json:"latitude"`
18 | Longitude float64 `json:"longitude"`
19 | }
20 |
21 | type Courier struct {
22 | AreaId string `json:"areaId"`
23 | Id string `json:"id"`
24 | Loc *Location `json:"loc"`
25 | Speed float64 `json:speed`
26 | MaxLoads int `json:"maxLoads"`
27 | }
28 |
29 | type CourierPlan struct {
30 | CourierId string `json:"courierId"`
31 | PlanRoutes []ActionNode `json:planRoutes`
32 | }
33 |
34 | type Order struct {
35 | AreaId string `json:"areaId"`
36 | Id string `json:"id"`
37 | SrcLoc *Location `json:"srcLoc"`
38 | DstLoc *Location `json:"dstLoc"`
39 | Status int `json:"status"`
40 | CreateTimestamp int64 `json:"createTimestamp"`
41 | PromiseDeliverTime int64 `json:"promiseDeliverTime"`
42 | EstimatedPrepareCompletedTimestamp int64 `json:"estimatedPrepareCompletedTimestamp"`
43 | }
44 |
45 | type DispatchRequest struct {
46 | RequestTimestamp int64 `json:"requestTimestamp"`
47 | AreaId string `json:"areaId"`
48 | IsFirstRound bool `json:"isFirstRound"`
49 | IsLastRound bool `json:"isLastRound"`
50 | Couriers []Courier `json:"couriers"`
51 | Orders []Order `json:"orders"`
52 | }
53 |
54 | type DispatchSolution struct {
55 | CourierPlans []CourierPlan `json:"courierPlans"`
56 | }
57 |
58 | type Response struct {
59 | Code int `json:"code"`
60 | Result interface{} `json:"result"`
61 | Message string `json:"message"`
62 | }
63 |
64 | func NewResponse(v interface{}) *Response {
65 | return &Response{
66 | Code: Status_OK,
67 | Result: v,
68 | Message: "",
69 | }
70 | }
71 |
72 | func NewErrorResponse(code int, message string) *Response {
73 | return &Response{
74 | Code: code,
75 | Message: message,
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/log.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/sirupsen/logrus"
6 | "io"
7 | "time"
8 | )
9 |
10 | func Logger(writer io.Writer, debug bool) *logrus.Logger {
11 | logger := logrus.New()
12 | logger.Out = writer
13 | if debug {
14 | logger.SetLevel(logrus.DebugLevel)
15 | }
16 | return logger
17 | }
18 |
19 | func NewLogger(writer io.Writer, debug bool) gin.HandlerFunc {
20 | logger := Logger(writer, debug)
21 | return func(c *gin.Context) {
22 | // 开始时间
23 | startTime := time.Now()
24 |
25 | // 处理请求
26 | c.Next()
27 |
28 | // 结束时间
29 | endTime := time.Now()
30 |
31 | // 执行时间
32 | latencyTime := endTime.Sub(startTime)
33 |
34 | // 请求方式
35 | reqMethod := c.Request.Method
36 |
37 | // 请求路由
38 | reqUri := c.Request.RequestURI
39 |
40 | // 状态码
41 | statusCode := c.Writer.Status()
42 |
43 | // 请求IP
44 | clientIP := c.ClientIP()
45 |
46 | //日志格式
47 | logger.Infof("| %3d | %13v | %15s | %s | %s |",
48 | statusCode,
49 | latencyTime,
50 | clientIP,
51 | reqMethod,
52 | reqUri,
53 |
54 | )
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/server.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "context"
5 | "github.com/gin-gonic/gin"
6 | "github.com/pkg/errors"
7 | "github.com/sirupsen/logrus"
8 | "net/http"
9 | "os"
10 | "sync"
11 | "time"
12 | )
13 |
14 | type Server struct {
15 | closeMux *sync.Mutex
16 | port int
17 | debug bool
18 | shutdownWait int
19 | closed bool
20 | logger *logrus.Entry
21 | srv *http.Server
22 | dispatcher Dispatcher
23 | }
24 |
25 | func NewServer(shutdownWait int, debug bool, clientId string) (*Server, error) {
26 | server := &Server{
27 | closeMux: &sync.Mutex{},
28 | debug: debug,
29 | shutdownWait: shutdownWait,
30 | closed: false,
31 | logger: logrus.WithField("client", clientId).WithField("time", time.Now().String()),
32 | dispatcher: NewGreedyDispatcher(),
33 | }
34 | return server, nil
35 | }
36 |
37 | func (server *Server) Start() error {
38 | server.closeMux.Lock()
39 | defer server.closeMux.Unlock()
40 | if server.closed {
41 | return errors.New("Server is closed")
42 | }
43 | r := gin.New()
44 | // Add Log
45 | r.Use(NewLogger(os.Stdout, server.debug))
46 | //Add Recovery
47 | r.Use(gin.Recovery())
48 |
49 | v1 := r.Group("/api/v1")
50 | v1.GET("/ping", func(c *gin.Context) {
51 | server.logger.Info("")
52 | c.JSON(http.StatusOK, server.dispatcher.Ping())
53 | })
54 |
55 | v1.POST("/dispatch", func(c *gin.Context) {
56 | request := &DispatchRequest{}
57 | if err := c.ShouldBind(&request); err == nil {
58 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
59 | defer cancel()
60 | ch := make(chan *Response)
61 | go func() {
62 | response, errs := server.dispatcher.Dispatch(request)
63 | if errs == nil {
64 | ch <- NewResponse(response)
65 | } else {
66 | ch <- NewErrorResponse(Status_UNKNOWN, errs.Error())
67 | }
68 | }()
69 | var response *Response
70 | for {
71 | select {
72 | case <-ctx.Done():
73 | server.logger.Errorf("Request timeout %v",*request)
74 | c.JSON(http.StatusOK, NewErrorResponse(Status_TIMEOUT, "Dispatcher timeout"))
75 | return
76 | case response = <-ch:
77 | server.logger.Infof("Request:%s,Response:%s", *request, *response)
78 | c.JSON(http.StatusOK, response)
79 | return
80 | }
81 | }
82 | } else {
83 | response := NewErrorResponse(
84 | Status_BAD_REQUEST, "Could not resolve request body.",
85 | )
86 | server.logger.Infof("Request:%s,Response:%s", &request, &response)
87 | c.JSON(http.StatusOK, &response)
88 | }
89 | })
90 | srv := &http.Server{
91 | Addr: ":8080",
92 | Handler: r,
93 | }
94 | server.srv = srv
95 | go func() {
96 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
97 | server.logger.Fatalf("listen: %s\n", err)
98 | }
99 | }()
100 | return nil
101 | }
102 |
103 | func (server *Server) Shutdown() error {
104 | server.closeMux.Lock()
105 | defer server.closeMux.Unlock()
106 | if server.closed {
107 | return nil
108 | }
109 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(server.shutdownWait))
110 | defer cancel()
111 | if err := server.srv.Shutdown(ctx); err != nil {
112 | server.logger.Fatal("Server shutdown error:", err)
113 | return err
114 | }
115 | server.closed = true
116 | server.logger.Info("Server exited")
117 | return nil
118 | }
119 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/go.mod:
--------------------------------------------------------------------------------
1 | module gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go
2 |
3 | require (
4 | github.com/gin-gonic/gin v1.4.0
5 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
6 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
7 | github.com/pkg/errors v0.8.0
8 | github.com/sirupsen/logrus v1.5.0
9 | github.com/spf13/cobra v0.0.7
10 | github.com/stretchr/objx v0.1.1 // indirect
11 | github.com/stretchr/testify v1.5.1 // indirect
12 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d // indirect
13 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
14 | gopkg.in/yaml.v2 v2.2.8 // indirect
15 | )
16 |
17 | go 1.12
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-go/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/sirupsen/logrus"
5 | "github.com/spf13/cobra"
6 | "gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go/dispatch"
7 | )
8 |
9 | var rootCmd = &cobra.Command{
10 | Use: "run",
11 | Short: "Tianchi&Eleme Delivery Order Dispatching Contest 2020",
12 | Long: "Tianchi&Eleme Delivery Order Dispatching Contest 2020",
13 | Run: func(cmd *cobra.Command, args []string) {
14 | cmd.Usage()
15 | },
16 | }
17 |
18 | func init() {
19 | rootCmd.AddCommand(dispatch.Cmd)
20 | }
21 | func main() {
22 | logrus.New().Info("demo")
23 | if err := rootCmd.Execute(); err != nil {
24 | logrus.Fatalf("%v", err)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-py/app.py:
--------------------------------------------------------------------------------
1 | import http
2 |
3 | from flask import Flask, jsonify, request
4 |
5 | import json
6 |
7 | from demo.dto import Response
8 |
9 | app = Flask(__name__)
10 |
11 |
12 | @app.route('/api/v1/ping', methods=['GET'])
13 | def ping():
14 | return json.dumps(dict(Response(200, "Pong", "")))
15 |
16 |
17 | @app.route('/api/v1/dispatch', methods=['POST'])
18 | def dispatch():
19 | data = request.json
20 | # data is in format of demo.dto.DispatchRequest
21 | print(data)
22 | return '', http.HTTPStatus.OK
23 |
24 |
25 | if __name__ == "__main__":
26 | app.run(debug=True, port=8080)
27 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/__init__.py
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/dto.py:
--------------------------------------------------------------------------------
1 | class Location(object):
2 | def __init__(self, _latitude, _longitude):
3 | self.latitude = _latitude
4 | self.longitude = _longitude
5 |
6 | def keys(self):
7 | return ['latitude', 'longitude']
8 |
9 | def __getitem__(self, item):
10 | return getattr(self, item)
11 |
12 |
13 | class Courier(object):
14 | def __init__(self, _id, _areaId, _loc, _speed, __maxLoads):
15 | self.id = _id
16 | self.areaId = _areaId
17 | self.loc = _loc
18 | self.speed = _speed
19 | self.maxLoads = __maxLoads
20 |
21 | def keys(self):
22 | return ['id', 'areaId', 'loc', 'speed', 'maxLoads']
23 |
24 | def __getitem__(self, item):
25 | return getattr(self, item)
26 |
27 |
28 | class Order(object):
29 | def __init__(self, _areaId, _id, _srcLoc, _dstLoc, _status, _createTimestamp, _promiseDeliverTime,
30 | _estimatedPrepareCompletedTimestamp):
31 | self.areaId = _areaId
32 | self.id = _id
33 | self.srcLoc = _srcLoc
34 | self.dstLoc = _dstLoc
35 | self.status = _status
36 | self.createTimestamp = _createTimestamp
37 | self.promiseDeliverTime = _promiseDeliverTime
38 | self.estimatedPrepareCompletedTimestamp = _estimatedPrepareCompletedTimestamp
39 |
40 | def keys(self):
41 | return ['id', 'areaId', 'srcLoc', 'dstLoc', 'status',
42 | 'createTimestamp', 'promiseDeliverTime', 'estimatedPrepareCompletedTimestamp']
43 |
44 | def __getitem__(self, item):
45 | return getattr(self, item)
46 |
47 |
48 | class ActionNode(object):
49 | def __init__(self, _actionType, _orderId, _actionTimestamp):
50 | self.actionType = _actionType
51 | self.orderId = _orderId
52 | self.actionTimestamp = _actionTimestamp
53 |
54 | def keys(self):
55 | return ['actionType', 'orderId', 'actionTimestamp']
56 |
57 | def __getitem__(self, item):
58 | return getattr(self, item)
59 |
60 |
61 | class CourierPlan(object):
62 | def __init__(self, _courierId, _planRoutes):
63 | self.courierId = _courierId
64 | self.planRoutes = _planRoutes
65 |
66 | def keys(self):
67 | return ['courierId', 'planRoutes']
68 |
69 | def __getitem__(self, item):
70 | return getattr(self, item)
71 |
72 |
73 | class DispatchRequest(object):
74 | def __init__(self, _requestTimestamp, _areaId, _isFirstRound, _isLastRound, _couriers, _orders):
75 | self.requestTimestamp = _requestTimestamp
76 | self.areaId = _areaId
77 | self.isFirstRound = _isFirstRound
78 | self.isLastRound = _isLastRound
79 | self.couriers = _couriers
80 | self.orders = _orders
81 |
82 | def keys(self):
83 | return ['requestTimestamp', 'areaId', 'isFirstRound', 'isLastRound',
84 | 'couriers', 'orders']
85 |
86 | def __getitem__(self, item):
87 | return getattr(self, item)
88 |
89 |
90 | class Response(object):
91 | def __init__(self, _code, _result, _message):
92 | self.code = _code
93 | self.result = _result
94 | self.message = _message
95 |
96 | def keys(self):
97 | return ['code', 'result', 'message']
98 |
99 | def __getitem__(self, item):
100 | return getattr(self, item)
101 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo-py/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(
4 | name="dispatch-demo-py",
5 | version="0.0.1",
6 | author="fangyu.ffy",
7 | author_email="fangyu.ffy@alibaba-inc.com",
8 | description="Tianchi-Eleme delivery order dispatch contest.",
9 | keywords="Tianchi,Eleme,Delivery,Dispatch",
10 | install_requires=['flask>=1.1.1']
11 |
12 | )
13 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.13.RELEASE
9 |
10 |
11 | dispatch
12 | dispatch-demo
13 | 0.0.1-SNAPSHOT
14 | dispatch-demo
15 | Demo project for Spring Boot
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.projectlombok
24 | lombok
25 |
26 |
27 |
28 |
29 | com.alibaba
30 | fastjson
31 | 1.2.68
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-devtools
42 | runtime
43 | true
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-test
48 | test
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-maven-plugin
59 |
60 |
61 | dispatch-demo
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/.DS_Store
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/.DS_Store
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/.DS_Store
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/DispatchDemoApplication.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | @SpringBootApplication
10 | public class DispatchDemoApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(DispatchDemoApplication.class, args);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/controller/DispatchController.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.controller;
2 |
3 |
4 | import com.alibaba.fastjson.JSON;
5 | import dispatch.demo.core.DispatchService;
6 | import dispatch.demo.dto.DispatchRequest;
7 | import dispatch.demo.dto.DispatchSolution;
8 | import dispatch.demo.dto.Response;
9 | import org.springframework.web.bind.annotation.*;
10 |
11 | import java.util.concurrent.ArrayBlockingQueue;
12 | import java.util.concurrent.Future;
13 | import java.util.concurrent.ThreadPoolExecutor;
14 | import java.util.concurrent.TimeUnit;
15 |
16 |
17 | /**
18 | * @author eleme.demo
19 | */
20 | @RestController()
21 | @RequestMapping("/api/v1")
22 | public class DispatchController {
23 |
24 |
25 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
26 | Runtime.getRuntime().availableProcessors(),
27 | Runtime.getRuntime().availableProcessors(),
28 | 30,
29 | TimeUnit.SECONDS,
30 | new ArrayBlockingQueue<>(100)
31 | );
32 |
33 | DispatchService dispatchService = new DispatchService();
34 |
35 |
36 | @RequestMapping(value = "/ping", method = RequestMethod.GET)
37 | public Response ping() {
38 | System.out.println("ping");
39 | return new Response<>("PONG");
40 | }
41 |
42 | @RequestMapping(value = "/dispatch", method = RequestMethod.POST, produces = "application/json")
43 | public String dispatch(@RequestBody String jsonRequest) {
44 | System.out.println(jsonRequest);
45 | DispatchRequest request = JSON.parseObject(jsonRequest, DispatchRequest.class);
46 | DispatchSolution result = null;
47 | Future f = threadPoolExecutor.submit(() -> {
48 | return dispatchService.dispatch(request);
49 | });
50 | try {
51 | //wait maximum 4s
52 | result = f.get(4, TimeUnit.SECONDS);
53 | } catch (Exception e) {
54 | System.out.println(e.getMessage());
55 | //downgrade solution here, downgrade solution must finish within 1s so that total request processing will be finished within 5s.
56 | return JSON.toJSONString(Response.NewErrResponse(e.getMessage()));
57 | }
58 | if (null != result) {
59 | System.out.println(JSON.toJSONString(result));
60 | }
61 | Response r = new Response(200, result);
62 | return JSON.toJSONString(r);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/DispatchService.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.core.solver.BaseSolver;
5 | import dispatch.demo.dto.CourierPlan;
6 | import dispatch.demo.dto.DispatchRequest;
7 | import dispatch.demo.dto.DispatchSolution;
8 |
9 | import java.util.Collections;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | /**
15 | * @author eleme.demo
16 | */
17 | public class DispatchService {
18 |
19 | Map serviceContext = new HashMap<>(0);
20 |
21 | public DispatchSolution dispatch(DispatchRequest request) {
22 | String areaId = request.getAreaId();
23 | DispatchContext context;
24 | if (request.isFirstRound()) {
25 | context = new DispatchContext();
26 | context.setAreaId(areaId);
27 | context.setTimeStamp(request.getRequestTime());
28 | serviceContext.put(areaId, context);
29 | } else {
30 | context = serviceContext.get(areaId);
31 | if (null == context) {
32 | DispatchSolution emptySolution = new DispatchSolution();
33 | emptySolution.setCourierPlans(Collections.emptyList());
34 | return emptySolution;
35 | } else {
36 | if (request.isLastRound()) {
37 | context.setEndOfTest(true);
38 | }
39 | }
40 | context.refresh(request.getRequestTime());
41 | }
42 | context.addOnlineCouriers(request.getCouriers());
43 | context.addDispatchingOrders(request.getOrders());
44 | BaseSolver solver = getSolver(context);
45 | List courierPlans = solver.solve();
46 | courierPlans.forEach(cp -> {
47 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true));
48 | });
49 | List assignedIds = solver.getAssignedOrderIds();
50 | context.markAllocatedOrders(assignedIds);
51 | while (!context.getOrderPool().getDispatchingOrders().isEmpty() && context.isEndOfTest()) {
52 | long aheadTime = 10 * 60;
53 | context.setTimeStamp(context.getTimeStamp() + aheadTime);
54 | BaseSolver lastRoundSolver = getSolver(context);
55 | List tmpPlans = lastRoundSolver.solve();
56 | courierPlans.addAll(tmpPlans);
57 | tmpPlans.forEach(cp -> {
58 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true));
59 | });
60 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds());
61 | }
62 | DispatchSolution solution = new DispatchSolution();
63 | solution.setCourierPlans(courierPlans);
64 | return solution;
65 | }
66 |
67 | BaseSolver getSolver(DispatchContext context) {
68 | return new BaseSolver(context);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/context/DispatchContext.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.context;
2 |
3 | import dispatch.demo.core.pool.CourierPool;
4 | import dispatch.demo.core.pool.OrderPool;
5 | import dispatch.demo.dto.ActionNode;
6 | import dispatch.demo.dto.Courier;
7 | import dispatch.demo.dto.Location;
8 | import dispatch.demo.dto.Order;
9 | import lombok.Data;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * @author eleme.demo
17 | */
18 | @Data
19 | public class DispatchContext {
20 | private String areaId;
21 | private CourierPool courierPool = new CourierPool();
22 | private OrderPool orderPool = new OrderPool();
23 | private long timeStamp;
24 | private boolean isEndOfTest = false;
25 |
26 | public void addOnlineCouriers(List courierList) {
27 | courierPool.getCouriers().addAll(courierList);
28 | }
29 |
30 | public void addDispatchingOrders(List orders) {
31 | orderPool.addDispatchingOrders(orders);
32 | }
33 |
34 | public void markAllocatedOrders(List orderIds) {
35 | orderIds.forEach(id -> orderPool.markAssignedOrder(id));
36 | }
37 |
38 | public void refresh(long refreshTime) {
39 | this.timeStamp = refreshTime;
40 | courierPool.getCouriers().forEach(c -> {
41 | refreshCourier(c, refreshTime);
42 | });
43 | }
44 |
45 | private void refreshCourier(Courier courier, long refreshTime) {
46 | List actionNodeList = courier.getPlanRoutes();
47 | List refreshNodeList = new ArrayList<>(0);
48 | for (ActionNode node : actionNodeList) {
49 | if (node.isSubmitted() && node.getActionTime() <= refreshTime) {
50 | if (node.getActionType() == 1) {
51 | //到店完成
52 | orderPool.markArrivalCompleteOrder(node.getOrderId());
53 | }
54 | if (node.getActionType() == 2) {
55 | //取餐完成
56 | orderPool.markPickCompleteOrder(node.getOrderId());
57 | }
58 | if (node.getActionType() == 3) {
59 | //送达
60 | orderPool.markDeliverCompleteOrder(node.getOrderId());
61 | }
62 | } else {
63 | refreshNodeList.add(node);
64 | }
65 | }
66 | List loadOrders = courier.getOrders().stream()
67 | .filter(o -> o.getStatus() != 4)
68 | .collect(Collectors.toList());
69 | courier.setOrders(loadOrders);
70 | courier.setPlanRoutes(refreshNodeList);
71 | if(refreshNodeList.isEmpty() && !actionNodeList.isEmpty()){
72 | Location latestLoc = orderPool.getOrderMap().get(actionNodeList.get(actionNodeList.size()-1).getOrderId()).getDstLoc();
73 | courier.setLoc(latestLoc);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/pool/CourierPool.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.pool;
2 |
3 | import dispatch.demo.dto.Courier;
4 | import lombok.Data;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * @author eleme.demo
11 | */
12 | @Data
13 | public class CourierPool {
14 | private List couriers = new ArrayList<>(0);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/pool/OrderPool.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.pool;
2 |
3 | import dispatch.demo.dto.Order;
4 | import lombok.Getter;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.stream.Collectors;
10 |
11 | /**
12 | * @author eleme.demo
13 | */
14 |
15 | public class OrderPool {
16 |
17 | private List orders;
18 |
19 | @Getter
20 | private HashMap orderMap;
21 |
22 | public OrderPool() {
23 | orders = new ArrayList<>(0);
24 | orderMap = new HashMap<>(0);
25 | }
26 |
27 | public void addDispatchingOrders(List dispatchingOrders) {
28 | this.orders.addAll(dispatchingOrders);
29 | for (Order order : orders) {
30 | orderMap.put(order.getId(), order);
31 | }
32 | }
33 |
34 | public List getDispatchingOrders() {
35 | return orders.stream().filter(o -> o.getStatus() == 0).collect(Collectors.toList());
36 | }
37 |
38 | public void markAssignedOrder(String orderId){
39 | orderMap.get(orderId).setStatus(1);
40 | }
41 |
42 | public void markArrivalCompleteOrder(String orderId){
43 | orderMap.get(orderId).setStatus(2);
44 | }
45 |
46 | public void markPickCompleteOrder(String orderId){
47 | orderMap.get(orderId).setStatus(3);
48 | }
49 |
50 | public void markDeliverCompleteOrder(String orderId){
51 | orderMap.get(orderId).setStatus(4);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/route/Planner.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.route;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.dto.ActionNode;
5 | import dispatch.demo.dto.Courier;
6 | import dispatch.demo.dto.Order;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * @author eleme.demo
12 | * route planner interface
13 | */
14 | public interface Planner {
15 |
16 | /**
17 | * 路径规划
18 | *
19 | * @param courier 给定骑手
20 | * @param order 待规划的单
21 | * @param context 上下文信息
22 | * @return 骑手路径
23 | */
24 | public List plan(Courier courier, Order order, DispatchContext context);
25 | }
26 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/route/TailAppendPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.route;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.dto.ActionNode;
5 | import dispatch.demo.dto.Courier;
6 | import dispatch.demo.dto.Location;
7 | import dispatch.demo.dto.Order;
8 | import dispatch.demo.utils.DistanceUtils;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | /**
15 | * @author eleme.demo
16 | * the courier always append new order to tail
17 | */
18 | public class TailAppendPlan implements Planner {
19 |
20 | @Override
21 | public List plan(Courier courier, Order order, DispatchContext context) {
22 | Location loc;
23 | long planTime;
24 | if (courier.getOrders().isEmpty()) {
25 | loc = courier.getLoc();
26 | planTime = context.getTimeStamp();
27 | } else {
28 | int size = courier.getPlanRoutes().size();
29 | ActionNode lastNode = courier.getPlanRoutes().get(size - 1);
30 | Order lastOrder = context.getOrderPool().getOrderMap().get(lastNode.getOrderId());
31 | loc = lastOrder.getDstLoc();
32 | planTime = lastNode.getActionTime();
33 | }
34 | List tailPlans = planOneOrder(courier, loc, planTime, order);
35 | List appendPlans = new ArrayList<>(courier.getPlanRoutes().size() + tailPlans.size());
36 | appendPlans.addAll(courier.getPlanRoutes());
37 | appendPlans.addAll(tailPlans);
38 | return appendPlans;
39 | }
40 |
41 | private List planOneOrder(Courier courier, Location loc, long planTime, Order order) {
42 | long arrivalTime = planTime + DistanceUtils.timeConsuming(loc, order.getSrcLoc(), courier.getSpeed());
43 | long pickTime = Math.max(order.getEstimatedPrepareCompletedTime(), arrivalTime);
44 | long deliverTime = pickTime + DistanceUtils.timeConsuming(order.getSrcLoc(), order.getDstLoc(), courier.getSpeed());
45 | ActionNode arrivalNode = new ActionNode(order.getId(), 1, arrivalTime, false, planTime);
46 | ActionNode pickNode = new ActionNode(order.getId(), 2, pickTime, false, arrivalTime);
47 | ActionNode deliveryNode = new ActionNode(order.getId(), 3, deliverTime, false, pickTime);
48 | return Arrays.asList(arrivalNode, pickNode, deliveryNode);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/ActionNode.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author eleme.demo
10 | */
11 | @Data
12 | @AllArgsConstructor
13 | @NoArgsConstructor
14 | public class ActionNode {
15 |
16 | /** 运单ID */
17 | private String orderId;
18 |
19 | /**
20 | * 1 到店完成
21 | * 2 取完成
22 | * 3 送完成
23 | */
24 | private int actionType;
25 |
26 | /** 预计发生时刻 */
27 | private long actionTime;
28 |
29 | /** 是否已提交 */
30 | @JSONField(serialize = false)
31 | private boolean isSubmitted = false;
32 |
33 | /** 该动作需提交的时间,如果晚于该时间提交,可能造成评测系统判断骑手无法到达该点 */
34 | @JSONField(serialize = false)
35 | private long needSubmitTime = -1L;
36 |
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Courier.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * @author eleme.demo
12 | */
13 | @Data
14 | public class Courier {
15 | private String areaId;
16 | private String id;
17 | private Location loc;
18 | private Double speed;
19 | private Integer maxLoads;
20 |
21 | @JSONField(serialize = false)
22 | private List planRoutes = new ArrayList<>(0);
23 |
24 | @JSONField(serialize = false)
25 | private List orders = new ArrayList<>(0);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/CourierPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * @author eleme.demo
11 | */
12 | @Data
13 | public class CourierPlan {
14 | private String courierId;
15 | private List planRoutes;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchRequest.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author eleme.demo
10 | */
11 | @Data
12 | public class DispatchRequest {
13 | private long requestTime;
14 | private String areaId;
15 | private boolean isFirstRound;
16 | private boolean isLastRound;
17 | private List couriers;
18 | private List orders;
19 | }
20 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchSolution.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author eleme.demo
9 | */
10 | @Data
11 | public class DispatchSolution {
12 | private List courierPlans;
13 | }
14 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Location.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author eleme.demo
7 | */
8 | @Data
9 | public class Location {
10 | private Double latitude;
11 | private Double longitude;
12 | }
13 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Order.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 |
10 | @Data
11 | public class Order {
12 | private String areaId;
13 | private String id;
14 | private Location srcLoc;
15 | private Location dstLoc;
16 | private long createTime;
17 | private long promiseDeliverTime;
18 | private long estimatedPrepareCompletedTime;
19 |
20 | /**
21 | * 0 dispatching
22 | * 1 goingRst
23 | * 2 picking
24 | * 3 delivering
25 | * 4 complete
26 | */
27 | @JSONField(serialize = false)
28 | int status = 0;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Response.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | @Data
10 | public class Response {
11 |
12 | private int code;
13 | private T result;
14 | private String message;
15 |
16 |
17 | public Response(T result) {
18 | this.code = 200;
19 | this.result = result;
20 | }
21 |
22 | public Response(int code, T result, String message) {
23 | this.code = code;
24 | this.result = result;
25 | this.message = message;
26 | }
27 |
28 | public Response(int code, T result) {
29 | this.code = code;
30 | this.result = result;
31 | }
32 |
33 | public static Response NewErrResponse(String message) {
34 | return new Response(500, message);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/utils/DistanceUtils.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.utils;
2 |
3 |
4 | import dispatch.demo.dto.Location;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | public class DistanceUtils {
10 |
11 | /**
12 | * 地球半径
13 | */
14 | private static final double RADIUS = 6367000.0;
15 |
16 | /**
17 | * 导航距离/路面距离 经验系数
18 | */
19 | private static final double COEFFICIENT = 1.4;
20 |
21 |
22 | public static int timeConsuming(Location from, Location to, double speed) {
23 | return (int) Math.ceil(getDistance(from, to) / speed);
24 | }
25 |
26 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */
27 | public static double getDistance(Location from, Location to) {
28 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT;
29 | }
30 |
31 | /** 简化版球面距离 */
32 | private static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) {
33 | // 经度差值
34 | double deltaLng = lng2 - lng1;
35 | // 纬度差值
36 | double deltaLat = lat2 - lat1;
37 | // 平均纬度
38 | double b = (lat1 + lat2) / 2.0;
39 | // 东西距离
40 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b));
41 | // 南北距离
42 | double y = RADIUS * Math.toRadians(deltaLat);
43 | // 用平面的矩形对角距离公式计算总距离
44 | return Math.sqrt(x * x + y * y);
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/src/test/java/dispatch/dispatchdemo/DispatchDemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package dispatch.dispatchdemo;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class DispatchDemoApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/dispatch-demo/target/dispatch-demo.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/target/dispatch-demo.jar
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/open_test/680507/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186
3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315
4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063
5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515
6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103
7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833
8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094
9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752
10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313
11 | 680507 1208264316 1575684848 11 3.026112456289089 40.451155 102.707619
12 | 680507 1222639031 1575683467 8 3.546382437049226 40.450959000000005 102.713936
13 | 680507 1734975658 1575684248 3 3.704858788960522 40.438719 102.709014
14 | 680507 116322334 1575685027 11 3.13533821514342 40.451766 102.708254
15 | 680507 1672528308 1575681727 9 2.9713525964966485 40.452513 102.708735
16 | 680507 112845496 1575679027 3 3.8483245919491025 40.477753 102.69838299999999
17 | 680507 117879616 1575682507 12 2.951266669813286 40.471816 102.706665
18 | 680507 1498386500 1575684067 9 2.9499812409610935 40.450167 102.721127
19 | 680507 1641767011 1575681487 9 2.2825539266226222 40.451039 102.713886
20 | 680507 1403535350 1575682507 14 2.8481381075161396 40.476379 102.7112
21 | 680507 1691267820 1575682267 8 3.248321005542984 40.452329 102.708221
22 | 680507 115919319 1575677706 11 2.79297577504939 40.445732 102.719816
23 | 680507 1501461921 1575682807 10 3.336964136657864 40.451084 102.707528
24 | 680507 119056946 1575683347 9 2.4996290528183382 40.451015000000005 102.707634
25 | 680507 1739955571 1575683407 2 2.034439127338177 40.437531 102.71731199999999
26 | 680507 1739635429 1575680767 1 3.565758995409262 40.44531 102.72065699999999
27 | 680507 1704858710 1575678667 7 2.6817540792350334 40.445347 102.719949
28 | 680507 1260738882 1575682687 10 2.716981986023813 40.469231 102.711462
29 | 680507 118350282 1575683347 9 3.1410202954437145 40.450942 102.713872
30 | 680507 1100384890 1575678247 12 3.1739785164893477 40.432919 102.695546
31 | 680507 1243561117 1575681487 8 3.670216712496116 40.452275 102.708763
32 | 680507 1561488920 1575682987 10 2.970246575553227 40.443556 102.69686899999999
33 | 680507 1390049525 1575684367 10 2.729634861374282 40.45082 102.707702
34 | 680507 1604576185 1575677167 10 3.068057263223962 40.468577 102.721584
35 | 680507 1734008360 1575684608 5 2.8149660796620615 40.444188 102.719844
36 | 680507 1340930725 1575677647 8 3.0853481200407105 40.449676000000004 102.718729
37 | 680507 1680551613 1575684067 9 3.5419144511514684 40.467838 102.72192199999999
38 | 680507 1742712882 1575681187 1 2.469981468674661 40.445187 102.72061
39 | 680507 1663491750 1575682387 9 2.91739756865818 40.450008000000004 102.707255
40 | 680507 1646693599 1575678307 9 3.0540291748278556 40.451739 102.71054
41 | 680507 1353313828 1575679927 10 3.1144211901270675 40.422092 102.684789
42 | 680507 1724835943 1575683587 6 2.527793854772829 40.440612 102.696155
43 | 680507 1669429740 1575684308 9 2.3571432025488197 40.447069 102.706948
44 | 680507 1479565240 1575681727 10 3.8045368692139583 40.451286 102.707625
45 | 680507 1625244485 1575684067 10 3.1205103631990765 40.468387 102.72151099999999
46 | 680507 1536359470 1575681067 10 2.949029183367058 40.445296 102.720787
47 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/open_test/725011/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 725011 1221280480 1575597549 11 3.0745467228136714 45.525371 103.662065
3 | 725011 113495157 1575591308 9 3.167722576151949 45.525573 103.648644
4 | 725011 1177503829 1575591308 12 3.6814195786682338 45.507856 103.662758
5 | 725011 1418952335 1575592808 10 3.8148912684766367 45.508578 103.648323
6 | 725011 1479538753 1575597129 11 2.832166129898812 45.54217 103.765009
7 | 725011 1622320859 1575592028 10 2.7767326358596005 45.543176 103.664697
8 | 725011 1307048619 1575594788 12 2.8811465775570624 45.507928 103.662966
9 | 725011 1657676623 1575594668 10 2.5084512136962984 45.554701 103.657823
10 | 725011 1646283965 1575591308 10 3.0709960737781836 45.517871 103.65811
11 | 725011 1246670853 1575594608 14 3.4073109270143678 45.5041 103.656093
12 | 725011 1307083020 1575591308 6 3.104167614990719 45.513523 103.646522
13 | 725011 1477839296 1575597609 11 3.1340188990585176 45.512018 103.645563
14 | 725011 1687180658 1575591308 9 3.379602154676791 45.496864 103.656408
15 | 725011 1500903736 1575591308 8 3.109008402113315 45.519959 103.637448
16 | 725011 1353832676 1575591668 12 2.9546278702091184 45.511084999999994 103.644226
17 | 725011 1469955904 1575591308 11 3.0431526726710088 45.50816 103.64672
18 | 725011 1250625037 1575591308 11 3.661297496606512 45.551017 103.658541
19 | 725011 1708425173 1575594128 7 2.8936645508515455 45.504822 103.64859100000001
20 | 725011 117244729 1575591548 8 3.745552874657883 45.507824 103.645524
21 | 725011 1622630002 1575595388 9 2.963381002287524 45.504607 103.652491
22 | 725011 1718265946 1575591908 8 3.2081500612724017 45.505793 103.648939
23 | 725011 1428083383 1575597309 13 3.4342418182588115 45.507699 103.661904
24 | 725011 1740484365 1575591308 1 3.1094414507277928 45.503514 103.663348
25 | 725011 1322529855 1575598449 9 3.4050049348521942 45.531061 103.647813
26 | 725011 1439011135 1575596649 10 3.170385812345891 45.50482 103.64859
27 | 725011 1734801322 1575591308 1 3.592799987069256 45.523335 103.648163
28 | 725011 1306666525 1575592568 11 3.059979859801288 45.531393 103.646792
29 | 725011 1584116537 1575591308 11 3.2326875812877685 45.507525 103.66171999999999
30 | 725011 114861767 1575598329 11 2.475249549190708 45.530645 103.648613
31 | 725011 1374788376 1575596349 12 3.377776328431921 45.507581 103.662041
32 | 725011 1287988348 1575602530 9 2.9140317765060852 45.527784000000004 103.661967
33 | 725011 1229044106 1575596169 6 2.261752965694964 45.512402 103.646282
34 | 725011 1680584174 1575591308 11 3.3716508780335053 45.521201 103.735459
35 | 725011 1137142537 1575598689 13 2.5892511698971408 45.541044 103.764013
36 | 725011 1642469864 1575591308 10 2.9722152944598874 45.523423 103.647972
37 | 725011 1254126910 1575591308 12 3.5647529504247255 45.507671 103.662028
38 | 725011 1237370576 1575596829 11 2.2297466450026837 45.513449 103.64869499999999
39 | 725011 1483094823 1575594908 11 3.7245840037730424 45.531253 103.64790500000001
40 | 725011 116287873 1575596349 11 2.41609808281589 45.501467 103.649249
41 | 725011 1603283203 1575595088 11 2.4171289591815524 45.508598 103.64837
42 | 725011 116752187 1575593288 11 2.856048911631838 45.520815 103.672229
43 | 725011 1495968351 1575591308 7 2.62466373517706 45.519472 103.638761
44 | 725011 1465546313 1575593828 11 2.908179066810375 45.511649 103.64427
45 | 725011 1642502425 1575600490 10 2.476718914322433 45.508105 103.646757
46 | 725011 1488524697 1575591308 7 3.1676446655060837 45.519224 103.641553
47 | 725011 115798791 1575599770 11 3.3014032247058434 45.514319 103.657326
48 | 725011 1287312067 1575591308 11 3.327427169310638 45.503823 103.66471
49 | 725011 1455084424 1575591308 11 3.1779898636537602 45.509151 103.64779
50 | 725011 1578881944 1575591308 10 3.6704894172748053 45.504233 103.655686
51 | 725011 1225769277 1575591308 11 3.242736489317296 45.530623 103.64749300000001
52 | 725011 1369995808 1575594368 9 3.0851662723791407 45.522729 103.643674
53 | 725011 1351295452 1575591308 10 3.344949353729399 45.514637 103.640763
54 | 725011 9028621 1575591308 7 3.350064118615471 45.499027000000005 103.654729
55 | 725011 1288750515 1575594548 9 2.706344400464836 45.50639 103.652383
56 | 725011 1360505717 1575594668 10 2.4994046906154845 45.554599 103.660969
57 | 725011 1387554021 1575595028 10 3.862021614383592 45.502163 103.65689300000001
58 | 725011 1244300839 1575591308 11 3.72014055841659 45.522973 103.664045
59 | 725011 115409365 1575591308 11 3.2135177692361996 45.530241 103.647946
60 | 725011 1501232069 1575591308 10 2.815186434932678 45.503602 103.656244
61 | 725011 1727665226 1575591308 4 3.050129780749418 45.527034 103.647473
62 | 725011 1307188096 1575591308 11 3.1440525066088196 45.514282 103.641467
63 | 725011 7960820 1575591728 7 3.2582422818676298 45.517493 103.665589
64 | 725011 1397564024 1575591308 13 3.4927502613980366 45.50346 103.66055
65 | 725011 1656032959 1575594428 10 3.0853410337771607 45.509891 103.647035
66 | 725011 113560243 1575594128 10 3.4392512368587513 45.509642 103.647185
67 | 725011 1718794740 1575600850 7 2.6709509184430917 45.51397 103.661188
68 | 725011 1131552518 1575597369 10 2.654692060202425 45.523501 103.657944
69 | 725011 1421636152 1575596049 10 2.3117626821830846 45.504822999999995 103.64858000000001
70 | 725011 111460869 1575591308 8 2.759435631046959 45.525423 103.648512
71 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/open_test/730221/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 730221 1374270581 1575507758 9 3.0855756624075665 47.846135 103.45929100000001
3 | 730221 1219549877 1575511179 8 2.735835929651148 47.826640000000005 103.463714
4 | 730221 10362332 1575508418 8 3.3254622249269596 47.844551 103.393856
5 | 730221 1542508376 1575507518 10 3.1019804970568075 47.823334 103.471177
6 | 730221 1255986534 1575504878 9 2.756974127718802 47.828238 103.47454599999999
7 | 730221 116232492 1575508118 12 2.8297521465887914 47.82338 103.471088
8 | 730221 1438422421 1575509919 9 3.272551333258363 47.824993000000006 103.474819
9 | 730221 1719029443 1575507518 7 3.136633049048524 47.82363599999999 103.471125
10 | 730221 117392228 1575508778 9 3.4669860107852886 47.844689 103.459914
11 | 730221 1101190254 1575507338 10 3.8612638902439116 47.788332000000004 103.490189
12 | 730221 1533383487 1575508478 9 2.937137118458426 47.846368 103.459956
13 | 730221 116794113 1575505778 10 2.884703152256932 47.82363700000001 103.473532
14 | 730221 1303854304 1575508478 9 2.160099560075172 47.826007 103.463852
15 | 730221 1247414713 1575507578 9 2.788878708059746 47.823733 103.470837
16 | 730221 1531451263 1575509558 7 2.6897679187876915 47.823212 103.472229
17 | 730221 111342785 1575507878 9 2.957880472090308 47.836821 103.46289
18 | 730221 1682849560 1575509018 9 3.241013777926264 47.844787 103.45992
19 | 730221 1303878770 1575508598 10 3.3466503598224784 47.84734 103.461474
20 | 730221 1120065698 1575509138 9 2.7014314447421595 47.82511 103.463588
21 | 730221 10792789 1575508838 9 3.0827844146835695 47.844640000000005 103.45992
22 | 730221 117381435 1575505958 9 3.7629232745587236 47.823979 103.459474
23 | 730221 1303865484 1575506318 9 2.808289608338827 47.819551 103.465743
24 | 730221 110925020 1575509018 10 3.1668466386711596 47.84747900000001 103.460404
25 | 730221 1651978273 1575507518 8 2.4506182303580224 47.85174000000001 103.441963
26 | 730221 1164400013 1575506078 11 2.964001712330374 47.741595 103.468632
27 | 730221 1408109501 1575507158 9 3.2041788375567806 47.845499 103.459825
28 | 730221 118079460 1575509018 10 2.799603052382247 47.828739 103.47914200000001
29 | 730221 1311564690 1575504878 5 3.417007067974616 47.819253 103.4647
30 | 730221 1246047812 1575506738 11 2.958634651537811 47.84433799999999 103.394124
31 | 730221 1405204799 1575507878 9 3.036288073194167 47.837857 103.462714
32 | 730221 112555471 1575504878 11 3.058366006647499 47.821502 103.475454
33 | 730221 1519023207 1575504998 8 3.2949759474592866 47.844191 103.45954
34 | 730221 118896621 1575508538 9 2.6746718243901983 47.824197 103.47114300000001
35 | 730221 1243531992 1575504878 10 2.227462886485577 47.823415000000004 103.474312
36 | 730221 1225017311 1575509858 9 3.1169436831693504 47.824902 103.463851
37 | 730221 1150409328 1575504878 12 3.271827101878319 47.824758 103.471802
38 | 730221 117547592 1575508478 9 3.3856157294826255 47.823253 103.471598
39 | 730221 1233874607 1575504878 9 2.7118212357395577 47.823877 103.465486
40 | 730221 113850365 1575508658 10 2.189624388590529 47.843824 103.39528100000001
41 | 730221 1288945870 1575508898 11 3.098248949321933 47.824986 103.464715
42 | 730221 1303855272 1575506018 9 2.724410324420489 47.82703600000001 103.462849
43 | 730221 1436529449 1575508238 8 3.1714894832694034 47.823324 103.471049
44 | 730221 1303888099 1575508058 8 3.417693007938824 47.825124 103.486324
45 | 730221 116307064 1575508598 9 3.1963192009026438 47.824628 103.471935
46 | 730221 1300728100 1575505958 9 2.1140643596565374 47.825008000000004 103.465214
47 | 730221 7974530 1575505358 10 2.8990507440059408 47.822896 103.474005
48 | 730221 1360627504 1575508298 8 2.819111820894523 47.82342 103.470958
49 | 730221 1273313638 1575509078 8 2.5975482704031503 47.822659 103.468022
50 | 730221 1223524751 1575507638 9 3.527847028865668 47.823756 103.470972
51 | 730221 1703976777 1575504878 7 4.025214851828238 47.825114 103.46357900000001
52 | 730221 10669200 1575504878 9 3.7352047673609468 47.823370000000004 103.47205799999999
53 | 730221 1158047816 1575505598 10 2.8880841553476055 47.823678 103.475251
54 | 730221 7971553 1575506618 10 3.0950750096727178 47.825406 103.465599
55 | 730221 1118702233 1575507518 11 2.9743917491841323 47.827329999999996 103.459721
56 | 730221 116251331 1575508478 10 2.391277502357789 47.843587 103.395451
57 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | dispatch
8 | dispatch
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | dispatch-api
13 |
14 |
15 |
16 |
17 |
18 | org.projectlombok
19 | lombok
20 | 1.18.12
21 |
22 |
23 |
24 | com.alibaba
25 | fastjson
26 | 1.2.68
27 |
28 |
29 |
30 | org.slf4j
31 | slf4j-api
32 | 1.7.30
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | maven-compiler-plugin
43 | 3.1
44 |
45 | 1.8
46 | 1.8
47 | -Xlint:all
48 | -parameters
49 | true
50 | true
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ## Specify $JAVA_HOME as you need.
4 | if [ -z "$JAVA_HOME" ] ; then
5 | JAVA_HOME="/data/jdk11.0.2"
6 | fi
7 |
8 | echo $JAVA_HOME
9 |
10 | cd /data
11 |
12 | cpu=8
13 | GC_PARALLEL_THREAD=`expr $((cpu*5/8))`
14 | GC_CONC_THREAD=`expr $((cpu*5/8/4+1))`
15 |
16 | MEM_OPTS="-server -Xms12g -Xmx12g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m"
17 |
18 | G1_OPTS="-XX:+UnlockExperimentalVMOptions -XX:G1RSetUpdatingPauseTimePercent=5 -XX:InitiatingHeapOccupancyPercent=33 -XX:G1NewSizePercent=35 -XX:G1MaxNewSizePercent=50 -XX:+AlwaysPreTouch -XX:-ParallelRefProcEnabled"
19 | G1_OPTS="$G1_OPTS -XX:ParallelGCThreads=$GC_PARALLEL_THREAD -XX:ConcGCThreads=$GC_CONC_THREAD"
20 | G1_OPTS="$G1_OPTS -XX:ReservedCodeCacheSize=128m -XX:+PrintCodeCache"
21 |
22 | $JAVA_HOME/bin/java $MEM_OPTS $G1_OPTS -jar dispatch-demo.jar 2>&1 &
23 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200420/start_judge.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | ## Specify $JAVA_HOME as you need.
3 | if [ -z "$JAVA_HOME" ] ; then
4 | JAVA_HOME="/data/jdk11.0.2"
5 | fi
6 |
7 | echo $JAVA_HOME
8 |
9 | $JAVA_HOME/bin/java -server -Xms1g -Xmx1g -jar dispatch-judge-jar-with-dependencies.jar "$MOCK_DATA_DIR" "$API_SERVER"
10 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | __pycache__
3 | dispatch-demo/dispatch-demo.iml
4 | dispatch-server/dispatchserver.iml
5 | dispatch-demo-py/dispatch-demo-py.iml
6 | dispatch-demo-py/venv
7 | dispatch-demo-go/dispatch-demo-go.iml
8 | target/
9 | dispatch-api/target
10 | dispatch-demo/target
11 | dispatch-server/target
12 | *.iml
13 | dispatch-demo-go/go.sum
14 |
15 | .DS_Store
16 | dispatch-demo-py/demo/__init__.pyc
17 | dispatch-demo-py/demo/dto.pyc
18 | jdk11.tar.gz
19 | go1.14.1.linux-amd64.tar.gz
20 | dispatch-demo-py/build/
21 | dispatch-demo-go/dispatch-demo-go
22 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/python:3
2 | #FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
3 | MAINTAINER annoymous
4 |
5 | WORKDIR /
6 |
7 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在start.sh中指定$JAVA_HOME
8 | # ADD jdk11.tar.gz /data
9 | # 根据需要打包
10 | #ADD go1.14.1.linux-amd64.tar.gz /data
11 |
12 | # 安装JDK13
13 |
14 | ENV LANG=en_US.UTF-8
15 | ENV JAVA_HOME=/usr/java/openjdk-13
16 | ENV PATH=/usr/java/openjdk-13/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
17 | ENV JAVA_VERSION=13.0.2
18 | # ENV JAVA_URL=https://download.java.net/java/GA/jdk13.0.2/d4173c853231432d94f001e99d882ca7/8/GPL/openjdk-13.0.2_linux-x64_bin.tar.gz
19 | ENV JAVA_SHA256=acc7a6aabced44e62ec3b83e3b5959df2b1aa6b3d610d58ee45f0c21a7821a71
20 | COPY openjdk.tgz /
21 | RUN echo "$JAVA_SHA256 */openjdk.tgz" | sha256sum -c -; mkdir -p "$JAVA_HOME"; tar --extract --file /openjdk.tgz --directory "$JAVA_HOME" --strip-components 1; rm /openjdk.tgz; ln -sfT "$JAVA_HOME" /usr/java/default; ln -sfT "$JAVA_HOME" /usr/java/latest; java -Xshare:dump; java --version; javac --version
22 |
23 |
24 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话,
25 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令
26 | COPY dispatch-demo-py /dispatch-demo-py
27 |
28 | # 按照start.sh文件中说明,提供start.sh 脚本
29 | COPY run_py.sh /
30 |
31 | RUN cp /run_py.sh /run.sh && pip3 install flask jinja2
32 |
33 | EXPOSE 8080
34 |
35 | RUN chmod u+x /run.sh
36 |
37 | CMD ["/bin/bash","/run.sh", "jshell"]
38 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/DockerfileJ:
--------------------------------------------------------------------------------
1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
2 | MAINTAINER annoymous
3 |
4 | WORKDIR /
5 |
6 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在start.sh中指定$JAVA_HOME
7 | #ADD jdk11.tar.gz /data
8 | # 根据需要打包
9 | #ADD go1.14.1.linux-amd64.tar.gz /data
10 |
11 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话,
12 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令
13 | COPY dispatch-demo/target/dispatch-demo.jar /
14 |
15 | # 按照start.sh文件中说明,提供start.sh 脚本
16 | COPY run.sh /
17 |
18 | EXPOSE 8080
19 |
20 | RUN chmod u+x /run.sh
21 |
22 | CMD ["/bin/bash","/run.sh"]
23 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all build build-java build-py build-go build-image build-image-judge clean clean-java clean-py clean-go
2 |
3 | NOW=$(shell date '+%Y-%m-%d_%H:%M:%S')
4 | USER=${shell whoami}
5 |
6 | all: build
7 |
8 | build: build-java build-py build-go build-image build-image-judge
9 |
10 | clean: clean-java clean-py clean-go
11 |
12 | build-java:
13 | echo "start build java" && \
14 | mvn -f pom.xml clean package install -DskipTests && mvn -f dispatch-demo/pom.xml clean package -DskipTests
15 |
16 | build-py:
17 | echo "start build python" && \
18 | cd dispatch-demo-py && python setup.py build
19 |
20 | build-go:
21 | echo "start build go" && \
22 | cd dispatch-demo-go && go build
23 |
24 | build-image:
25 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} .
26 |
27 | build-image-judge:
28 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} -f DockerfileJudge
29 |
30 | clean-java:
31 | mvn clean && mvn clean -f dispatch-demo/pom.xml
32 |
33 | clean-py:
34 | cd dispatch-demo-py && python setup.py clean && rm -rf dispatch_demo_py.egg-info
35 |
36 | clean-go:
37 | cd dispatch-demo-go && go mod tidy && rm -rf dispatch-demo-go
38 |
39 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/deploy.png
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | dispatch
7 | dispatch
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | tianchi-dispatch-api
13 |
14 |
15 |
16 | org.projectlombok
17 | lombok
18 |
19 |
20 |
21 | com.alibaba
22 | fastjson
23 |
24 |
25 | com.google.guava
26 | guava
27 | 28.1-jre
28 |
29 |
30 | org.apache.commons
31 | commons-lang3
32 | 3.9
33 |
34 |
35 | joda-time
36 | joda-time
37 | 2.10.3
38 |
39 |
40 | org.apache.httpcomponents
41 | httpclient
42 | 4.5.12
43 |
44 |
45 | org.slf4j
46 | slf4j-api
47 |
48 |
49 | ch.qos.logback
50 | logback-classic
51 | 1.2.3
52 |
53 |
54 |
55 | ch.qos.logback
56 | logback-core
57 | 1.2.3
58 |
59 |
60 |
61 | junit
62 | junit
63 | 4.12
64 | test
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | org.apache.maven.plugins
73 | maven-assembly-plugin
74 | 2.5.5
75 |
76 |
77 |
78 | dispatch.judge.DispatchJudge
79 |
80 |
81 |
82 | jar-with-dependencies
83 |
84 |
85 |
86 |
87 | make-assembly
88 | package
89 |
90 | single
91 |
92 |
93 |
94 |
95 |
96 | dispatch-judge
97 |
98 |
99 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/DispatchClient.java:
--------------------------------------------------------------------------------
1 | package dispatch.api;
2 |
3 | import dispatch.api.dto.DispatchRequest;
4 | import dispatch.api.dto.DispatchSolution;
5 | import dispatch.api.dto.Response;
6 | import dispatch.api.exception.DispatchException;
7 |
8 | import java.io.Closeable;
9 |
10 | /**
11 | * @author fangyu.fu
12 | */
13 | public interface DispatchClient extends Closeable {
14 | Response dispatch(DispatchRequest dispatchRequest) throws DispatchException;
15 |
16 | Response ping() throws DispatchException;
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/ActionNode.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ActionNode {
7 | private String orderId;
8 | private int actionType;
9 | private long actionTime;
10 | }
11 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Courier.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 |
7 | @Data
8 | @Accessors(chain = true)
9 | public class Courier {
10 | private String areaId;
11 | private String id;
12 | private Location loc;
13 | private Double speed;
14 | private Integer maxLoads;
15 | }
16 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/CourierPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class CourierPlan {
9 | private String courierId;
10 | private List planRoutes;
11 | }
12 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/DispatchRequest.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.util.List;
7 |
8 | @Data
9 | @Accessors(chain = true)
10 | public class DispatchRequest {
11 | private long requestTime;
12 | private String areaId;
13 | private boolean isFirstRound;
14 | private boolean isLastRound;
15 | private List couriers;
16 | private List orders;
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/DispatchSolution.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class DispatchSolution {
9 | private List courierPlans;
10 | }
11 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Location.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Location {
7 | private Double latitude;
8 | private Double longitude;
9 |
10 | public Location(Double latitude, Double longitude) {
11 | this.latitude = latitude;
12 | this.longitude = longitude;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Order.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | @Data
7 | @Accessors(chain = true)
8 | public class Order {
9 | private String areaId;
10 | private String id;
11 | private Location srcLoc;
12 | private Location dstLoc;
13 | private long createTime;
14 | private long promiseDeliverTime;
15 | private long estimatedPrepareCompletedTime;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Response.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | @Data
7 | @NoArgsConstructor
8 | public class Response {
9 |
10 | private int code;
11 | private T result;
12 | private String message;
13 |
14 |
15 | public Response(T result) {
16 | this.code = 200;
17 | this.result = result;
18 | }
19 |
20 | public Response(int code, T result, String message) {
21 | this.code = code;
22 | this.result = result;
23 | this.message = message;
24 | }
25 |
26 | public Response(int code, T result) {
27 | this.code = code;
28 | this.result = result;
29 | }
30 |
31 | public static Response NewErrResponse(String message) {
32 | return new Response(500, message);
33 | }
34 |
35 | public static Response NewErrResponse(int code, String message) {
36 | return new Response(500, message);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/exception/DispatchException.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.exception;
2 |
3 | public class DispatchException extends Exception {
4 | public DispatchException(int code, String message) {
5 | super(message);
6 | }
7 |
8 | public DispatchException(int code, String message, Throwable t) {
9 | super(message, t);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/impl/HttpDispatchClientImpl.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.impl;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.TypeReference;
5 | import dispatch.api.DispatchClient;
6 | import dispatch.api.dto.DispatchRequest;
7 | import dispatch.api.dto.DispatchSolution;
8 | import dispatch.api.dto.Response;
9 | import dispatch.api.exception.DispatchException;
10 | import lombok.Data;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.apache.http.HttpStatus;
13 | import org.apache.http.client.config.RequestConfig;
14 |
15 | import java.io.Closeable;
16 | import java.io.IOException;
17 |
18 | /**
19 | * @author fangyu.fu
20 | */
21 | @Data
22 | @Slf4j
23 | public class HttpDispatchClientImpl implements DispatchClient, Closeable {
24 |
25 | private static final String DISPATCH_PATH_V1 = "/api/v1/dispatch";
26 | private static final String PING_PATH_V1 = "/api/v1/ping";
27 | private static String DEFAULT_URL = "http://localhost:8080";
28 | private HttpClientManager httpClientManager;
29 |
30 | public HttpDispatchClientImpl(String url) {
31 | httpClientManager = new HttpClientManager(url, 5000, 5000,5000,0);
32 | }
33 |
34 | public HttpDispatchClientImpl() {
35 | httpClientManager = new HttpClientManager(DEFAULT_URL, 5000, 5000, 5000, 0);
36 | }
37 |
38 | public HttpDispatchClientImpl(String url, RequestConfig requestConfig, int retry) {
39 | httpClientManager = new HttpClientManager(url, requestConfig, retry);
40 | }
41 |
42 | @Override
43 | public Response dispatch(DispatchRequest dispatchRequest) throws DispatchException {
44 | try {
45 | return httpClientManager.post(DISPATCH_PATH_V1, JSON.toJSONString(dispatchRequest), (body) ->
46 | JSON.parseObject(body, new TypeReference>() {
47 | })
48 | );
49 | } catch (Exception e) {
50 | log.error("", e);
51 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e);
52 | }
53 | }
54 |
55 | @Override
56 | public Response ping() throws DispatchException {
57 | try {
58 | return httpClientManager.get(PING_PATH_V1, (body) ->
59 | JSON.parseObject(body, new TypeReference>() {
60 | })
61 | );
62 | } catch (Exception e) {
63 | log.error("", e);
64 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e);
65 | }
66 | }
67 |
68 | @Override
69 | public void close() throws IOException {
70 | httpClientManager.close();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/CourierRecord.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Lists;
4 | import dispatch.api.dto.Courier;
5 | import dispatch.api.dto.CourierPlan;
6 | import dispatch.api.dto.Location;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 |
10 | import java.util.List;
11 |
12 | @Getter
13 | public class CourierRecord {
14 | private Courier courier;
15 | @Setter
16 | private Location location;
17 | private Long courierTime;
18 | private List courierPlans;
19 |
20 | public CourierRecord(Courier courier, Long courierTime) {
21 | this.courier = courier;
22 | this.location = courier.getLoc();
23 | this.courierTime = courierTime;
24 | this.courierPlans = Lists.newArrayList();
25 | }
26 |
27 | public void timeChange(Long time) {
28 | if (time > courierTime) {
29 | courierTime = time;
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/DispatchJudge.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import dispatch.api.DispatchClient;
5 | import dispatch.api.impl.HttpDispatchClientImpl;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | import java.io.File;
9 | import java.util.HashMap;
10 |
11 | @Slf4j
12 | public class DispatchJudge {
13 |
14 | public static void main(String[] args) {
15 |
16 | String directory = "";
17 | String api = "http://localhost:8080";
18 | if (args.length > 0) {
19 | directory = args[0];
20 | log.error(String.format("Data directory is %s", directory));
21 | }
22 | if (args.length > 1) {
23 | api = args[1];
24 | log.error(String.format("Api is %s", api));
25 | }
26 | File rootDirectory = new File(directory);
27 | if(!rootDirectory.isDirectory()){
28 | log.error("Input path must be a directory.");
29 | System.exit(1);
30 | }
31 | File[] dataFiles = rootDirectory.listFiles((f)->f.isDirectory() && f.getName().matches("\\d+"));
32 | for(File dataFile:dataFiles){
33 | String orderPath = String.format("%s/%s",dataFile.getAbsolutePath(),"order");
34 | String courierPath = String.format("%s/%s",dataFile.getAbsolutePath(), "courier");
35 | DispatchClient dispatchClient = new HttpDispatchClientImpl(api);
36 | // 从文件读取订单骑士数据
37 | RawData rawData = new RawData(orderPath, courierPath);
38 |
39 | SequentialJudge sequentialJudge = new SequentialJudge(dispatchClient, rawData);
40 | sequentialJudge.doDispatch();
41 |
42 | Score score = sequentialJudge.getScore();
43 | log.error(String.format("AreaId %s overtimeCount: %f", dataFile.getName(), score.getOvertimeCount()));
44 | log.error(String.format("AreaId %s avgDeliveryTime: %f", dataFile.getName(), score.getAvgServiceTime()));
45 | if (score.getIllegalMsg().isIllegal()) {
46 | log.error(String.format("AreaId %s error Msg %s", dataFile.getName(), score.getIllegalMsg().getMsg()));
47 | }
48 | }
49 | //Merge result
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/DispatchLog.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.DispatchRequest;
4 | import dispatch.api.dto.DispatchSolution;
5 | import lombok.Getter;
6 |
7 | @Getter
8 | public class DispatchLog {
9 | private DispatchRequest request;
10 | private DispatchSolution solution;
11 |
12 | public DispatchLog(DispatchRequest request, DispatchSolution solution) {
13 | this.request = request;
14 | this.solution = solution;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/IllegalMsg.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class IllegalMsg {
7 | private boolean illegal;
8 | private String msg = "";
9 |
10 | public IllegalMsg(String msg) {
11 | this.illegal = true;
12 | this.msg = msg;
13 | }
14 |
15 | public IllegalMsg() {
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/JudgeUtil.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.Location;
4 | import org.joda.time.DateTime;
5 |
6 | public class JudgeUtil {
7 | /**
8 | * 地球半径
9 | */
10 | private static final double RADIUS = 6367000.0;
11 |
12 | /**
13 | * 导航距离/路面距离 经验系数
14 | */
15 | private static final double COEFFICIENT = 1.4;
16 |
17 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */
18 | public static double getDistance(Location from, Location to) {
19 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT;
20 | }
21 |
22 | /** 简化版球面距离 */
23 | public static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) {
24 | // 经度差值
25 | double deltaLng = lng2 - lng1;
26 | // 纬度差值
27 | double deltaLat = lat2 - lat1;
28 | // 平均纬度
29 | double b = (lat1 + lat2) / 2.0;
30 | // 东西距离
31 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b));
32 | // 南北距离
33 | double y = RADIUS * Math.toRadians(deltaLat);
34 | // 用平面的矩形对角距离公式计算总距离
35 | return Math.sqrt(x * x + y * y);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/OrderRecord.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import dispatch.api.dto.Order;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class OrderRecord {
8 | private Order order;
9 | private int status;
10 | private boolean overTime;
11 | private Long deliveryTime;
12 |
13 | public OrderRecord(Order order) {
14 | this.order = order;
15 | this.status = 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/RawData.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.google.common.collect.Maps;
5 | import dispatch.api.dto.Courier;
6 | import dispatch.api.dto.Location;
7 | import dispatch.api.dto.Order;
8 | import lombok.Getter;
9 |
10 | import java.io.File;
11 | import java.util.*;
12 |
13 | @Getter
14 | public class RawData {
15 |
16 | private String areaId;
17 | private List orders;
18 | private List couriers;
19 | private Map courierOnlineTime;
20 |
21 | public RawData(String orderFilePath, String courierFilePath) {
22 | this.orders = Lists.newArrayList();
23 | this.couriers = Lists.newArrayList();
24 | this.courierOnlineTime = Maps.newHashMap();
25 |
26 | try {
27 | Scanner orderScanner = new Scanner(new File(orderFilePath));
28 | orderScanner.nextLine();
29 | while (orderScanner.hasNextLine()) {
30 | this.orders.add(orderLine2Order(getRecordFromLine(orderScanner.nextLine())));
31 | }
32 | Scanner courierScanner = new Scanner(new File(courierFilePath));
33 | courierScanner.nextLine();
34 | while (courierScanner.hasNextLine()) {
35 | List courierLine = getRecordFromLine(courierScanner.nextLine());
36 | this.courierOnlineTime.put(courierLine.get(1), Long.parseLong(courierLine.get(2)));
37 | this.couriers.add(courierLine2Courier(courierLine));
38 | }
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | }
42 | this.orders.sort(Comparator.comparingLong(Order::getCreateTime));
43 | this.couriers.sort(Comparator.comparingLong(c -> courierOnlineTime.get(c.getId())));
44 | this.areaId = orders.get(0).getAreaId();
45 | }
46 |
47 |
48 | private static final String COMMA_DELIMITER = "\t";
49 |
50 | private static List getRecordFromLine(String line) {
51 | List values = new ArrayList<>();
52 | try (Scanner rowScanner = new Scanner(line)) {
53 | rowScanner.useDelimiter(COMMA_DELIMITER);
54 | while (rowScanner.hasNext()) {
55 | values.add(rowScanner.next());
56 | }
57 | }
58 | return values;
59 | }
60 |
61 | private static Order orderLine2Order(List orderLine) {
62 | return new Order().setAreaId(orderLine.get(0))
63 | .setId(orderLine.get(1))
64 | .setCreateTime(Long.parseLong(orderLine.get(2)))
65 | .setEstimatedPrepareCompletedTime(Long.parseLong(orderLine.get(3)))
66 | .setPromiseDeliverTime(Long.parseLong(orderLine.get(4)))
67 | .setSrcLoc(new Location(Double.parseDouble(orderLine.get(5)), Double.parseDouble(orderLine.get(6))))
68 | .setDstLoc(new Location(Double.parseDouble(orderLine.get(7)), Double.parseDouble(orderLine.get(8))));
69 | }
70 |
71 | private static Courier courierLine2Courier(List courierLine) {
72 | return new Courier().setAreaId(courierLine.get(0))
73 | .setId(courierLine.get(1))
74 | .setMaxLoads(Integer.parseInt(courierLine.get(3)))
75 | .setSpeed(Double.parseDouble(courierLine.get(4)))
76 | .setLoc(new Location(Double.parseDouble(courierLine.get(5)), Double.parseDouble(courierLine.get(6))));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/Score.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Score {
7 | private IllegalMsg illegalMsg = new IllegalMsg();
8 | private double avgServiceTime;
9 | private double overtimeCount;
10 | private long serviceTimeSum;
11 | private long orderSum;
12 |
13 | public void setIllegalMsg(IllegalMsg illegalMsg) {
14 | this.illegalMsg = illegalMsg;
15 | }
16 |
17 | public void setIllegalMsg(String illegalMsg) {
18 | this.illegalMsg = new IllegalMsg(illegalMsg);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/SequentialJudge.java:
--------------------------------------------------------------------------------
1 | package dispatch.judge;
2 |
3 | import com.google.common.collect.Iterables;
4 | import com.google.common.collect.Lists;
5 | import com.google.common.collect.Queues;
6 | import dispatch.api.DispatchClient;
7 | import dispatch.api.dto.*;
8 | import lombok.Getter;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Queue;
13 |
14 | public class SequentialJudge {
15 | private DispatchClient dispatchClient;
16 | private int intervalSecond;
17 |
18 | private RawData rawData;
19 | private Queue orderQueue;
20 | private Queue courierQueue;
21 |
22 | private long currentTime;
23 | private long endTime;
24 |
25 | @Getter
26 | private Score score;
27 | private List dispatchLogs = new ArrayList<>(0);
28 |
29 |
30 | public SequentialJudge(DispatchClient client, RawData rawData) {
31 | this(client, rawData, 60);
32 | }
33 |
34 | public SequentialJudge(DispatchClient client, RawData rawData, int intervalSecond) {
35 | this.dispatchClient = client;
36 | this.rawData = rawData;
37 | this.intervalSecond = intervalSecond;
38 | this.orderQueue = Queues.newArrayDeque(rawData.getOrders());
39 | this.courierQueue = Queues.newArrayDeque(rawData.getCouriers());
40 | this.score = new Score();
41 |
42 | this.currentTime = orderQueue.element().getCreateTime() + intervalSecond;
43 | this.endTime = Iterables.getLast(rawData.getOrders()).getCreateTime();
44 |
45 | }
46 |
47 | public void doDispatch() {
48 | DispatchContext dispatchContext = new DispatchContext();
49 | boolean isFirstRound = true;
50 | while (currentTime <= endTime) {
51 | DispatchRequest request = new DispatchRequest()
52 | .setAreaId(rawData.getAreaId())
53 | .setRequestTime(currentTime);
54 |
55 | List dispatchingOrders = Lists.newArrayList();
56 | List onlineCourier = Lists.newArrayList();
57 | while (!orderQueue.isEmpty() && orderQueue.element().getCreateTime() <= currentTime) {
58 | dispatchingOrders.add(orderQueue.remove());
59 | }
60 | while (!courierQueue.isEmpty() &&
61 | rawData.getCourierOnlineTime().get(courierQueue.element().getId()) <= currentTime) {
62 | onlineCourier.add(courierQueue.remove());
63 | }
64 |
65 | request.setCouriers(onlineCourier);
66 | request.setOrders(dispatchingOrders);
67 |
68 | currentTime += intervalSecond;
69 | request.setFirstRound(isFirstRound);
70 | request.setLastRound(currentTime > endTime);
71 |
72 | if (isFirstRound) {
73 | isFirstRound = false;
74 | }
75 |
76 | Response solutionResponse;
77 | try {
78 | solutionResponse = dispatchClient.dispatch(request);
79 | } catch (Exception e) {
80 | score.setIllegalMsg(e.getMessage());
81 | return;
82 | }
83 |
84 | if (null == solutionResponse) {
85 | score.setIllegalMsg("no response");
86 | return;
87 | } else if (solutionResponse.getCode() != 200) {
88 | score.setIllegalMsg(solutionResponse.getMessage());
89 | return;
90 | } else {
91 | DispatchLog dispatchLog = new DispatchLog(request, solutionResponse.getResult());
92 | this.dispatchLogs.add(dispatchLog);
93 | IllegalMsg illegalMsg = dispatchContext.allocate(dispatchLog);
94 | if (illegalMsg.isIllegal()) {
95 | score.setIllegalMsg(illegalMsg.getMsg());
96 | return;
97 | }
98 | }
99 | }
100 | this.score = dispatchContext.checkAndScore();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-api/src/test/java/dispatch/api/impl/HttpDispatchClientImplTest.java:
--------------------------------------------------------------------------------
1 | package dispatch.api.impl;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import dispatch.api.DispatchClient;
5 | import dispatch.api.exception.DispatchException;
6 | import dispatch.judge.DispatchJudge;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.junit.AfterClass;
9 | import org.junit.BeforeClass;
10 | import org.junit.Test;
11 |
12 | import java.io.IOException;
13 | import java.util.HashMap;
14 |
15 | import static org.junit.Assert.assertEquals;
16 |
17 | @Slf4j
18 | public class HttpDispatchClientImplTest {
19 | private static DispatchClient dispatchClient;
20 |
21 | @BeforeClass
22 | public static void init() {
23 | dispatchClient = new HttpDispatchClientImpl();
24 | }
25 |
26 | @AfterClass
27 | public static void destroy() throws IOException {
28 | dispatchClient.close();
29 | }
30 |
31 | @Test
32 | public void testPing() throws DispatchException, InterruptedException {
33 | log.error(String.format("%s", JSON.toJSON(new DispatchJudge())));
34 | assertEquals(dispatchClient.ping().getResult(), "PONG");
35 | Thread.sleep(100);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/cmd.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "github.com/sirupsen/logrus"
5 | "github.com/spf13/cobra"
6 | "os"
7 | "os/signal"
8 | "syscall"
9 | )
10 |
11 | var (
12 | debug bool
13 | clientId string
14 | shutdownWaitSecs int
15 | )
16 |
17 | func init() {
18 | Cmd.PersistentFlags().BoolVar(&debug, "debug", true, "debug mode")
19 | Cmd.PersistentFlags().StringVar(&clientId, "clientId", "", "Id of your tianchi account")
20 | Cmd.PersistentFlags().IntVar(&shutdownWaitSecs, "shutdownWait", 10, "shutdown wait seconds")
21 | }
22 |
23 | var (
24 | // Cmd is the sub command for running as an api server
25 | Cmd = &cobra.Command{
26 | Use: "run",
27 | Short: "Start player's dispatching http server at port 8080.",
28 | Long: "Start player's dispatching http server at port 8080.",
29 | Run: func(cmd *cobra.Command, args []string) {
30 | if debug {
31 | logrus.SetLevel(logrus.DebugLevel)
32 | }
33 |
34 | server, err := NewServer(shutdownWaitSecs, debug, clientId)
35 | if err != nil {
36 | logrus.Fatalf("Starting player's server failed: %v\n", err)
37 | }
38 |
39 | err = server.Start()
40 | if err != nil {
41 | logrus.Fatalf("Starting player's server failed: %v\n", err)
42 | }
43 |
44 | signals := make(chan os.Signal)
45 | signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
46 | <-signals
47 | err = server.Shutdown()
48 | if err != nil {
49 | logrus.Fatalf("Shutdown client server failed: %v\n", err)
50 | }
51 | },
52 | }
53 | )
54 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/dispatcher.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | type Dispatcher interface {
4 | Ping() string
5 | Dispatch(request *DispatchRequest) ([]DispatchSolution, error)
6 | }
7 |
8 | type GreedyDispatcher struct {
9 | routes []DispatchSolution
10 | }
11 |
12 | func NewGreedyDispatcher() *GreedyDispatcher {
13 | return &GreedyDispatcher{}
14 | }
15 |
16 | func (*GreedyDispatcher) Ping() string {
17 | return "PONG"
18 | }
19 |
20 | func (*GreedyDispatcher) Dispatch(request *DispatchRequest) ([]DispatchSolution, error) {
21 | return nil, nil
22 | }
23 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/dto.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | const (
4 | Status_OK = 200
5 | Status_BAD_REQUEST = 400
6 | Status_UNKNOWN = 500
7 | Status_TIMEOUT = 510
8 | )
9 |
10 | type ActionNode struct {
11 | OrderId string `json:"orderId"`
12 | ActionType int `json:"actionType"`
13 | ActionTimestamp int64 `json:"ActionTimestamp"`
14 | }
15 |
16 | type Location struct {
17 | Latitude float64 `json:"latitude"`
18 | Longitude float64 `json:"longitude"`
19 | }
20 |
21 | type Courier struct {
22 | AreaId string `json:"areaId"`
23 | Id string `json:"id"`
24 | Loc *Location `json:"loc"`
25 | Speed float64 `json:speed`
26 | MaxLoads int `json:"maxLoads"`
27 | }
28 |
29 | type CourierPlan struct {
30 | CourierId string `json:"courierId"`
31 | PlanRoutes []ActionNode `json:planRoutes`
32 | }
33 |
34 | type Order struct {
35 | AreaId string `json:"areaId"`
36 | Id string `json:"id"`
37 | SrcLoc *Location `json:"srcLoc"`
38 | DstLoc *Location `json:"dstLoc"`
39 | Status int `json:"status"`
40 | CreateTimestamp int64 `json:"createTimestamp"`
41 | PromiseDeliverTime int64 `json:"promiseDeliverTime"`
42 | EstimatedPrepareCompletedTimestamp int64 `json:"estimatedPrepareCompletedTimestamp"`
43 | }
44 |
45 | type DispatchRequest struct {
46 | RequestTimestamp int64 `json:"requestTimestamp"`
47 | AreaId string `json:"areaId"`
48 | IsFirstRound bool `json:"isFirstRound"`
49 | IsLastRound bool `json:"isLastRound"`
50 | Couriers []Courier `json:"couriers"`
51 | Orders []Order `json:"orders"`
52 | }
53 |
54 | type DispatchSolution struct {
55 | CourierPlans []CourierPlan `json:"courierPlans"`
56 | }
57 |
58 | type Response struct {
59 | Code int `json:"code"`
60 | Result interface{} `json:"result"`
61 | Message string `json:"message"`
62 | }
63 |
64 | func NewResponse(v interface{}) *Response {
65 | return &Response{
66 | Code: Status_OK,
67 | Result: v,
68 | Message: "",
69 | }
70 | }
71 |
72 | func NewErrorResponse(code int, message string) *Response {
73 | return &Response{
74 | Code: code,
75 | Message: message,
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/log.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/sirupsen/logrus"
6 | "io"
7 | "time"
8 | )
9 |
10 | func Logger(writer io.Writer, debug bool) *logrus.Logger {
11 | logger := logrus.New()
12 | logger.Out = writer
13 | if debug {
14 | logger.SetLevel(logrus.DebugLevel)
15 | }
16 | return logger
17 | }
18 |
19 | func NewLogger(writer io.Writer, debug bool) gin.HandlerFunc {
20 | logger := Logger(writer, debug)
21 | return func(c *gin.Context) {
22 | // 开始时间
23 | startTime := time.Now()
24 |
25 | // 处理请求
26 | c.Next()
27 |
28 | // 结束时间
29 | endTime := time.Now()
30 |
31 | // 执行时间
32 | latencyTime := endTime.Sub(startTime)
33 |
34 | // 请求方式
35 | reqMethod := c.Request.Method
36 |
37 | // 请求路由
38 | reqUri := c.Request.RequestURI
39 |
40 | // 状态码
41 | statusCode := c.Writer.Status()
42 |
43 | // 请求IP
44 | clientIP := c.ClientIP()
45 |
46 | //日志格式
47 | logger.Infof("| %3d | %13v | %15s | %s | %s |",
48 | statusCode,
49 | latencyTime,
50 | clientIP,
51 | reqMethod,
52 | reqUri,
53 |
54 | )
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/server.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "context"
5 | "github.com/gin-gonic/gin"
6 | "github.com/pkg/errors"
7 | "github.com/sirupsen/logrus"
8 | "net/http"
9 | "os"
10 | "sync"
11 | "time"
12 | )
13 |
14 | type Server struct {
15 | closeMux *sync.Mutex
16 | port int
17 | debug bool
18 | shutdownWait int
19 | closed bool
20 | logger *logrus.Entry
21 | srv *http.Server
22 | dispatcher Dispatcher
23 | }
24 |
25 | func NewServer(shutdownWait int, debug bool, clientId string) (*Server, error) {
26 | server := &Server{
27 | closeMux: &sync.Mutex{},
28 | debug: debug,
29 | shutdownWait: shutdownWait,
30 | closed: false,
31 | logger: logrus.WithField("client", clientId).WithField("time", time.Now().String()),
32 | dispatcher: NewGreedyDispatcher(),
33 | }
34 | return server, nil
35 | }
36 |
37 | func (server *Server) Start() error {
38 | server.closeMux.Lock()
39 | defer server.closeMux.Unlock()
40 | if server.closed {
41 | return errors.New("Server is closed")
42 | }
43 | r := gin.New()
44 | // Add Log
45 | r.Use(NewLogger(os.Stdout, server.debug))
46 | //Add Recovery
47 | r.Use(gin.Recovery())
48 |
49 | v1 := r.Group("/api/v1")
50 | v1.GET("/ping", func(c *gin.Context) {
51 | server.logger.Info("")
52 | c.JSON(http.StatusOK, server.dispatcher.Ping())
53 | })
54 |
55 | v1.POST("/dispatch", func(c *gin.Context) {
56 | request := &DispatchRequest{}
57 | if err := c.ShouldBind(&request); err == nil {
58 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
59 | defer cancel()
60 | ch := make(chan *Response)
61 | go func() {
62 | response, errs := server.dispatcher.Dispatch(request)
63 | if errs == nil {
64 | ch <- NewResponse(response)
65 | } else {
66 | ch <- NewErrorResponse(Status_UNKNOWN, errs.Error())
67 | }
68 | }()
69 | var response *Response
70 | for {
71 | select {
72 | case <-ctx.Done():
73 | server.logger.Errorf("Request timeout %v",*request)
74 | c.JSON(http.StatusOK, NewErrorResponse(Status_TIMEOUT, "Dispatcher timeout"))
75 | return
76 | case response = <-ch:
77 | server.logger.Infof("Request:%s,Response:%s", *request, *response)
78 | c.JSON(http.StatusOK, response)
79 | return
80 | }
81 | }
82 | } else {
83 | response := NewErrorResponse(
84 | Status_BAD_REQUEST, "Could not resolve request body.",
85 | )
86 | server.logger.Infof("Request:%s,Response:%s", &request, &response)
87 | c.JSON(http.StatusOK, &response)
88 | }
89 | })
90 | srv := &http.Server{
91 | Addr: ":8080",
92 | Handler: r,
93 | }
94 | server.srv = srv
95 | go func() {
96 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
97 | server.logger.Fatalf("listen: %s\n", err)
98 | }
99 | }()
100 | return nil
101 | }
102 |
103 | func (server *Server) Shutdown() error {
104 | server.closeMux.Lock()
105 | defer server.closeMux.Unlock()
106 | if server.closed {
107 | return nil
108 | }
109 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(server.shutdownWait))
110 | defer cancel()
111 | if err := server.srv.Shutdown(ctx); err != nil {
112 | server.logger.Fatal("Server shutdown error:", err)
113 | return err
114 | }
115 | server.closed = true
116 | server.logger.Info("Server exited")
117 | return nil
118 | }
119 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/go.mod:
--------------------------------------------------------------------------------
1 | module gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go
2 |
3 | require (
4 | github.com/gin-gonic/gin v1.4.0
5 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
6 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
7 | github.com/pkg/errors v0.8.0
8 | github.com/sirupsen/logrus v1.5.0
9 | github.com/spf13/cobra v0.0.7
10 | github.com/stretchr/objx v0.1.1 // indirect
11 | github.com/stretchr/testify v1.5.1 // indirect
12 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d // indirect
13 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
14 | gopkg.in/yaml.v2 v2.2.8 // indirect
15 | )
16 |
17 | go 1.12
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-go/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/sirupsen/logrus"
5 | "github.com/spf13/cobra"
6 | "gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go/dispatch"
7 | )
8 |
9 | var rootCmd = &cobra.Command{
10 | Use: "run",
11 | Short: "Tianchi&Eleme Delivery Order Dispatching Contest 2020",
12 | Long: "Tianchi&Eleme Delivery Order Dispatching Contest 2020",
13 | Run: func(cmd *cobra.Command, args []string) {
14 | cmd.Usage()
15 | },
16 | }
17 |
18 | func init() {
19 | rootCmd.AddCommand(dispatch.Cmd)
20 | }
21 | func main() {
22 | logrus.New().Info("demo")
23 | if err := rootCmd.Execute(); err != nil {
24 | logrus.Fatalf("%v", err)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/app.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from flask import Flask, jsonify, request
4 | from demo.service import DispatchService
5 | from demo.dto import DispatchRequest, Location, Order, Courier, Response
6 | import json
7 |
8 | app = Flask(__name__)
9 |
10 |
11 | @app.route('/api/v1/ping', methods=['GET'])
12 | def ping():
13 | pong_result = '{"code":200,"result":"PONG"}'
14 | return pong_result
15 |
16 |
17 | @app.route('/api/v1/score', methods=['GET'])
18 | def score():
19 | score_result = '{"code":200,"result":"PONG"}'
20 | return score_result
21 |
22 |
23 | def toLocation(dct):
24 | latitude = dct['latitude']
25 | longitude = dct['longitude']
26 | return Location(float(latitude), float(longitude))
27 |
28 |
29 | def toDispatchRequest(dct):
30 | courierList = dct['couriers']
31 | courierobjs = []
32 | for courier in courierList:
33 | areaId = courier['areaId']
34 | id = courier['id']
35 | loc = courier['loc']
36 | maxLoads = courier['maxLoads']
37 | speed = courier['speed']
38 | courierobj = Courier(id, areaId, toLocation(loc), float(speed), int(maxLoads))
39 | courierobjs.append(courierobj)
40 | orderList = dct['orders']
41 | orderobjs = []
42 | for order in orderList:
43 | areaId = order['areaId']
44 | createTime = order['createTime']
45 | dstLoc = order['dstLoc']
46 | estimatedPrepareCompletedTime = order['estimatedPrepareCompletedTime']
47 | id = order['id']
48 | promiseDeliverTime = order['promiseDeliverTime']
49 | srcLoc = order['srcLoc']
50 | orderobj = Order(areaId, id, toLocation(srcLoc), toLocation(dstLoc), 0, int(createTime),
51 | int(promiseDeliverTime), int(estimatedPrepareCompletedTime))
52 | orderobjs.append(orderobj)
53 | request = DispatchRequest(int(dct['requestTime']), dct['areaId'], bool(dct['firstRound']), bool(dct['lastRound']),
54 | courierobjs, orderobjs)
55 | return request
56 |
57 |
58 | dispatchService = DispatchService()
59 |
60 |
61 | @app.route('/api/v1/dispatch', methods=['POST'])
62 | def dispatch():
63 | data = request.json
64 | # data is in format of demo.dto.DispatchRequest
65 | # print(data)
66 | # empty_result = """{
67 | # "code":200,
68 | # "result":{
69 | # "courierPlans":[]
70 | # }
71 | # }"""
72 | resultobj = dispatchService.dispatch(toDispatchRequest(data))
73 |
74 | def outputFilter(o):
75 | is_find = False
76 | res: dict = o.__dict__
77 | res = res.copy()
78 | for k in res.keys():
79 | if k == "isSubmitted" or k == "needSubmitTime":
80 | is_find = True
81 | break
82 | if is_find:
83 | del res["isSubmitted"]
84 | del res["needSubmitTime"]
85 | return res
86 |
87 | result = json.dumps(resultobj.__dict__, default=outputFilter, sort_keys=False)
88 | # if result is not None:
89 | # print(result.replace(" ", ""))
90 | responseobj = Response(200, resultobj, "")
91 | response = json.dumps(responseobj.__dict__, default=outputFilter, sort_keys=False)
92 |
93 | return response.replace(" ", "")
94 |
95 |
96 | def local_start(port=8080):
97 | app.run(debug=False, port=port)
98 |
99 |
100 | if __name__ == "__main__":
101 | app.run(debug=False, port=8080)
102 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/__init__.py
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/context.py:
--------------------------------------------------------------------------------
1 | from .dto import Order, Courier, ActionNode
2 | from .pool import OrderPool, CourierPool
3 | from typing import Dict, List
4 |
5 |
6 | class DispatchContext:
7 | def __init__(self, areaId, timeStamp, isEndOfTest=False):
8 | self.areaId = areaId
9 | self.timeStamp = timeStamp
10 | self.isEndOfTest = isEndOfTest
11 |
12 | self.courierPool = CourierPool()
13 | self.orderPool = OrderPool()
14 |
15 | def setTimeStamp(self, timeStamp):
16 | self.timeStamp = timeStamp
17 |
18 | def setIsEndOfTest(self, isEndOfTest):
19 | self.isEndOfTest = isEndOfTest
20 |
21 | def addOnlineCouriers(self, courierList):
22 | self.courierPool.addOnlineCouriers(courierList)
23 |
24 | def addDispatchingOrders(self, orders):
25 | self.orderPool.addDispatchingOrders(orders)
26 |
27 | def markAllocatedOrders(self, orderIds):
28 | for orderId in orderIds:
29 | self.orderPool.markAssignedOrder(orderId)
30 |
31 | def refresh(self, refreshTime):
32 | self.timeStamp = refreshTime
33 | for courier in self.courierPool.couriers:
34 | self.refreshCourier(courier, refreshTime)
35 |
36 | def refreshCourier(self, courier: Courier, refreshTime):
37 | actionNodeList = courier.planRoutes
38 | refreshNodeList: List[ActionNode] = []
39 | for node in actionNodeList:
40 | if node.isSubmitted and node.actionTime <= refreshTime:
41 | if node.actionType == 1:
42 | self.orderPool.markArrivalCompleteOrder(node.orderId)
43 | elif node.actionType == 2:
44 | self.orderPool.markPickCompleteOrder(node.orderId)
45 | elif node.actionType == 3:
46 | self.orderPool.markDeliverCompleteOrder(node.orderId)
47 | else:
48 | refreshNodeList.append(node)
49 | loadOrders = [order for order in courier.orders if order.status != 4]
50 | courier.orders = loadOrders
51 | courier.planRoutes = refreshNodeList
52 | if len(refreshNodeList) == 0 and len(actionNodeList) != 0:
53 | latestOrder: Order = self.orderPool.getOrder(actionNodeList[-1].orderId)
54 | courier.setLoc(latestOrder.dstLoc)
55 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/dto.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List
2 |
3 | class Location(object):
4 | def __init__(self, _latitude, _longitude):
5 | self.latitude = _latitude
6 | self.longitude = _longitude
7 |
8 | def keys(self):
9 | return ['latitude', 'longitude']
10 |
11 | def __getitem__(self, item):
12 | return getattr(self, item)
13 |
14 |
15 | class Courier(object):
16 | def __init__(self, _id, _areaId, _loc, _speed, __maxLoads):
17 | self.id = _id
18 | self.areaId = _areaId
19 | self.loc = _loc
20 | self.speed = _speed
21 | self.maxLoads = __maxLoads
22 |
23 | self.planRoutes: List[ActionNode] = []
24 | self.orders: List[Order] = []
25 |
26 | def keys(self):
27 | return ['id', 'areaId', 'loc', 'speed', 'maxLoads']
28 |
29 | def __getitem__(self, item):
30 | return getattr(self, item)
31 |
32 | def setLoc(self, loc):
33 | self.loc = loc
34 |
35 | def setsetPlanRoutes(self, _planRoutes):
36 | self.planRoutes = _planRoutes
37 |
38 |
39 | class Order(object):
40 | def __init__(self, _areaId, _id, _srcLoc, _dstLoc, _status, _createTimestamp, _promiseDeliverTime,
41 | _estimatedPrepareCompletedTime):
42 | self.areaId = _areaId
43 | self.id = _id
44 | self.srcLoc = _srcLoc
45 | self.dstLoc = _dstLoc
46 | self.status = _status
47 | self.createTimestamp = _createTimestamp
48 | self.promiseDeliverTime = _promiseDeliverTime
49 | self.estimatedPrepareCompletedTime = _estimatedPrepareCompletedTime
50 |
51 | def keys(self):
52 | return ['id', 'areaId', 'srcLoc', 'dstLoc', 'status',
53 | 'createTimestamp', 'promiseDeliverTime', 'estimatedPrepareCompletedTime']
54 |
55 | def __getitem__(self, item):
56 | return getattr(self, item)
57 |
58 | def setStatus(self, status):
59 | self.status = status
60 |
61 |
62 | class ActionNode(object):
63 | def __init__(self, _actionType, _orderId, _actionTimestamp, _isSubmitted, _needSubmitTime):
64 | self.actionTime = _actionTimestamp
65 | self.actionType = _actionType
66 | self.orderId = _orderId
67 | if _isSubmitted is None:
68 | self.isSubmitted = False
69 | else:
70 | self.isSubmitted = _isSubmitted
71 | if _needSubmitTime is None:
72 | self.needSubmitTime = -1
73 | else:
74 | self.needSubmitTime = _needSubmitTime
75 |
76 | def keys(self):
77 | return ['actionType', 'orderId', 'actionTimestamp', 'isSubmitted', 'needSubmitTime']
78 |
79 | def __getitem__(self, item):
80 | return getattr(self, item)
81 |
82 | def setSubmitted(self, _isSubmitted):
83 | self.isSubmitted = _isSubmitted
84 |
85 |
86 | class CourierPlan(object):
87 | def __init__(self, _courierId, _planRoutes):
88 | self.courierId = _courierId
89 | self.planRoutes: List[ActionNode] = _planRoutes
90 |
91 | def keys(self):
92 | return ['courierId', 'planRoutes']
93 |
94 | def __getitem__(self, item):
95 | return getattr(self, item)
96 |
97 |
98 | class DispatchRequest(object):
99 | def __init__(self, _requestTimestamp, _areaId, _isFirstRound, _isLastRound, _couriers, _orders):
100 | self.requestTimestamp = _requestTimestamp
101 | self.areaId = _areaId
102 | self.isFirstRound = _isFirstRound
103 | self.isLastRound = _isLastRound
104 | self.couriers = _couriers
105 | self.orders = _orders
106 |
107 | def keys(self):
108 | return ['requestTimestamp', 'areaId', 'isFirstRound', 'isLastRound',
109 | 'couriers', 'orders']
110 |
111 | def __getitem__(self, item):
112 | return getattr(self, item)
113 |
114 |
115 | class DispatchSolution(object):
116 | def __init__(self, _courierPlans):
117 | self.courierPlans = _courierPlans
118 |
119 | def keys(self):
120 | return ['courierPlans']
121 |
122 | def __getitem__(self, item):
123 | return getattr(self, item)
124 |
125 |
126 | class Response(object):
127 | def __init__(self, _code, _result, _message):
128 | self.code = _code
129 | self.result = _result
130 | self.message = _message
131 |
132 | def keys(self):
133 | return ['code', 'result', 'message']
134 |
135 | def __getitem__(self, item):
136 | return getattr(self, item)
137 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/plan.py:
--------------------------------------------------------------------------------
1 | from .dto import ActionNode, Courier, Order, Location
2 | from .context import DispatchContext
3 | from .util import DistanceUtils
4 | from typing import Dict, List
5 |
6 |
7 | class TailAppendPlan():
8 | def plan(self, courier: Courier, order: Order, context: DispatchContext) -> List[ActionNode]:
9 | if len(courier.orders) == 0:
10 | loc = courier.loc
11 | planTime = context.timeStamp
12 | else:
13 | lastNode = courier.planRoutes[-1]
14 | lastOrder = context.orderPool.orderMap[lastNode.orderId]
15 | loc = lastOrder.dstLoc
16 | planTime = lastNode.actionTime
17 | tailPlans = self.planOneOrder(courier, loc, planTime, order)
18 | appendPlans = []
19 | appendPlans += courier.planRoutes
20 | appendPlans += tailPlans
21 | return appendPlans
22 |
23 | def planOneOrder(self, courier: Courier, loc: Location, planTime, order: Order):
24 | distanceUtils = DistanceUtils()
25 | arrivalTime = planTime + distanceUtils.timeConsuming(loc, order.srcLoc, courier.speed)
26 | pickTime = max(order.estimatedPrepareCompletedTime, arrivalTime)
27 | deliverTime = pickTime + distanceUtils.timeConsuming(order.srcLoc, order.dstLoc, courier.speed)
28 | arrivalNode = ActionNode(1, order.id, arrivalTime, False, planTime)
29 | pickNode = ActionNode(2, order.id, pickTime, False, arrivalTime)
30 | deliveryNode = ActionNode(3, order.id, deliverTime, False, pickTime)
31 | return [arrivalNode, pickNode, deliveryNode]
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/pool.py:
--------------------------------------------------------------------------------
1 | from .dto import Order, Courier
2 | from typing import Dict, List
3 |
4 |
5 | class OrderPool:
6 | def __init__(self):
7 | self.orders: List[Order] = []
8 | self.orderMap: Dict[str, Order] = {}
9 |
10 | def addDispatchingOrders(self, dispatchingOrders: List[Order]):
11 | self.orders = self.orders + dispatchingOrders
12 | for order in dispatchingOrders:
13 | self.orderMap[order.id] = order
14 |
15 | def getDispatchingOrders(self):
16 | return [order for order in self.orders if order.status == 0]
17 |
18 | def markAssignedOrder(self, orderId):
19 | self.orderMap.get(orderId).setStatus(1)
20 |
21 | def markArrivalCompleteOrder(self, orderId):
22 | self.orderMap.get(orderId).setStatus(2)
23 |
24 | def markPickCompleteOrder(self, orderId):
25 | self.orderMap.get(orderId).setStatus(3)
26 |
27 | def markDeliverCompleteOrder(self, orderId):
28 | self.orderMap.get(orderId).setStatus(4)
29 |
30 | def getOrder(self, orderId) -> Order:
31 | return self.orderMap.get(orderId)
32 |
33 |
34 | class CourierPool:
35 | def __init__(self):
36 | self.couriers: List[Courier] = []
37 |
38 | def addOnlineCouriers(self, courierList: List[Courier]):
39 | self.couriers = self.couriers + courierList
40 |
41 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/service.py:
--------------------------------------------------------------------------------
1 | from .dto import DispatchRequest, DispatchSolution, ActionNode, CourierPlan
2 | from .context import DispatchContext
3 | from typing import Dict, List
4 | from .solver import BaseSolver
5 |
6 | class DispatchService:
7 | def __init__(self):
8 | self.serviceContext: Dict[str, DispatchContext] = {}
9 |
10 | def dispatch(self, request: DispatchRequest):
11 | areaId = request.areaId
12 | if request.isFirstRound:
13 | context = DispatchContext(areaId, request.requestTimestamp)
14 | self.serviceContext[areaId] = context
15 | else:
16 | context = self.serviceContext.get(areaId)
17 | if context is None:
18 | emptySolution = DispatchSolution([])
19 | return emptySolution
20 | else:
21 | if request.isLastRound:
22 | context.setIsEndOfTest(True)
23 | context.refresh(request.requestTimestamp)
24 |
25 | context.addOnlineCouriers(request.couriers)
26 | context.addDispatchingOrders(request.orders)
27 | solver = self.getSolver(context)
28 | courierPlans = solver.solve()
29 | for cp in courierPlans:
30 | for a in cp.planRoutes:
31 | a.setSubmitted(True)
32 | assignedIds = solver.getAssignedOrderIds()
33 | context.markAllocatedOrders(assignedIds)
34 | while len(context.orderPool.getDispatchingOrders()) != 0 and context.isEndOfTest:
35 | aheadTime = 10 * 60
36 | context.setTimeStamp(context.timeStamp + aheadTime)
37 | lastRoundSolver = self.getSolver(context)
38 | tmpPlans = lastRoundSolver.solve()
39 | for cp in tmpPlans:
40 | for a in cp.planRoutes:
41 | a.setSubmitted(True)
42 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds())
43 | solution = DispatchSolution(courierPlans)
44 | return solution
45 |
46 | def getSolver(self, context: DispatchContext) -> BaseSolver:
47 | return BaseSolver(context)
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/solver.py:
--------------------------------------------------------------------------------
1 | from .context import DispatchContext
2 | from .dto import Courier, Order, CourierPlan
3 | from typing import Dict, List
4 | from .plan import TailAppendPlan
5 | import sys
6 |
7 |
8 | class Cost:
9 | def __init__(self, i, j, couriers: List[Courier], orders: List[Order], context: DispatchContext):
10 | self.i = i
11 | self.j = j
12 | self.courier = couriers[i]
13 | self.order = orders[j]
14 | tailAppendPlan = TailAppendPlan()
15 | self.planActionNodes = tailAppendPlan.plan(self.courier, self.order, context)
16 | self.cost = self.calCost()
17 |
18 | def isValid(self):
19 | maxLoad = self.courier.maxLoads
20 | cr = sum([1 for order in self.courier.orders if order.status == 3])
21 | for node in self.planActionNodes:
22 | if node.actionType == 2:
23 | cr += 1
24 | if cr > maxLoad:
25 | return False
26 | if node.actionType == 3:
27 | cr -= 1
28 | return True
29 |
30 | def calCost(self):
31 | cost = sys.float_info.max
32 | if not self.isValid():
33 | return sys.float_info.max
34 | for node in self.planActionNodes:
35 | if node.actionType == 3 and node.orderId == self.order.id:
36 | cost = node.actionTime
37 | break
38 | return cost
39 |
40 |
41 | class BaseSolver:
42 | def __init__(self, context: DispatchContext):
43 | self.context = context
44 | self.orders = self.getCandidateOrders(context)
45 | self.couriers = self.getCandidateCouriers(context)
46 | self.ordersAssigned = [False for i in self.orders]
47 | self.costTable = []
48 | self.MINIMUM_INTERVAL_SECONDS = 60
49 |
50 | def getCandidateCouriers(self, dispatchContext: DispatchContext):
51 | return dispatchContext.courierPool.couriers
52 |
53 | def getCandidateOrders(self, dispatchContext: DispatchContext):
54 | return dispatchContext.orderPool.getDispatchingOrders()
55 |
56 | def getAssignedOrderIds(self):
57 | return [order.id for i, order in enumerate(self.orders) if self.ordersAssigned[i]]
58 |
59 | def initTable(self):
60 | courierSize = len(self.couriers)
61 | orderSize = len(self.orders)
62 | for i in range(courierSize):
63 | costTableRow = []
64 | for j in range(orderSize):
65 | costTableRow.append(self.getCost(i, j))
66 | self.costTable.append(costTableRow)
67 |
68 | def solve(self) -> List[CourierPlan]:
69 | self.initTable()
70 | while True:
71 | cost = self.getBest()
72 | if cost is None:
73 | break
74 | self.dealWithCost(cost)
75 | results: List[CourierPlan] = []
76 | for courier in self.couriers:
77 | submitPlan = self.getSubmitPlan(courier)
78 | if len(submitPlan.planRoutes) != 0:
79 | results.append(submitPlan)
80 | return results
81 |
82 | def getSubmitPlan(self, courier: Courier):
83 | submitThresholdTime = self.context.timeStamp + self.MINIMUM_INTERVAL_SECONDS
84 | submittedNodes = [node for node in courier.planRoutes if (not node.isSubmitted) and (node.needSubmitTime <= submitThresholdTime or self.context.isEndOfTest)]
85 | plan = CourierPlan(courier.id, submittedNodes)
86 | return plan
87 |
88 | def dealWithCost(self, cost: Cost):
89 | cost.courier.setsetPlanRoutes(cost.planActionNodes)
90 | cost.courier.orders.append(cost.order)
91 | self.ordersAssigned[cost.j] = True
92 | self.updateWeightRow(cost.i)
93 | self.updateWeightCol(cost.j)
94 |
95 | def updateWeightRow(self, i):
96 | for j in range(len(self.orders)):
97 | self.costTable[i][j] = self.getCost(i, j)
98 |
99 | def updateWeightCol(self, j):
100 | for i in range(len(self.couriers)):
101 | self.costTable[i][j] = self.getCost(i, j)
102 |
103 | def getBest(self):
104 | best = None
105 | courierSize = len(self.couriers)
106 | orderSize = len(self.orders)
107 | for i in range(courierSize):
108 | for j in range(orderSize):
109 | tmpC = self.costTable[i][j]
110 | if tmpC is None:
111 | continue
112 | if best is None:
113 | best = tmpC
114 | continue
115 | if self.costLess(tmpC, best):
116 | best = tmpC
117 | return best
118 |
119 | def costLess(self, c1: Cost, c2: Cost):
120 | return c1.cost <= c2.cost
121 |
122 | def getCost(self, i, j):
123 | if self.ordersAssigned[j]:
124 | return None
125 | cost = Cost(i, j, self.couriers, self.orders, self.context)
126 | if not cost.isValid():
127 | return None
128 | return cost
129 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/util.py:
--------------------------------------------------------------------------------
1 | from .dto import Location
2 | import math
3 |
4 |
5 | class DistanceUtils:
6 | def __init__(self):
7 | # 地球半径
8 | self.RADIUS = 6367000.0
9 | # 导航距离/路面距离 经验系数
10 | self.COEFFICIENT = 1.4
11 |
12 | def timeConsuming(self, fromL: Location, toL: Location, speed):
13 | return math.ceil(self.getDistance(fromL, toL) / speed)
14 |
15 | # 经验路面距离 = 球面距离 * 经验系数(1.4)
16 | def getDistance(self, fromL: Location, toL: Location):
17 | return self.greatCircleDistance(fromL.longitude, fromL.latitude, toL.longitude, toL.latitude) * self.COEFFICIENT
18 |
19 | # 简化版球面距离
20 | def greatCircleDistance(self, lng1, lat1, lng2, lat2):
21 | # 经度差值
22 | deltaLng = lng2 - lng1
23 | # 纬度差值
24 | deltaLat = lat2 - lat1
25 | # 平均纬度
26 | b = (lat1 + lat2) / 2.0
27 | # 东西距离
28 | x = math.radians(deltaLng) * self.RADIUS * math.cos(math.radians(b))
29 | # 南北距离
30 | y = self.RADIUS * math.radians(deltaLat)
31 | # 用平面的矩形对角距离公式计算总距离
32 | return math.sqrt(x * x + y * y)
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/local_judge.py:
--------------------------------------------------------------------------------
1 | import os
2 | import multiprocessing
3 | import app
4 |
5 |
6 | def run_judge(jar_path, class_path, date_path):
7 | cmd = "java -cp .:{} {} {}".format(jar_path, class_path, date_path)
8 | print(cmd)
9 | os.system(cmd)
10 | print("end judge.")
11 |
12 |
13 | if __name__ == '__main__':
14 | p = multiprocessing.Process(target=app.local_start, kwargs={'port': 8080})
15 | p.start()
16 | run_judge("./dispatch-judge-jar-with-dependencies.jar", "dispatch.judge.DispatchJudge", "./open_test")
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/680507/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186
3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315
4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063
5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515
6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103
7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833
8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094
9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752
10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313
11 | 680507 1208264316 1575684848 11 3.026112456289089 40.451155 102.707619
12 | 680507 1222639031 1575683467 8 3.546382437049226 40.450959000000005 102.713936
13 | 680507 1734975658 1575684248 3 3.704858788960522 40.438719 102.709014
14 | 680507 116322334 1575685027 11 3.13533821514342 40.451766 102.708254
15 | 680507 1672528308 1575681727 9 2.9713525964966485 40.452513 102.708735
16 | 680507 112845496 1575679027 3 3.8483245919491025 40.477753 102.69838299999999
17 | 680507 117879616 1575682507 12 2.951266669813286 40.471816 102.706665
18 | 680507 1498386500 1575684067 9 2.9499812409610935 40.450167 102.721127
19 | 680507 1641767011 1575681487 9 2.2825539266226222 40.451039 102.713886
20 | 680507 1403535350 1575682507 14 2.8481381075161396 40.476379 102.7112
21 | 680507 1691267820 1575682267 8 3.248321005542984 40.452329 102.708221
22 | 680507 115919319 1575677706 11 2.79297577504939 40.445732 102.719816
23 | 680507 1501461921 1575682807 10 3.336964136657864 40.451084 102.707528
24 | 680507 119056946 1575683347 9 2.4996290528183382 40.451015000000005 102.707634
25 | 680507 1739955571 1575683407 2 2.034439127338177 40.437531 102.71731199999999
26 | 680507 1739635429 1575680767 1 3.565758995409262 40.44531 102.72065699999999
27 | 680507 1704858710 1575678667 7 2.6817540792350334 40.445347 102.719949
28 | 680507 1260738882 1575682687 10 2.716981986023813 40.469231 102.711462
29 | 680507 118350282 1575683347 9 3.1410202954437145 40.450942 102.713872
30 | 680507 1100384890 1575678247 12 3.1739785164893477 40.432919 102.695546
31 | 680507 1243561117 1575681487 8 3.670216712496116 40.452275 102.708763
32 | 680507 1561488920 1575682987 10 2.970246575553227 40.443556 102.69686899999999
33 | 680507 1390049525 1575684367 10 2.729634861374282 40.45082 102.707702
34 | 680507 1604576185 1575677167 10 3.068057263223962 40.468577 102.721584
35 | 680507 1734008360 1575684608 5 2.8149660796620615 40.444188 102.719844
36 | 680507 1340930725 1575677647 8 3.0853481200407105 40.449676000000004 102.718729
37 | 680507 1680551613 1575684067 9 3.5419144511514684 40.467838 102.72192199999999
38 | 680507 1742712882 1575681187 1 2.469981468674661 40.445187 102.72061
39 | 680507 1663491750 1575682387 9 2.91739756865818 40.450008000000004 102.707255
40 | 680507 1646693599 1575678307 9 3.0540291748278556 40.451739 102.71054
41 | 680507 1353313828 1575679927 10 3.1144211901270675 40.422092 102.684789
42 | 680507 1724835943 1575683587 6 2.527793854772829 40.440612 102.696155
43 | 680507 1669429740 1575684308 9 2.3571432025488197 40.447069 102.706948
44 | 680507 1479565240 1575681727 10 3.8045368692139583 40.451286 102.707625
45 | 680507 1625244485 1575684067 10 3.1205103631990765 40.468387 102.72151099999999
46 | 680507 1536359470 1575681067 10 2.949029183367058 40.445296 102.720787
47 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/725011/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 725011 1221280480 1575597549 11 3.0745467228136714 45.525371 103.662065
3 | 725011 113495157 1575591308 9 3.167722576151949 45.525573 103.648644
4 | 725011 1177503829 1575591308 12 3.6814195786682338 45.507856 103.662758
5 | 725011 1418952335 1575592808 10 3.8148912684766367 45.508578 103.648323
6 | 725011 1479538753 1575597129 11 2.832166129898812 45.54217 103.765009
7 | 725011 1622320859 1575592028 10 2.7767326358596005 45.543176 103.664697
8 | 725011 1307048619 1575594788 12 2.8811465775570624 45.507928 103.662966
9 | 725011 1657676623 1575594668 10 2.5084512136962984 45.554701 103.657823
10 | 725011 1646283965 1575591308 10 3.0709960737781836 45.517871 103.65811
11 | 725011 1246670853 1575594608 14 3.4073109270143678 45.5041 103.656093
12 | 725011 1307083020 1575591308 6 3.104167614990719 45.513523 103.646522
13 | 725011 1477839296 1575597609 11 3.1340188990585176 45.512018 103.645563
14 | 725011 1687180658 1575591308 9 3.379602154676791 45.496864 103.656408
15 | 725011 1500903736 1575591308 8 3.109008402113315 45.519959 103.637448
16 | 725011 1353832676 1575591668 12 2.9546278702091184 45.511084999999994 103.644226
17 | 725011 1469955904 1575591308 11 3.0431526726710088 45.50816 103.64672
18 | 725011 1250625037 1575591308 11 3.661297496606512 45.551017 103.658541
19 | 725011 1708425173 1575594128 7 2.8936645508515455 45.504822 103.64859100000001
20 | 725011 117244729 1575591548 8 3.745552874657883 45.507824 103.645524
21 | 725011 1622630002 1575595388 9 2.963381002287524 45.504607 103.652491
22 | 725011 1718265946 1575591908 8 3.2081500612724017 45.505793 103.648939
23 | 725011 1428083383 1575597309 13 3.4342418182588115 45.507699 103.661904
24 | 725011 1740484365 1575591308 1 3.1094414507277928 45.503514 103.663348
25 | 725011 1322529855 1575598449 9 3.4050049348521942 45.531061 103.647813
26 | 725011 1439011135 1575596649 10 3.170385812345891 45.50482 103.64859
27 | 725011 1734801322 1575591308 1 3.592799987069256 45.523335 103.648163
28 | 725011 1306666525 1575592568 11 3.059979859801288 45.531393 103.646792
29 | 725011 1584116537 1575591308 11 3.2326875812877685 45.507525 103.66171999999999
30 | 725011 114861767 1575598329 11 2.475249549190708 45.530645 103.648613
31 | 725011 1374788376 1575596349 12 3.377776328431921 45.507581 103.662041
32 | 725011 1287988348 1575602530 9 2.9140317765060852 45.527784000000004 103.661967
33 | 725011 1229044106 1575596169 6 2.261752965694964 45.512402 103.646282
34 | 725011 1680584174 1575591308 11 3.3716508780335053 45.521201 103.735459
35 | 725011 1137142537 1575598689 13 2.5892511698971408 45.541044 103.764013
36 | 725011 1642469864 1575591308 10 2.9722152944598874 45.523423 103.647972
37 | 725011 1254126910 1575591308 12 3.5647529504247255 45.507671 103.662028
38 | 725011 1237370576 1575596829 11 2.2297466450026837 45.513449 103.64869499999999
39 | 725011 1483094823 1575594908 11 3.7245840037730424 45.531253 103.64790500000001
40 | 725011 116287873 1575596349 11 2.41609808281589 45.501467 103.649249
41 | 725011 1603283203 1575595088 11 2.4171289591815524 45.508598 103.64837
42 | 725011 116752187 1575593288 11 2.856048911631838 45.520815 103.672229
43 | 725011 1495968351 1575591308 7 2.62466373517706 45.519472 103.638761
44 | 725011 1465546313 1575593828 11 2.908179066810375 45.511649 103.64427
45 | 725011 1642502425 1575600490 10 2.476718914322433 45.508105 103.646757
46 | 725011 1488524697 1575591308 7 3.1676446655060837 45.519224 103.641553
47 | 725011 115798791 1575599770 11 3.3014032247058434 45.514319 103.657326
48 | 725011 1287312067 1575591308 11 3.327427169310638 45.503823 103.66471
49 | 725011 1455084424 1575591308 11 3.1779898636537602 45.509151 103.64779
50 | 725011 1578881944 1575591308 10 3.6704894172748053 45.504233 103.655686
51 | 725011 1225769277 1575591308 11 3.242736489317296 45.530623 103.64749300000001
52 | 725011 1369995808 1575594368 9 3.0851662723791407 45.522729 103.643674
53 | 725011 1351295452 1575591308 10 3.344949353729399 45.514637 103.640763
54 | 725011 9028621 1575591308 7 3.350064118615471 45.499027000000005 103.654729
55 | 725011 1288750515 1575594548 9 2.706344400464836 45.50639 103.652383
56 | 725011 1360505717 1575594668 10 2.4994046906154845 45.554599 103.660969
57 | 725011 1387554021 1575595028 10 3.862021614383592 45.502163 103.65689300000001
58 | 725011 1244300839 1575591308 11 3.72014055841659 45.522973 103.664045
59 | 725011 115409365 1575591308 11 3.2135177692361996 45.530241 103.647946
60 | 725011 1501232069 1575591308 10 2.815186434932678 45.503602 103.656244
61 | 725011 1727665226 1575591308 4 3.050129780749418 45.527034 103.647473
62 | 725011 1307188096 1575591308 11 3.1440525066088196 45.514282 103.641467
63 | 725011 7960820 1575591728 7 3.2582422818676298 45.517493 103.665589
64 | 725011 1397564024 1575591308 13 3.4927502613980366 45.50346 103.66055
65 | 725011 1656032959 1575594428 10 3.0853410337771607 45.509891 103.647035
66 | 725011 113560243 1575594128 10 3.4392512368587513 45.509642 103.647185
67 | 725011 1718794740 1575600850 7 2.6709509184430917 45.51397 103.661188
68 | 725011 1131552518 1575597369 10 2.654692060202425 45.523501 103.657944
69 | 725011 1421636152 1575596049 10 2.3117626821830846 45.504822999999995 103.64858000000001
70 | 725011 111460869 1575591308 8 2.759435631046959 45.525423 103.648512
71 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/730221/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 730221 1374270581 1575507758 9 3.0855756624075665 47.846135 103.45929100000001
3 | 730221 1219549877 1575511179 8 2.735835929651148 47.826640000000005 103.463714
4 | 730221 10362332 1575508418 8 3.3254622249269596 47.844551 103.393856
5 | 730221 1542508376 1575507518 10 3.1019804970568075 47.823334 103.471177
6 | 730221 1255986534 1575504878 9 2.756974127718802 47.828238 103.47454599999999
7 | 730221 116232492 1575508118 12 2.8297521465887914 47.82338 103.471088
8 | 730221 1438422421 1575509919 9 3.272551333258363 47.824993000000006 103.474819
9 | 730221 1719029443 1575507518 7 3.136633049048524 47.82363599999999 103.471125
10 | 730221 117392228 1575508778 9 3.4669860107852886 47.844689 103.459914
11 | 730221 1101190254 1575507338 10 3.8612638902439116 47.788332000000004 103.490189
12 | 730221 1533383487 1575508478 9 2.937137118458426 47.846368 103.459956
13 | 730221 116794113 1575505778 10 2.884703152256932 47.82363700000001 103.473532
14 | 730221 1303854304 1575508478 9 2.160099560075172 47.826007 103.463852
15 | 730221 1247414713 1575507578 9 2.788878708059746 47.823733 103.470837
16 | 730221 1531451263 1575509558 7 2.6897679187876915 47.823212 103.472229
17 | 730221 111342785 1575507878 9 2.957880472090308 47.836821 103.46289
18 | 730221 1682849560 1575509018 9 3.241013777926264 47.844787 103.45992
19 | 730221 1303878770 1575508598 10 3.3466503598224784 47.84734 103.461474
20 | 730221 1120065698 1575509138 9 2.7014314447421595 47.82511 103.463588
21 | 730221 10792789 1575508838 9 3.0827844146835695 47.844640000000005 103.45992
22 | 730221 117381435 1575505958 9 3.7629232745587236 47.823979 103.459474
23 | 730221 1303865484 1575506318 9 2.808289608338827 47.819551 103.465743
24 | 730221 110925020 1575509018 10 3.1668466386711596 47.84747900000001 103.460404
25 | 730221 1651978273 1575507518 8 2.4506182303580224 47.85174000000001 103.441963
26 | 730221 1164400013 1575506078 11 2.964001712330374 47.741595 103.468632
27 | 730221 1408109501 1575507158 9 3.2041788375567806 47.845499 103.459825
28 | 730221 118079460 1575509018 10 2.799603052382247 47.828739 103.47914200000001
29 | 730221 1311564690 1575504878 5 3.417007067974616 47.819253 103.4647
30 | 730221 1246047812 1575506738 11 2.958634651537811 47.84433799999999 103.394124
31 | 730221 1405204799 1575507878 9 3.036288073194167 47.837857 103.462714
32 | 730221 112555471 1575504878 11 3.058366006647499 47.821502 103.475454
33 | 730221 1519023207 1575504998 8 3.2949759474592866 47.844191 103.45954
34 | 730221 118896621 1575508538 9 2.6746718243901983 47.824197 103.47114300000001
35 | 730221 1243531992 1575504878 10 2.227462886485577 47.823415000000004 103.474312
36 | 730221 1225017311 1575509858 9 3.1169436831693504 47.824902 103.463851
37 | 730221 1150409328 1575504878 12 3.271827101878319 47.824758 103.471802
38 | 730221 117547592 1575508478 9 3.3856157294826255 47.823253 103.471598
39 | 730221 1233874607 1575504878 9 2.7118212357395577 47.823877 103.465486
40 | 730221 113850365 1575508658 10 2.189624388590529 47.843824 103.39528100000001
41 | 730221 1288945870 1575508898 11 3.098248949321933 47.824986 103.464715
42 | 730221 1303855272 1575506018 9 2.724410324420489 47.82703600000001 103.462849
43 | 730221 1436529449 1575508238 8 3.1714894832694034 47.823324 103.471049
44 | 730221 1303888099 1575508058 8 3.417693007938824 47.825124 103.486324
45 | 730221 116307064 1575508598 9 3.1963192009026438 47.824628 103.471935
46 | 730221 1300728100 1575505958 9 2.1140643596565374 47.825008000000004 103.465214
47 | 730221 7974530 1575505358 10 2.8990507440059408 47.822896 103.474005
48 | 730221 1360627504 1575508298 8 2.819111820894523 47.82342 103.470958
49 | 730221 1273313638 1575509078 8 2.5975482704031503 47.822659 103.468022
50 | 730221 1223524751 1575507638 9 3.527847028865668 47.823756 103.470972
51 | 730221 1703976777 1575504878 7 4.025214851828238 47.825114 103.46357900000001
52 | 730221 10669200 1575504878 9 3.7352047673609468 47.823370000000004 103.47205799999999
53 | 730221 1158047816 1575505598 10 2.8880841553476055 47.823678 103.475251
54 | 730221 7971553 1575506618 10 3.0950750096727178 47.825406 103.465599
55 | 730221 1118702233 1575507518 11 2.9743917491841323 47.827329999999996 103.459721
56 | 730221 116251331 1575508478 10 2.391277502357789 47.843587 103.395451
57 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small/680507/courier:
--------------------------------------------------------------------------------
1 | areaid id onlinetime maxload speed latitude longitude
2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186
3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315
4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063
5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515
6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103
7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833
8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094
9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752
10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313
11 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo-py/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(
4 | name="dispatch_demo_py",
5 | version="0.0.1",
6 | author="fangyu.ffy",
7 | author_email="fangyu.ffy@alibaba-inc.com",
8 | description="Tianchi-Eleme delivery order dispatch contest.",
9 | keywords="Tianchi,Eleme,Delivery,Dispatch",
10 | install_requires=['flask>=1.1.1']
11 |
12 | )
13 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.13.RELEASE
9 |
10 |
11 | dispatch
12 | dispatch-demo
13 | 0.0.1-SNAPSHOT
14 | dispatch-demo
15 | Demo project for Spring Boot
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.projectlombok
24 | lombok
25 |
26 |
27 |
28 |
29 | com.alibaba
30 | fastjson
31 | 1.2.68
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-devtools
42 | runtime
43 | true
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-test
48 | test
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-maven-plugin
59 |
60 |
61 | dispatch-demo
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/DispatchDemoApplication.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | @SpringBootApplication
10 | public class DispatchDemoApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(DispatchDemoApplication.class, args);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/controller/DispatchController.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.controller;
2 |
3 |
4 | import com.alibaba.fastjson.JSON;
5 | import dispatch.demo.core.DispatchService;
6 | import dispatch.demo.dto.DispatchRequest;
7 | import dispatch.demo.dto.DispatchSolution;
8 | import dispatch.demo.dto.Response;
9 | import org.springframework.web.bind.annotation.*;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 | import java.util.concurrent.ArrayBlockingQueue;
13 | import java.util.concurrent.Future;
14 | import java.util.concurrent.ThreadPoolExecutor;
15 | import java.util.concurrent.TimeUnit;
16 |
17 |
18 | /**
19 | * @author eleme.demo
20 | */
21 | @RestController()
22 | @RequestMapping("/api/v1")
23 | public class DispatchController {
24 |
25 |
26 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
27 | Runtime.getRuntime().availableProcessors(),
28 | Runtime.getRuntime().availableProcessors(),
29 | 30,
30 | TimeUnit.SECONDS,
31 | new ArrayBlockingQueue<>(100)
32 | );
33 |
34 | DispatchService dispatchService = new DispatchService();
35 |
36 |
37 | @RequestMapping(value = "/ping", method = RequestMethod.GET)
38 | public Response ping() {
39 | System.out.println("ping");
40 | return new Response<>("PONG");
41 | }
42 |
43 | @RequestMapping(value = "/score", method = RequestMethod.POST)
44 | public Response score(HttpServletRequest request) {
45 | System.out.println("ping");
46 | return new Response<>("PONG");
47 | }
48 |
49 | @RequestMapping(value = "/dispatch", method = RequestMethod.POST, produces = "application/json")
50 | public String dispatch(@RequestBody String jsonRequest) {
51 | System.out.println(jsonRequest);
52 | DispatchRequest request = JSON.parseObject(jsonRequest, DispatchRequest.class);
53 | DispatchSolution result = null;
54 | Future f = threadPoolExecutor.submit(() -> {
55 | return dispatchService.dispatch(request);
56 | });
57 | try {
58 | //wait maximum 4s
59 | result = f.get(4, TimeUnit.SECONDS);
60 | } catch (Exception e) {
61 | System.out.println(e.getMessage());
62 | //downgrade solution here, downgrade solution must finish within 1s so that total request processing will be finished within 5s.
63 | return JSON.toJSONString(Response.NewErrResponse(e.getMessage()));
64 | }
65 | if (null != result) {
66 | System.out.println(JSON.toJSONString(result));
67 | }
68 | Response r = new Response(200, result);
69 | return JSON.toJSONString(r);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/DispatchService.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.core.solver.BaseSolver;
5 | import dispatch.demo.dto.CourierPlan;
6 | import dispatch.demo.dto.DispatchRequest;
7 | import dispatch.demo.dto.DispatchSolution;
8 |
9 | import java.util.Collections;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | /**
15 | * @author eleme.demo
16 | */
17 | public class DispatchService {
18 |
19 | Map serviceContext = new HashMap<>(0);
20 |
21 | public DispatchSolution dispatch(DispatchRequest request) {
22 | String areaId = request.getAreaId();
23 | DispatchContext context;
24 | if (request.isFirstRound()) {
25 | context = new DispatchContext();
26 | context.setAreaId(areaId);
27 | context.setTimeStamp(request.getRequestTime());
28 | serviceContext.put(areaId, context);
29 | } else {
30 | context = serviceContext.get(areaId);
31 | if (null == context) {
32 | DispatchSolution emptySolution = new DispatchSolution();
33 | emptySolution.setCourierPlans(Collections.emptyList());
34 | return emptySolution;
35 | } else {
36 | if (request.isLastRound()) {
37 | context.setEndOfTest(true);
38 | }
39 | }
40 | context.refresh(request.getRequestTime());
41 | }
42 | context.addOnlineCouriers(request.getCouriers());
43 | context.addDispatchingOrders(request.getOrders());
44 | BaseSolver solver = getSolver(context);
45 | List courierPlans = solver.solve();
46 | courierPlans.forEach(cp -> {
47 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true));
48 | });
49 | List assignedIds = solver.getAssignedOrderIds();
50 | context.markAllocatedOrders(assignedIds);
51 | while (!context.getOrderPool().getDispatchingOrders().isEmpty() && context.isEndOfTest()) {
52 | long aheadTime = 10 * 60;
53 | context.setTimeStamp(context.getTimeStamp() + aheadTime);
54 | BaseSolver lastRoundSolver = getSolver(context);
55 | List tmpPlans = lastRoundSolver.solve();
56 | courierPlans.addAll(tmpPlans);
57 | tmpPlans.forEach(cp -> {
58 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true));
59 | });
60 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds());
61 | }
62 | DispatchSolution solution = new DispatchSolution();
63 | solution.setCourierPlans(courierPlans);
64 | return solution;
65 | }
66 |
67 | BaseSolver getSolver(DispatchContext context) {
68 | return new BaseSolver(context);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/context/DispatchContext.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.context;
2 |
3 | import dispatch.demo.core.pool.CourierPool;
4 | import dispatch.demo.core.pool.OrderPool;
5 | import dispatch.demo.dto.ActionNode;
6 | import dispatch.demo.dto.Courier;
7 | import dispatch.demo.dto.Location;
8 | import dispatch.demo.dto.Order;
9 | import lombok.Data;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * @author eleme.demo
17 | */
18 | @Data
19 | public class DispatchContext {
20 | private String areaId;
21 | private CourierPool courierPool = new CourierPool();
22 | private OrderPool orderPool = new OrderPool();
23 | private long timeStamp;
24 | private boolean isEndOfTest = false;
25 |
26 | public void addOnlineCouriers(List courierList) {
27 | courierPool.getCouriers().addAll(courierList);
28 | }
29 |
30 | public void addDispatchingOrders(List orders) {
31 | orderPool.addDispatchingOrders(orders);
32 | }
33 |
34 | public void markAllocatedOrders(List orderIds) {
35 | orderIds.forEach(id -> orderPool.markAssignedOrder(id));
36 | }
37 |
38 | public void refresh(long refreshTime) {
39 | this.timeStamp = refreshTime;
40 | courierPool.getCouriers().forEach(c -> {
41 | refreshCourier(c, refreshTime);
42 | });
43 | }
44 |
45 | private void refreshCourier(Courier courier, long refreshTime) {
46 | List actionNodeList = courier.getPlanRoutes();
47 | List refreshNodeList = new ArrayList<>(0);
48 | for (ActionNode node : actionNodeList) {
49 | if (node.isSubmitted() && node.getActionTime() <= refreshTime) {
50 | if (node.getActionType() == 1) {
51 | //到店完成
52 | orderPool.markArrivalCompleteOrder(node.getOrderId());
53 | }
54 | if (node.getActionType() == 2) {
55 | //取餐完成
56 | orderPool.markPickCompleteOrder(node.getOrderId());
57 | }
58 | if (node.getActionType() == 3) {
59 | //送达
60 | orderPool.markDeliverCompleteOrder(node.getOrderId());
61 | }
62 | } else {
63 | refreshNodeList.add(node);
64 | }
65 | }
66 | List loadOrders = courier.getOrders().stream()
67 | .filter(o -> o.getStatus() != 4)
68 | .collect(Collectors.toList());
69 | courier.setOrders(loadOrders);
70 | courier.setPlanRoutes(refreshNodeList);
71 | if(refreshNodeList.isEmpty() && !actionNodeList.isEmpty()){
72 | Location latestLoc = orderPool.getOrderMap().get(actionNodeList.get(actionNodeList.size()-1).getOrderId()).getDstLoc();
73 | courier.setLoc(latestLoc);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/pool/CourierPool.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.pool;
2 |
3 | import dispatch.demo.dto.Courier;
4 | import lombok.Data;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * @author eleme.demo
11 | */
12 | @Data
13 | public class CourierPool {
14 | private List couriers = new ArrayList<>(0);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/pool/OrderPool.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.pool;
2 |
3 | import dispatch.demo.dto.Order;
4 | import lombok.Getter;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.stream.Collectors;
10 |
11 | /**
12 | * @author eleme.demo
13 | */
14 |
15 | public class OrderPool {
16 |
17 | private List orders;
18 |
19 | @Getter
20 | private HashMap orderMap;
21 |
22 | public OrderPool() {
23 | orders = new ArrayList<>(0);
24 | orderMap = new HashMap<>(0);
25 | }
26 |
27 | public void addDispatchingOrders(List dispatchingOrders) {
28 | this.orders.addAll(dispatchingOrders);
29 | for (Order order : orders) {
30 | orderMap.put(order.getId(), order);
31 | }
32 | }
33 |
34 | public List getDispatchingOrders() {
35 | return orders.stream().filter(o -> o.getStatus() == 0).collect(Collectors.toList());
36 | }
37 |
38 | public void markAssignedOrder(String orderId){
39 | orderMap.get(orderId).setStatus(1);
40 | }
41 |
42 | public void markArrivalCompleteOrder(String orderId){
43 | orderMap.get(orderId).setStatus(2);
44 | }
45 |
46 | public void markPickCompleteOrder(String orderId){
47 | orderMap.get(orderId).setStatus(3);
48 | }
49 |
50 | public void markDeliverCompleteOrder(String orderId){
51 | orderMap.get(orderId).setStatus(4);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/route/Planner.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.route;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.dto.ActionNode;
5 | import dispatch.demo.dto.Courier;
6 | import dispatch.demo.dto.Order;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * @author eleme.demo
12 | * route planner interface
13 | */
14 | public interface Planner {
15 |
16 | /**
17 | * 路径规划
18 | *
19 | * @param courier 给定骑手
20 | * @param order 待规划的单
21 | * @param context 上下文信息
22 | * @return 骑手路径
23 | */
24 | public List plan(Courier courier, Order order, DispatchContext context);
25 | }
26 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/route/TailAppendPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.core.route;
2 |
3 | import dispatch.demo.core.context.DispatchContext;
4 | import dispatch.demo.dto.ActionNode;
5 | import dispatch.demo.dto.Courier;
6 | import dispatch.demo.dto.Location;
7 | import dispatch.demo.dto.Order;
8 | import dispatch.demo.utils.DistanceUtils;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | /**
15 | * @author eleme.demo
16 | * the courier always append new order to tail
17 | */
18 | public class TailAppendPlan implements Planner {
19 |
20 | @Override
21 | public List plan(Courier courier, Order order, DispatchContext context) {
22 | Location loc;
23 | long planTime;
24 | if (courier.getOrders().isEmpty()) {
25 | loc = courier.getLoc();
26 | planTime = context.getTimeStamp();
27 | } else {
28 | int size = courier.getPlanRoutes().size();
29 | ActionNode lastNode = courier.getPlanRoutes().get(size - 1);
30 | Order lastOrder = context.getOrderPool().getOrderMap().get(lastNode.getOrderId());
31 | loc = lastOrder.getDstLoc();
32 | planTime = lastNode.getActionTime();
33 | }
34 | List tailPlans = planOneOrder(courier, loc, planTime, order);
35 | List appendPlans = new ArrayList<>(courier.getPlanRoutes().size() + tailPlans.size());
36 | appendPlans.addAll(courier.getPlanRoutes());
37 | appendPlans.addAll(tailPlans);
38 | return appendPlans;
39 | }
40 |
41 | private List planOneOrder(Courier courier, Location loc, long planTime, Order order) {
42 | long arrivalTime = planTime + DistanceUtils.timeConsuming(loc, order.getSrcLoc(), courier.getSpeed());
43 | long pickTime = Math.max(order.getEstimatedPrepareCompletedTime(), arrivalTime);
44 | long deliverTime = pickTime + DistanceUtils.timeConsuming(order.getSrcLoc(), order.getDstLoc(), courier.getSpeed());
45 | ActionNode arrivalNode = new ActionNode(order.getId(), 1, arrivalTime, false, planTime);
46 | ActionNode pickNode = new ActionNode(order.getId(), 2, pickTime, false, arrivalTime);
47 | ActionNode deliveryNode = new ActionNode(order.getId(), 3, deliverTime, false, pickTime);
48 | return Arrays.asList(arrivalNode, pickNode, deliveryNode);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/ActionNode.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author eleme.demo
10 | */
11 | @Data
12 | @AllArgsConstructor
13 | @NoArgsConstructor
14 | public class ActionNode {
15 |
16 | /** 运单ID */
17 | private String orderId;
18 |
19 | /**
20 | * 1 到店完成
21 | * 2 取完成
22 | * 3 送完成
23 | */
24 | private int actionType;
25 |
26 | /** 预计发生时刻 */
27 | private long actionTime;
28 |
29 | /** 是否已提交 */
30 | @JSONField(serialize = false)
31 | private boolean isSubmitted = false;
32 |
33 | /** 该动作需提交的时间,如果晚于该时间提交,可能造成评测系统判断骑手无法到达该点 */
34 | @JSONField(serialize = false)
35 | private long needSubmitTime = -1L;
36 |
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Courier.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * @author eleme.demo
12 | */
13 | @Data
14 | public class Courier {
15 | private String areaId;
16 | private String id;
17 | private Location loc;
18 | private Double speed;
19 | private Integer maxLoads;
20 |
21 | @JSONField(serialize = false)
22 | private List planRoutes = new ArrayList<>(0);
23 |
24 | @JSONField(serialize = false)
25 | private List orders = new ArrayList<>(0);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/CourierPlan.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * @author eleme.demo
11 | */
12 | @Data
13 | public class CourierPlan {
14 | private String courierId;
15 | private List planRoutes;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchRequest.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author eleme.demo
10 | */
11 | @Data
12 | public class DispatchRequest {
13 | private long requestTime;
14 | private String areaId;
15 | private boolean isFirstRound;
16 | private boolean isLastRound;
17 | private List couriers;
18 | private List orders;
19 | }
20 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchSolution.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author eleme.demo
9 | */
10 | @Data
11 | public class DispatchSolution {
12 | private List courierPlans;
13 | }
14 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Location.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author eleme.demo
7 | */
8 | @Data
9 | public class Location {
10 | private Double latitude;
11 | private Double longitude;
12 | }
13 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Order.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 |
10 | @Data
11 | public class Order {
12 | private String areaId;
13 | private String id;
14 | private Location srcLoc;
15 | private Location dstLoc;
16 | private long createTime;
17 | private long promiseDeliverTime;
18 | private long estimatedPrepareCompletedTime;
19 |
20 | /**
21 | * 0 dispatching
22 | * 1 goingRst
23 | * 2 picking
24 | * 3 delivering
25 | * 4 complete
26 | */
27 | @JSONField(serialize = false)
28 | int status = 0;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Response.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | @Data
10 | public class Response {
11 |
12 | private int code;
13 | private T result;
14 | private String message;
15 |
16 |
17 | public Response(T result) {
18 | this.code = 200;
19 | this.result = result;
20 | }
21 |
22 | public Response(int code, T result, String message) {
23 | this.code = code;
24 | this.result = result;
25 | this.message = message;
26 | }
27 |
28 | public Response(int code, T result) {
29 | this.code = code;
30 | this.result = result;
31 | }
32 |
33 | public static Response NewErrResponse(String message) {
34 | return new Response(500, message);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/utils/DistanceUtils.java:
--------------------------------------------------------------------------------
1 | package dispatch.demo.utils;
2 |
3 |
4 | import dispatch.demo.dto.Location;
5 |
6 | /**
7 | * @author eleme.demo
8 | */
9 | public class DistanceUtils {
10 |
11 | /**
12 | * 地球半径
13 | */
14 | private static final double RADIUS = 6367000.0;
15 |
16 | /**
17 | * 导航距离/路面距离 经验系数
18 | */
19 | private static final double COEFFICIENT = 1.4;
20 |
21 |
22 | public static int timeConsuming(Location from, Location to, double speed) {
23 | return (int) Math.ceil(getDistance(from, to) / speed);
24 | }
25 |
26 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */
27 | public static double getDistance(Location from, Location to) {
28 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT;
29 | }
30 |
31 | /** 简化版球面距离 */
32 | private static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) {
33 | // 经度差值
34 | double deltaLng = lng2 - lng1;
35 | // 纬度差值
36 | double deltaLat = lat2 - lat1;
37 | // 平均纬度
38 | double b = (lat1 + lat2) / 2.0;
39 | // 东西距离
40 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b));
41 | // 南北距离
42 | double y = RADIUS * Math.toRadians(deltaLat);
43 | // 用平面的矩形对角距离公式计算总距离
44 | return Math.sqrt(x * x + y * y);
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/dispatch-demo/src/test/java/dispatch/dispatchdemo/DispatchDemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package dispatch.dispatchdemo;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class DispatchDemoApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | dispatch
8 | dispatch
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | dispatch-api
13 | tianchi-dispatch-evaluate
14 |
15 |
16 |
17 |
18 |
19 | org.projectlombok
20 | lombok
21 | 1.18.12
22 |
23 |
24 |
25 | com.alibaba
26 | fastjson
27 | 1.2.68
28 |
29 |
30 |
31 | org.slf4j
32 | slf4j-api
33 | 1.7.30
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | maven-compiler-plugin
44 | 3.1
45 |
46 | 1.8
47 | 1.8
48 | -Xlint:all
49 | -parameters
50 | true
51 | true
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ## Specify $JAVA_HOME as you need.
4 | if [ -z "$JAVA_HOME" ] ; then
5 | JAVA_HOME="/data/jdk11.0.2"
6 | fi
7 |
8 | echo $JAVA_HOME
9 |
10 | cd /data
11 |
12 | cpu=8
13 | GC_PARALLEL_THREAD=`expr $((cpu*5/8))`
14 | GC_CONC_THREAD=`expr $((cpu*5/8/4+1))`
15 |
16 | MEM_OPTS="-server"
17 |
18 | G1_OPTS="-XX:+UnlockExperimentalVMOptions -XX:G1RSetUpdatingPauseTimePercent=5 -XX:InitiatingHeapOccupancyPercent=33 -XX:G1NewSizePercent=35 -XX:G1MaxNewSizePercent=50 -XX:+AlwaysPreTouch -XX:-ParallelRefProcEnabled"
19 | G1_OPTS="$G1_OPTS -XX:ParallelGCThreads=$GC_PARALLEL_THREAD -XX:ConcGCThreads=$GC_CONC_THREAD"
20 | G1_OPTS="$G1_OPTS -XX:ReservedCodeCacheSize=128m -XX:+PrintCodeCache"
21 |
22 | $JAVA_HOME/bin/java $MEM_OPTS $G1_OPTS -jar dispatch-demo.jar 2>&1 &
23 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/run_py.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ## Specify $JAVA_HOME as you need.
4 | if [ -z "$JAVA_HOME" ] ; then
5 | JAVA_HOME="/data/jdk-11.0.2"
6 | fi
7 | export JAVA_HOME
8 | cd dispatch-demo-py
9 |
10 | export FLASK_APP=app.py
11 | flask run -p 8080 &
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/run_py_dev.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ## Specify $JAVA_HOME as you need.
4 | if [ -z "$JAVA_HOME" ] ; then
5 | JAVA_HOME="/data/jdk-11.0.2"
6 | fi
7 | export JAVA_HOME
8 | cd dispatch-demo-py
9 |
10 | export FLASK_APP=app.py
11 | flask run -p 8080
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/eleme_round2_dispatch_master_20200421/start_judge.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | ## Specify $JAVA_HOME as you need.
3 | if [ -z "$JAVA_HOME" ] ; then
4 | JAVA_HOME="/data/jdk11.0.2"
5 | fi
6 |
7 | echo $JAVA_HOME
8 |
9 | $JAVA_HOME/bin/java -server -Xms1g -Xmx1g -jar dispatch-judge-jar-with-dependencies.jar "$MOCK_DATA_DIR" "$API_SERVER"
10 |
--------------------------------------------------------------------------------
/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.06.29 AM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.06.29 AM.png
--------------------------------------------------------------------------------
/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.55.34 AM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.55.34 AM.png
--------------------------------------------------------------------------------
/复赛 Baseline 流程部署分享/deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/deploy.png
--------------------------------------------------------------------------------