├── .gitattributes
├── README.md
├── docs
├── .nojekyll
├── 2020秋招-小米笔试题-小米之家购物.md
├── README.md
└── index.html
├── tf_consumer
├── pom.xml
├── src
│ └── main
│ │ ├── resources
│ │ └── kafka.properties
│ │ └── scala
│ │ ├── consumer
│ │ └── SparkConsumer.scala
│ │ └── utils
│ │ ├── PropertyUtil.scala
│ │ └── RedisUtil.scala
└── tf_consumer.iml
├── tf_modeling
├── pom.xml
├── src
│ └── main
│ │ └── scala
│ │ ├── modeling
│ │ └── Train.scala
│ │ └── utils
│ │ └── RedisUtil.scala
└── tf_modeling.iml
├── tf_prediction
├── pom.xml
├── src
│ └── main
│ │ └── scala
│ │ ├── predict
│ │ └── Prediction.scala
│ │ └── utils
│ │ └── RedisUtil.scala
└── tf_prediction.iml
└── tf_producer
├── pom.xml
└── src
└── main
├── resources
└── kafka.properties
└── scala
├── producer
└── Producer.scala
└── utils
└── PropertyUtil.scala
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 交通拥堵预测
2 |
3 | **思路**:考虑到没有相应的数据来源,这里是数据使用kafa, 进行自主模拟生产,然后消费预处理后存储到非关系型数据库中,再从redis中读取数据进行数据建模,将建立的模型存储到hdfs上,等进行数据预测时读取hdfs上的预测模型,进行预测。
4 |
5 | **项目环境**
6 |
7 | | 操作系统 | 版本号 |
8 | | -------- | -------------- |
9 | | window | window10家庭版 |
10 | | Linux | Ubuntu18.04 |
11 |
12 | **大数据框架环境**
13 |
14 | | 框架 | 版本号 |
15 | | --------- | ------------------ |
16 | | hadoop | Apache 2.7.2 |
17 | | zookeeper | Apache 3.4.5 |
18 | | kafka | kafka_2.10_0.8.2.1 |
19 | | scala | Apache 2.1.1 |
20 | | spark | 3.0.5 |
21 | | redis | 2.11.8 |
22 | | jdk | 1.8 |
23 |
24 | | 编程工具 | 版本号 |
25 | | ------------- | -------- |
26 | | Intellij IDEA | 2019.1.3 |
27 |
28 | **数据结构**
29 |
30 | | 字段名 | 字段含义 | example |
31 | | ---------- | ---------------------------------------- | ----------- |
32 | | monitor_id | 监测点id,在同一个业务系统中是唯一的 | 0001、002等 |
33 | | speed | 当前某一辆车经过监测点的时速,单位:km/h | 060、010等 |
34 |
35 | **启动大数据集群环境**
36 |
37 | 注意:启动大数据集群环境,这里因为资源有限,我以单节点作为测试,此次启动命令都是绝对启动命令,都是绝对路径,请根据自己实际情况进行启动。
38 |
39 | ```
40 | 1、启动 hadoop
41 |
42 | $ /usr/local/hadoop/sbin/start-all.sh
43 |
44 |
45 | 启动 kafka http://dblab.xmu.edu.cn/blog/1096-2/#more-1096
46 |
47 | $ /usr/local/kafka/bin/zookeeper-server-start.sh /usr/local/kafka/config/zookeeper.properties
48 |
49 | $ /usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/config/server.properties
50 |
51 | 2、创建主题
52 |
53 | $ /usr/local/kafka/bin/kafka-topics.sh --zookeeper localhost:2181 --topic traffic --create --replication-factor 1 --partitions 1
54 |
55 | 创建的主题是否存在。
56 |
57 | $ /usr/local/kafka/bin/kafka-topics.sh --list --zookeeper localhost:2181
58 |
59 | 测试启动成功
60 |
61 | 手动生产消息
62 | $ /usr/local/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic traffic
63 |
64 | 接收
65 | $ /usr/local/kafka/bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic traffic --from-beginning
66 |
67 |
68 | 启动redis
69 |
70 | $ /usr/local/redis/src/redis-server /usr/local/redis/redis.conf
71 |
72 | # 测试启动
73 | $ /usr/local/redis/src/redis-cli -h 192.168.126.132
74 |
75 | ```
76 |
77 | 关闭集群
78 |
79 | ```
80 | 关闭zookeeper
81 | $ /usr/local/kafka/bin/zookeeper-server-stop.sh
82 |
83 | 关闭kafka
84 | $ /usr/local/kafka/bin/kafka-server-stop.sh
85 |
86 | 关闭hadoop
87 | $ /usr/local/hadoop/sbin/stop-all.sh
88 |
89 | 关闭redis
90 | $ /usr/local/redis/src/redis-cli -h 192.168.126.132 -p 6379 shutdown
91 | ```
92 |
93 |
94 |
95 |
96 |
97 | ### 编写代码--创建总工程--traffic_prediction
98 |
99 | - 创建普通Java工程:traffic_prediction
100 | - 删除 src 目录(工程traffic_prediction 作为总工程目录,不编写代码)
101 |
102 | ### 编写生产者
103 |
104 | **思路:**
105 |
106 | **a**)新建子模块工程:tf_produccer
107 |
108 | - New ——> Module ——>选择maven 工程——> 创建完毕——>右键Add Framework Support 添加scala支持
109 | - 创建scala目录并设置为Source Root
110 |
111 | **b)** 配置maven依赖
112 |
113 | **c)** 因为要把数据发送给kafka,所以配置kafka属性,保存于某个配置文件中
114 |
115 | **d)** 编写kafka加载属性的工具类
116 |
117 | **e)** 每隔5分钟,切换一次模拟状态,例如第一个五分钟,车速都在30KM/H以上,下一个五分钟,车速都在10KM/H一下,往复模拟公路一会堵车,一会不堵车的情况。
118 |
119 | **f)** 启动zookeeper,kafka,并创建kafka主题,检查主题存在性
120 |
121 | **g)** 将数据发送至kafka并使用kafka console-consumer进行检测
122 |
123 |
124 |
125 | ### **编写消费者**
126 |
127 | **思路:**
128 |
129 | **a**)新建子工程:tf_consumer
130 |
131 | **b)** 配置maven依赖
132 |
133 | **c**) 配置redis并测试
134 |
135 | **d**) 将刚才kafka.properties以及PropertyUtil拷贝过来
136 |
137 | **e**) 编写redis操作工具类:RedisUtil
138 |
139 | **f**) 读取kafka中的数据,实时保存到redis中,并且按照分钟和监测点聚合车速和车辆个数
140 |
141 |
142 |
143 | ### 编写数据建模代码
144 |
145 | **思路:**
146 |
147 | **a)** 确定要对哪个监测点进行建模,我们称之为目标监测点
148 |
149 | **b**) 找到目标监测点的其他相关监测点(比如相关监测点与目标监测点属于一条公路的)
150 |
151 | **c**) 从redis中访问得到以上所有监测点若干小时内的历史数据信息(一部分作为训练数据,一部分作为测试数据)
152 |
153 | **d**) 提取组装特征向量与目标向量,训练参数集,训练模型
154 |
155 | **e**) 测试模型吻合度,将符合吻合度的模型保存到HDFS中,同时将模型的保存路径放置于redis中
156 |
157 | ### 编写预测模块
158 |
159 | **思路:**
160 |
161 | **a)** 用户传入想要进行预测的时间节点,读取该时间节点之前3分钟,2分钟和1分钟的数据
162 |
163 | **b**)此时应该已经得到了历史数据集,通过该历史数据集预测传入时间点的车流状态
164 |
165 | **提示**:为了方便观察测试,建议传一个历史时间点,这样可以很直观的看到预测结果是否符合期望值。
166 |
167 |
168 |
169 | **警告:代码中涉及到的IP,请自觉更换为你所使用的的集群的IP,我的单机的是192.168.126.132**
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiongmefeishi/traffic_prediction/7388053734a04f08082b9d877aa26aee49c9d22e/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/2020秋招-小米笔试题-小米之家购物.md:
--------------------------------------------------------------------------------
1 | **年轻即出发**...
2 |
3 | **简书**:https://www.jianshu.com/u/7110a2ba6f9e
4 |
5 | **知乎**:https://www.zhihu.com/people/zqtao23/posts
6 |
7 | **GitHub源码**:https://github.com/zqtao2332
8 |
9 | **个人网站**:http://www.zqtaotao.cn/ (停止维护更新内容)
10 |
11 | **QQ交流群**:606939954
12 |
13 | 咆哮怪兽一枚...嗷嗷嗷...趁你现在还有时间,尽你自己最大的努力。努力做成你最想做的那件事,成为你最想成为的那种人,过着你最想过的那种生活。也许我们始终都只是一个小人物,但这并不妨碍我们选择用什么样的方式活下去,这个世界永远比你想的要更精彩。
14 |
15 |
16 |
17 | 最后:喜欢编程,对生活充满激情
18 |
19 | ------
20 |
21 | ------
22 |
23 | **本节内容预告**
24 |
25 | 2020秋招-小米笔试题-小米之家购物
26 |
27 | ------
28 |
29 | ------
30 |
31 | **2020秋招-小米笔试题-小米之家购物**
32 |
33 | 小米之家购物 ---> N 元钱最少能买几件,求最少not最多
34 |
35 | ```
36 | 时间限制:C/C++语言 1000MS;其他语言 3000MS
37 | 内存限制:C/C++语言 65536KB;其他语言 589824KB
38 | ```
39 |
40 | 题目描述:
41 | 小米之家有很多米粉喜欢的产品,产品种类很多,价格也不同。比如某签字笔1元,某充电宝79元,某电池1元,某电视1999元等
42 |
43 | 假设库存不限,小明去小米之家买东西,要用光N元预算的钱,请问他最少能买几件产品?
44 |
45 | 输入
46 |
47 | ```
48 | 第1行为产品种类数
49 |
50 | 接下来的每行为每种产品的价格
51 |
52 | 最后一行为预算金额
53 | ```
54 |
55 | 输出
56 |
57 | ```
58 | 能买到的最少的产品的件数,无法没有匹配的返回-1
59 | ```
60 |
61 | 样例输入
62 |
63 | ```
64 | 2
65 | 500
66 | 1
67 | 1000
68 | ```
69 |
70 | 样例输出
71 |
72 | ```
73 | 2
74 | ```
75 |
76 | 动态规划
77 |
78 | ```
79 | 动态规划
80 | dp[i][j] 表示在可以使用 arr[0..i] 任意货币的情况下,组成 j 需要的最小张数
81 | @param arr 货币价值
82 | @param aim 目标值
83 | @return 组成 aim 最少需要货币张数
84 | *
85 | 完全不使用当前货币arr[i]情况下的最少张数,即 dpl[i-1][j]的值
86 | 只使用1张当前货币arr[i]情况下的最少张数,即 dp[i-1][j-arr[i]] + 1
87 | 只使用2张当前货币arr[i]情况下的最少张数,即 dp[i-1][j-2*arr[i]] + 2
88 | 只使用3张当前货币arr[i]情况下的最少张数,即 dp[i-1][j-3*arr[i]] + 3
89 | *
90 | 总结所有情况下,最终取最小张数
91 | dp[i][j]=min{dp[i-1][j-K*arr[i]] + K} (K >= 0)
92 | *
93 | 简化依赖
94 | dp[i][j]=min{dp[i-1][j], dp[i][j-arr[i]] + 1}
95 | 其中 j-arr[i] <0 时越界,说明arr[i] 值太大,用一张货币都会超过钱数 j
96 | *
97 | dp[i][j] 依赖左边一个值和上边一个值
98 | ```
99 |
100 |
101 |
102 | ```
103 | package cn.zqtao.examintion;
104 |
105 |
106 | /**
107 | * 小米之家购物 ---> N 元钱最少能买几件,求最少not最多
108 | * 时间限制:C/C++语言 1000MS;其他语言 3000MS
109 | * 内存限制:C/C++语言 65536KB;其他语言 589824KB
110 | * 题目描述:
111 | * 小米之家有很多米粉喜欢的产品,产品种类很多,价格也不同。比如某签字笔1元,某充电宝79元,某电池1元,某电视1999元等
112 | *
113 | * 假设库存不限,小明去小米之家买东西,要用光N元预算的钱,请问他最少能买几件产品?
114 | *
115 | * 输入
116 | * 第1行为产品种类数
117 | *
118 | * 接下来的每行为每种产品的价格
119 | *
120 | * 最后一行为预算金额
121 | *
122 | *
123 | * 输出
124 | * 能买到的最少的产品的件数,无法没有匹配的返回-1
125 | *
126 | *
127 | * 样例输入
128 | * 2
129 | * 500
130 | * 1
131 | * 1000
132 | * 样例输出
133 | * 2
134 | */
135 | public class Code_04_MinItemByAllMoney {
136 | public static int solution(int[] prices, int budget) {
137 | if (prices == null || prices.length == 0 || budget < 0) return -1;
138 |
139 | int n = prices.length;
140 | int max = Integer.MAX_VALUE;
141 | int[][] dp = new int[n][budget+1];
142 | for (int j = 1; j <= budget; j++) {
143 | dp[0][j] = max;
144 | if (j - prices[0] >= 0 && dp[0][j - prices[0]] != max){
145 | dp[0][j] = dp[0][j - prices[0]] + 1;
146 | }
147 | }
148 | int left = 0;
149 | for (int i = 1; i < n; i++) {
150 | for (int j = 1; j <= budget; j++) {
151 | left = max;
152 | if (j - prices[i] >= 0 && dp[i][j - prices[i]] != max){
153 | left = dp[i][j - prices[i]] + 1;
154 | }
155 | dp[i][j] = Math.min(left, dp[i - 1][j]);
156 | }
157 | }
158 | return dp[n - 1][budget] != max ? dp[n - 1][budget] : -1;
159 | }
160 |
161 | public static void main(String[] args) {
162 | int[] arr = {500, 1};
163 | System.out.println(solution(arr, 2001));
164 | }
165 | }
166 | ```
167 |
168 | **压缩动态规划表空间**
169 |
170 | ```
171 | public static int minCoin2(int[] prices, int budget) {
172 | if (prices == null || prices.length == 0 || budget < 0) return -1;
173 |
174 | int[] dp = new int[budget+1];
175 | int max = Integer.MAX_VALUE;
176 |
177 | for (int j = 1; j <= budget; j++) { // 初始化第一行,只是用prices[0] 的情况下
178 | dp[j] = max;
179 | if (j - prices[0] >= 0 && dp[j - prices[0]] != max) {
180 | dp[j] = dp[j - prices[0]] + 1;
181 | }
182 | }
183 |
184 | int left = 0;
185 | for (int i = 1; i < prices.length; i++) {
186 | for (int j = 1; j <= budget; j++) {
187 | left = max;
188 | if (j - prices[i] >= 0 && dp[j - prices[i]] != max){
189 | left = dp[j - prices[i]] + 1;
190 | }
191 | dp[j] = Math.min(dp[j], left);
192 | }
193 | }
194 | return dp[budget] == max ? -1 : dp[budget];
195 | }
196 | ```
197 |
198 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | - [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
2 |
3 | ## ✏️ 算法
4 |
5 | - [剑指 Offer 题解](2020秋招-小米笔试题-小米之家购物.md)
6 | - [剑指 Offer 题解](2020秋招-小米笔试题-小米之家购物.md)
7 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tf_consumer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.zqtao
8 | tf_consumer
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 |
15 | org.apache.kafka
16 | kafka-clients
17 | 0.11.0.2
18 |
19 |
20 |
21 | com.alibaba
22 | fastjson
23 | 1.2.41
24 |
25 |
26 |
27 | org.apache.spark
28 | spark-core_2.11
29 | 2.1.1
30 |
31 |
32 |
33 | org.apache.spark
34 | spark-streaming_2.11
35 | 2.1.1
36 |
37 |
38 |
39 | org.apache.spark
40 | spark-streaming-kafka_2.11
41 | 1.6.3
42 |
43 |
44 |
45 | redis.clients
46 | jedis
47 | 2.9.0
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/tf_consumer/src/main/resources/kafka.properties:
--------------------------------------------------------------------------------
1 | #设置kafka的brokerlist
2 | bootstrap.servers=192.168.126.132:9092
3 | key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
4 | value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
5 |
6 | # 元数据broker列表
7 | metadata.broker.list=192.168.126.132:9092
8 |
9 | acks=all
10 | retries=0
11 |
12 | #设置消费者组
13 | group.id=g_traffic1
14 |
15 | # 设置是否自动确认offset
16 | enable.auto.commit=true
17 |
18 | # 自动确认offset的间隔时间
19 | auto.commit.interval.ms=30000
20 |
21 | # 设置主题
22 | kafka.topics=traffic
23 |
24 | # 设置zk中follower和leader之间的关于kafka的信息同步时间间隔
25 | zookeeper.sync.time.ms=250
26 | num.io.threads=12
27 | batch.size=65536
28 | buffer.memory=524288
29 | # kafka中消息保存的时间
30 | log.retention.hours=2
31 |
--------------------------------------------------------------------------------
/tf_consumer/src/main/scala/consumer/SparkConsumer.scala:
--------------------------------------------------------------------------------
1 | package consumer
2 |
3 | import java.text.SimpleDateFormat
4 | import java.util.Calendar
5 |
6 | import com.alibaba.fastjson.{JSON, TypeReference}
7 | import kafka.serializer.StringDecoder
8 | import org.apache.spark.streaming.kafka.KafkaUtils
9 | import org.apache.spark.streaming.{Seconds, StreamingContext}
10 | import org.apache.spark.{SparkConf, SparkContext}
11 | import utils.{PropertyUtil, RedisUtil}
12 |
13 | object SparkConsumer {
14 | def main(args: Array[String]): Unit = {
15 |
16 | println("初始化spark")
17 | //初始化Spark
18 | val sparkConf = new SparkConf().setMaster("local[2]").setAppName("TrafficStreaming")
19 | val sc = new SparkContext(sparkConf)
20 | val ssc = new StreamingContext(sc, Seconds(5))
21 | ssc.checkpoint("./ssc/checkpoint")
22 |
23 | //配置kafka参数
24 | val kafkaParams = Map("metadata.broker.list" -> PropertyUtil.getProperty("metadata.broker.list"))
25 |
26 | //配置kafka主题
27 | val topics = Set(PropertyUtil.getProperty("kafka.topics"))
28 |
29 | //读取kafka主题中的,每一个事件
30 | val kafkaLineDStream = KafkaUtils.createDirectStream[
31 | String,
32 | String,
33 | StringDecoder,
34 | StringDecoder](ssc, kafkaParams, topics)
35 | .map(_._2)
36 |
37 | //解析json字符串,最终得到的event的形式是:{"0001" -> "57"}
38 | val event = kafkaLineDStream.map(line => {
39 | //使用fastjson解析当前事件中封装的数据信息
40 | val lineJavaMap = JSON.parseObject(line, new TypeReference[java.util.Map[String, String]](){})
41 | //将这个JavaMap转化成Scala Map
42 | import scala.collection.JavaConverters._
43 | val lineScalaMap: collection.mutable.Map[String, String] = mapAsScalaMapConverter(lineJavaMap).asScala
44 | println(lineScalaMap)
45 | lineScalaMap
46 | })
47 |
48 | //将每一条数据按照monitor_id聚合,聚合时每一条数据中的“车辆速度”叠加
49 | //例如,聚合好的数据形式:(monitor_id, (speed, 1)), (0001, (57, 1))
50 | //最终结果举例:(0001, (1365, 30))
51 | val sumOfSpeedAndCount = event
52 | .map(e => (e.get("monitor_id").get, e.get("speed").get))//("0001", "57")
53 | .mapValues(s => (s.toInt, 1))//("0001", (57, 1)) (0001, (58, 1))
54 | .reduceByKeyAndWindow(
55 | (t1: (Int, Int), t2: (Int, Int)) => (t1._1 + t2._1, t1._2 + t2._2),
56 | Seconds(60),
57 | Seconds(60))
58 |
59 | //定义redis中的数据库索引
60 | val dbIndex = 1
61 | //将采集到的数据,按照每分钟放置于redis中,将用于后边的数据建模
62 | sumOfSpeedAndCount.foreachRDD(rdd => {
63 | rdd.foreachPartition(partitionRecords => {
64 | partitionRecords
65 | .filter((tuple: (String, (Int, Int))) => tuple._2._2 > 0)//过滤车辆个数小于1的情况
66 | .foreach(pair => {
67 | //开始取出这60秒的window中所有的聚合数据
68 | //例如:1356_30
69 | val jedis = RedisUtil.pool.getResource
70 | val monitorId = pair._1
71 | val sumOfSpeed = pair._2._1
72 | val sumOfCarCount = pair._2._2
73 |
74 | //两种情况:
75 | //1、数据生产时,会产生时间戳字段,流入到kafka的事件中
76 | //2、实时数据,数据消费的时间,就是数据时间
77 | val currentTime = Calendar.getInstance().getTime
78 | val dateSDF = new SimpleDateFormat("yyyyMMdd")//用于redis中的key
79 | val hourMinuteSDF = new SimpleDateFormat("HHmm")//用于redis中的fields
80 |
81 | val hourMinuteTime = hourMinuteSDF.format(currentTime)//1634
82 | val date = dateSDF.format(currentTime)//20180203
83 |
84 | jedis.select(dbIndex)
85 | jedis.hset(date + "_" + monitorId, hourMinuteTime, sumOfSpeed + "_" + sumOfCarCount)
86 | println(date + "_" + monitorId)
87 | RedisUtil.pool.returnResource(jedis)
88 | })
89 | })
90 | })
91 |
92 | //spark开始工作
93 | ssc.start()
94 | ssc.awaitTermination()
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/tf_consumer/src/main/scala/utils/PropertyUtil.scala:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import java.util.Properties
4 |
5 | object PropertyUtil {
6 | val properties = new Properties()
7 |
8 | try{
9 | //加载配置属性
10 | val inputStream = ClassLoader.getSystemResourceAsStream("kafka.properties")
11 | properties.load(inputStream)
12 | }catch {
13 | case ex:Exception => println(ex)
14 | }finally {}
15 |
16 | // 通过key得到kafka的属性值
17 | def getProperty(key: String): String = properties.getProperty(key)
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/tf_consumer/src/main/scala/utils/RedisUtil.scala:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import redis.clients.jedis._
4 |
5 | object RedisUtil {
6 | //配置redis基本连接参数
7 | val host = "192.168.126.132"
8 | val port = 6379
9 | val timeout = 30000
10 |
11 | val config = new JedisPoolConfig
12 |
13 | //设置允许最大的连接个数
14 | config.setMaxTotal(100)
15 | //最大空闲连接数
16 | config.setMaxIdle(30)
17 | //最小空闲连接数
18 | config.setMinIdle(8)
19 |
20 | //设置连接时的最大等待毫秒数 10 秒
21 | config.setMaxWaitMillis(10000)
22 | //设置在获取连接时,是否检查连接的有效性
23 | config.setTestOnBorrow(true)
24 | //设置释放连接到池中时是否检查有效性
25 | config.setTestOnReturn(true)
26 |
27 | //在连接空闲时,是否检查连接有效性
28 | config.setTestWhileIdle(true)
29 |
30 | //两次扫描之间的时间间隔毫秒数
31 | config.setTimeBetweenEvictionRunsMillis(30000)
32 | //每次扫描的最多的对象数
33 | config.setNumTestsPerEvictionRun(10)
34 | //逐出连接的最小空闲时间,默认是180000(30分钟)
35 | config.setMinEvictableIdleTimeMillis(60000)
36 |
37 | //连接池
38 | lazy val pool = new JedisPool(config, host, port, timeout)
39 |
40 | //释放资源
41 | lazy val hook = new Thread{
42 | override def run() = {
43 | pool.destroy()
44 | }
45 | }
46 | sys.addShutdownHook(hook)
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/tf_consumer/tf_consumer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/tf_modeling/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.zqtao
8 | tf_modeling
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.apache.spark
15 | spark-core_2.11
16 | 2.1.1
17 |
18 |
19 |
20 | redis.clients
21 | jedis
22 | 2.9.0
23 |
24 |
25 |
26 | org.apache.spark
27 | spark-mllib_2.11
28 | 2.1.1
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tf_modeling/src/main/scala/modeling/Train.scala:
--------------------------------------------------------------------------------
1 | package modeling
2 |
3 | import java.io.{File, PrintWriter}
4 | import java.text.SimpleDateFormat
5 | import java.util.{Calendar, Date}
6 |
7 | import org.apache.spark.mllib.classification.LogisticRegressionWithLBFGS
8 | import org.apache.spark.mllib.evaluation.MulticlassMetrics
9 | import org.apache.spark.mllib.linalg.Vectors
10 | import org.apache.spark.mllib.regression.LabeledPoint
11 | import org.apache.spark.{SparkConf, SparkContext}
12 | import utils.RedisUtil
13 |
14 | import scala.collection.mutable.ArrayBuffer
15 |
16 | /**
17 | * 数据建模
18 | */
19 | object Train {
20 | def main(args: Array[String]): Unit = {
21 | //写入文件的输出流
22 | val writer = new PrintWriter(new File("model_train.txt"))
23 | //初始化spark
24 | val sparkConf = new SparkConf()
25 | .setMaster("local[2]")
26 | .setAppName("TrafficModel")
27 | val sc = new SparkContext(sparkConf)
28 |
29 | //定义redis的数据库相关
30 | val dbIndex = 1
31 | //获取redis连接
32 | val jedis = RedisUtil.pool.getResource
33 | jedis.select(dbIndex)
34 |
35 | //设立目标监测点:你要对哪几个监测点进行建模
36 | val monitorIDs = List("0005", "0015")
37 | //取出相关监测点
38 | val monitorRelations = Map[String, Array[String]](
39 | "0005" -> Array("0003", "0004", "0005", "0006", "0007"),
40 | "0015" -> Array("0013", "0014", "0015", "0016", "0017"))
41 |
42 | //遍历上边所有的监测点,读取数据
43 | monitorIDs.map(monitorID => {
44 | //得到当前“目标监测点”的相关监测点
45 | val monitorRelationArray = monitorRelations(monitorID)//得到的是Array(相关监测点)
46 |
47 | //初始化时间
48 | val currentDate = Calendar.getInstance().getTime
49 | //当前小时分钟数
50 | val hourMinuteSDF = new SimpleDateFormat("HHmm")
51 | //当前年月日
52 | val dateSDF = new SimpleDateFormat("yyyyMMdd")
53 | //以当前时间,格式化好年月日的时间
54 | val dateOfString = dateSDF.format(currentDate)
55 |
56 | //根据“相关监测点”,取得当日的所有的监测点的平均车速
57 | //最终结果样式:(0005, {1033=93_2, 1034=1356_30})
58 | val relationsInfo = monitorRelationArray.map(monitorID => {
59 | (monitorID, jedis.hgetAll(dateOfString + "_" + monitorID))
60 | })
61 |
62 | //确定使用多少小时内的数据进行建模
63 | val hours = 1
64 | //创建3个数组,一个数组用于存放特征向量,一数组用于存放Label向量,一个数组用于存放前两者之间的关联
65 | val dataX = ArrayBuffer[Double]()
66 | val dataY = ArrayBuffer[Double]()
67 |
68 | //用于存放特征向量和特征结果的映射关系
69 | val dataTrain = ArrayBuffer[LabeledPoint]()
70 |
71 | //将时间拉回到1个小时之前,倒序,拉回单位:分钟
72 |
73 | for(i <- Range(60 * hours, 2, -1)){
74 | dataX.clear()
75 | dataY.clear()
76 | //以下内容包含:线性滤波
77 | for(index <- 0 to 2){
78 | //当前毫秒数 - 1个小时之前的毫秒数 + 1个小时之前的后0分钟,1分钟,2分钟的毫秒数(第3分钟作为Label向量)
79 | val oneMoment = currentDate.getTime - 60 * i * 1000 + 60 * index * 1000
80 | //拼装出当前(当前for循环这一次的时间)的小时分钟数
81 | val oneHM = hourMinuteSDF.format(new Date(oneMoment))//1441 field
82 | //取得该时刻下里面数据
83 | //取出的数据形式距离:(0005, {1033=93_2, 1034=1356_30})
84 | for((k, v) <- relationsInfo){
85 | //如果index==2,意味着前3分钟的数据已经组装到了dataX中,那么下一时刻的数据,如果是目标卡口,则需要存放于dataY中
86 | if(k == monitorID && index == 2){
87 | val nextMoment = oneMoment + 60 * 1000
88 | val nextHM = hourMinuteSDF.format(new Date(nextMoment))//1027
89 |
90 | //判断是否有数据
91 | if(v.containsKey(nextHM)){
92 | val speedAndCarCount = v.get(nextHM).split("_")
93 | val valueY = speedAndCarCount(0).toFloat / speedAndCarCount(1).toFloat//得到第4分钟的平均车速
94 | dataY += valueY
95 | }
96 | }
97 |
98 | //组装前3分钟的dataX
99 | if(v.containsKey(oneHM)){
100 | val speedAndCarCount = v.get(oneHM).split("_")
101 | val valueX = speedAndCarCount(0).toFloat / speedAndCarCount(1).toFloat//得到当前这一分钟的特征值
102 | dataX += valueX
103 | }else{
104 | dataX += 60.0F // 车速
105 | }
106 | }
107 | }
108 | //准备训练模型
109 | //先将dataX和dataY映射于一个LabeledPoint对象中
110 | if(dataY.toArray.length == 1){
111 | val label = dataY.toArray.head//答案的平均车速
112 | //label的取值范围是:0~15, 30~60 -----> 0, 1, 2, 3, 4, 5, 6
113 | //真实情况:0~120KM/H车速,划分7个级别,公式就如下:
114 | val record = LabeledPoint(if (label / 10 < 6) (label / 10).toInt else 6, Vectors.dense(dataX.toArray))
115 | dataTrain += record
116 | }
117 | }
118 |
119 | //将数据集写入到文件中方便查看
120 | dataTrain.foreach(record => {
121 | println(record)
122 | writer.write(record.toString() + "\n")
123 | })
124 |
125 | //开始组装训练集和测试集
126 | val rddData = sc.parallelize(dataTrain)
127 | val randomSplits = rddData.randomSplit(Array(0.6, 0.4), 11L)
128 | //训练集
129 | val trainData = randomSplits(0)
130 | //测试集
131 | val testData = randomSplits(1)
132 |
133 | //使用训练集进行建模
134 | val model = new LogisticRegressionWithLBFGS().setNumClasses(7).run(trainData)
135 | //完成建模之后,使用测试集,评估模型精确度
136 | val predictionAndLabels = testData.map{
137 | case LabeledPoint(label, features) =>
138 | val prediction = model.predict(features)
139 | (prediction, label)
140 | }
141 |
142 | //得到当前评估值
143 | val metrics = new MulticlassMetrics(predictionAndLabels)
144 | val accuracy = metrics.accuracy//取值范围:0.0~1.0
145 |
146 | println("评估值:" + accuracy)
147 | writer.write(accuracy + "\n")
148 |
149 | //设置评估阈值:超过多少精确度,则保存模型
150 | if(accuracy > 0.0){
151 | //将模型保存到HDFS
152 | // val hdfsPath = "hdfs://192.168.126.132:8020/traffic/model/" +
153 | val hdfsPath = "hdfs://192.168.126.132:9000/traffic/model/" +
154 | monitorID +
155 | "_" +
156 | new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis()))
157 | model.save(sc, hdfsPath)
158 | jedis.hset("model", monitorID, hdfsPath)
159 | }
160 | })
161 |
162 | RedisUtil.pool.returnResource(jedis)
163 | writer.flush
164 | writer.close
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/tf_modeling/src/main/scala/utils/RedisUtil.scala:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import redis.clients.jedis._
4 |
5 | object RedisUtil {
6 | //配置redis基本连接参数
7 | val host = "192.168.126.132"
8 | val port = 6379
9 | val timeout = 30000
10 |
11 | val config = new JedisPoolConfig
12 |
13 | //设置允许最大的连接个数
14 | config.setMaxTotal(200)
15 | //最大空闲连接数
16 | config.setMaxIdle(50)
17 | //最小空闲连接数
18 | config.setMinIdle(8)
19 |
20 | //设置连接时的最大等待毫秒数
21 | config.setMaxWaitMillis(10000)
22 | //设置在获取连接时,是否检查连接的有效性
23 | config.setTestOnBorrow(true)
24 | //设置释放连接到池中时是否检查有效性
25 | config.setTestOnReturn(true)
26 |
27 | //在连接空闲时,是否检查连接有效性
28 | config.setTestWhileIdle(true)
29 |
30 | //两次扫描之间的时间间隔毫秒数
31 | config.setTimeBetweenEvictionRunsMillis(30000)
32 | //每次扫描的最多的对象数
33 | config.setNumTestsPerEvictionRun(10)
34 | //逐出连接的最小空闲时间,默认是180000(30分钟)
35 | config.setMinEvictableIdleTimeMillis(60000)
36 |
37 | //连接池
38 | lazy val pool = new JedisPool(config, host, port, timeout)
39 |
40 | //释放资源
41 | lazy val hook = new Thread{
42 | override def run() = {
43 | pool.destroy()
44 | }
45 | }
46 | sys.addShutdownHook(hook)
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/tf_modeling/tf_modeling.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/tf_prediction/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.zqtao
8 | tf_prediction
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.apache.spark
15 | spark-core_2.11
16 | 2.1.1
17 |
18 |
19 |
20 | redis.clients
21 | jedis
22 | 2.9.0
23 |
24 |
25 |
26 | org.apache.spark
27 | spark-mllib_2.11
28 | 2.1.1
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tf_prediction/src/main/scala/predict/Prediction.scala:
--------------------------------------------------------------------------------
1 | package predict
2 |
3 | import java.text.SimpleDateFormat
4 |
5 | import org.apache.spark.mllib.classification.LogisticRegressionModel
6 | import org.apache.spark.mllib.linalg.Vectors
7 | import org.apache.spark.{SparkConf, SparkContext}
8 | import utils.RedisUtil
9 |
10 | import scala.collection.mutable.ArrayBuffer
11 |
12 | /**
13 | * 堵车预测
14 | */
15 | object Prediction {
16 | def main(args: Array[String]): Unit = {
17 | //配置spark
18 | val sparkConf = new SparkConf()
19 | .setMaster("local[2]")
20 | .setAppName("TrafficPredict")
21 |
22 | val sc = new SparkContext(sparkConf)
23 |
24 | //时间设置,目的是:为了拼凑出redis中的key和field的字符串
25 | val dateSDF = new SimpleDateFormat("yyyyMMdd")
26 | val hourMinuteSDF = new SimpleDateFormat("HHmm")
27 | //2019-02-05 17:00
28 | val userSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm")
29 |
30 | //定义用于传入的,想要预测是否堵车的日期
31 | // val inputDateString = "2019-06-04 15:41"
32 | // 这里为了测试准确性,使用历史数据进行预测,即由模型推原历史数据
33 | val inputDateString = "2019-06-04 13:56"
34 | val inputDate = userSDF.parse(inputDateString)
35 |
36 | //得到redis中的key,例如:20190205
37 | val dayOfInputDate = dateSDF.format(inputDate)
38 | //1700
39 | val hourMinuteOfInputDate = hourMinuteSDF.format(inputDate)
40 |
41 | val dbIndex = 1
42 | val jedis = RedisUtil.pool.getResource
43 | jedis.select(dbIndex)
44 |
45 |
46 | //想要预测的监测点
47 | val monitorIDs = List("0005", "0015")
48 | val monitorRelations = Map[String, Array[String]](
49 | "0005" -> Array("0003", "0004", "0005", "0006", "0007"),
50 | "0015" -> Array("0013", "0014", "0015", "0016", "0017"))
51 |
52 | monitorIDs.map(monitorID => {
53 | val monitorRealtionArray = monitorRelations(monitorID)
54 | val relationInfo = monitorRealtionArray.map(monitorID => {
55 | (monitorID, jedis.hgetAll(dayOfInputDate + "_" + monitorID))
56 | })
57 |
58 | //装载目标时间点之前的3分钟的历史数据
59 | val dataX = ArrayBuffer[Double]()
60 |
61 | //组装数据的过程
62 | for (index <- Range(3, 0, -1)) {
63 | val oneMoment = inputDate.getTime - 60 * index * 1000
64 | val oneHM = hourMinuteSDF.format(oneMoment) //1657
65 |
66 | for ((k, v) <- relationInfo) {
67 | if (v.containsKey(oneHM)) {
68 | val speedAndCarCount = v.get(oneHM).split("_")
69 | val valueX = speedAndCarCount(0).toFloat / speedAndCarCount(1).toFloat
70 | dataX += valueX
71 | } else {
72 | dataX += 60.0F
73 | }
74 | }
75 | }
76 |
77 | // 打印三分钟之前的数据
78 | println(dataX)
79 | //加载模型
80 | val modelPath = jedis.hget("model", monitorID)
81 | val model = LogisticRegressionModel.load(sc, modelPath)
82 |
83 | //预测
84 | val prediction = model.predict(Vectors.dense(dataX.toArray))
85 | println(monitorID + ",堵车评估值:" + prediction + ",是否通畅:" + (if (prediction >= 3) "通畅" else "拥堵"))
86 | })
87 | RedisUtil.pool.returnResource(jedis)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tf_prediction/src/main/scala/utils/RedisUtil.scala:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import redis.clients.jedis._
4 |
5 | object RedisUtil {
6 | //配置redis基本连接参数
7 | val host = "192.168.126.132"
8 | val port = 6379
9 | val timeout = 30000
10 |
11 | val config = new JedisPoolConfig
12 |
13 | //设置允许最大的连接个数
14 | config.setMaxTotal(200)
15 | //最大空闲连接数
16 | config.setMaxIdle(50)
17 | //最小空闲连接数
18 | config.setMinIdle(8)
19 |
20 | //设置连接时的最大等待毫秒数
21 | config.setMaxWaitMillis(10000)
22 | //设置在获取连接时,是否检查连接的有效性
23 | config.setTestOnBorrow(true)
24 | //设置释放连接到池中时是否检查有效性
25 | config.setTestOnReturn(true)
26 |
27 | //在连接空闲时,是否检查连接有效性
28 | config.setTestWhileIdle(true)
29 |
30 | //两次扫描之间的时间间隔毫秒数
31 | config.setTimeBetweenEvictionRunsMillis(30000)
32 | //每次扫描的最多的对象数
33 | config.setNumTestsPerEvictionRun(10)
34 | //逐出连接的最小空闲时间,默认是180000(30分钟)
35 | config.setMinEvictableIdleTimeMillis(60000)
36 |
37 | //连接池
38 | lazy val pool = new JedisPool(config, host, port, timeout)
39 |
40 | //释放资源
41 | lazy val hook = new Thread{
42 | override def run() = {
43 | pool.destroy()
44 | }
45 | }
46 | sys.addShutdownHook(hook)
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/tf_prediction/tf_prediction.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/tf_producer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.zqtao
8 | tf_producer
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.kafka
14 | kafka-clients
15 | 0.11.0.2
16 |
17 |
18 |
19 | com.alibaba
20 | fastjson
21 | 1.2.41
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/tf_producer/src/main/resources/kafka.properties:
--------------------------------------------------------------------------------
1 | #设置kafka的brokerlist
2 | bootstrap.servers=192.168.126.132:9092
3 | key.serializer=org.apache.kafka.common.serialization.StringSerializer
4 | value.serializer=org.apache.kafka.common.serialization.StringSerializer
5 |
6 | acks=all
7 | retries=0
8 |
9 | #设置消费者组
10 | group.id=g_traffic1
11 |
12 | # 设置是否自动确认offset
13 | enable.auto.commit=true
14 |
15 | # 自动确认offset的间隔时间
16 | auto.commit.interval.ms=30000
17 |
18 | # 设置主题
19 | kafka.topics=traffic
20 |
21 | # 设置zk中follower和leader之间的关于kafka的信息同步时间间隔
22 | zookeeper.sync.time.ms=250
23 | num.io.threads=12
24 | batch.size=65536
25 | buffer.memory=524288
26 | # kafka中消息保存的时间
27 | log.retention.hours=2
28 |
--------------------------------------------------------------------------------
/tf_producer/src/main/scala/producer/Producer.scala:
--------------------------------------------------------------------------------
1 | package producer
2 |
3 | import java.text.DecimalFormat
4 | import java.util.Calendar
5 |
6 | import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
7 | import utils.PropertyUtil
8 |
9 | import scala.util.Random
10 | import java._
11 |
12 | import com.alibaba.fastjson.JSON
13 | /**
14 | * 模拟数据生产
15 | * 随机产生:监测点id,车速(按照5分钟的频率变换堵车状态)
16 | * 序列化为Json
17 | * 发送给kafka
18 | */
19 | object Producer {
20 | def main(args: Array[String]): Unit = {
21 | //读取kafka配置信息
22 | val props = PropertyUtil.properties
23 | //创建Kafka生产者对象
24 | val producer = new KafkaProducer[String, String](props)
25 |
26 | //模拟产生实时数据,单位:秒
27 | var startTime = Calendar.getInstance().getTimeInMillis() / 1000
28 | //数据模拟,堵车状态切换的周期单位为:秒
29 | val trafficCycle = 300
30 | //开始不停的产生实时数据
31 | val df = new DecimalFormat("0000")
32 | while(true){
33 | //模拟产生监测点id:0001~0020
34 | val randomMonitorId = df.format(Random.nextInt(20) + 1)
35 | //模拟车速
36 | var randomSpeed = "000"
37 | //得到本条数据产生时的当前时间,单位:秒
38 | val currentTime = Calendar.getInstance().getTimeInMillis() / 1000
39 | //每5分钟切换一次公路状态
40 | if(currentTime - startTime > trafficCycle){
41 | randomSpeed = new DecimalFormat("000").format(Random.nextInt(15))
42 | if(currentTime - startTime > trafficCycle * 2){
43 | startTime = currentTime
44 | }
45 | }else{
46 | randomSpeed = new DecimalFormat("000").format(Random.nextInt(30) + 30)
47 | }
48 |
49 | //该Map集合用于存放产生出来的数据
50 | val jsonMap = new util.HashMap[String, String]()
51 | jsonMap.put("monitor_id", randomMonitorId)
52 | jsonMap.put("speed", randomSpeed)
53 |
54 | //序列化
55 | val event = JSON.toJSON(jsonMap)
56 | println(event)
57 |
58 | //发送事件到kafka集群中
59 | producer.send(new ProducerRecord[String, String](PropertyUtil.getProperty("kafka.topics"), event.toString))
60 | Thread.sleep(100)
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tf_producer/src/main/scala/utils/PropertyUtil.scala:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import java.util.Properties
4 |
5 | object PropertyUtil {
6 | val properties = new Properties()
7 |
8 | try{
9 | //加载 kafka 配置属性
10 | val inputStream = ClassLoader.getSystemResourceAsStream("kafka.properties")
11 | properties.load(inputStream)
12 | }catch {
13 | case ex:Exception => println(ex)
14 | }finally {}
15 |
16 | // 通过key得到kafka的属性值
17 | def getProperty(key: String): String = properties.getProperty(key)
18 |
19 | }
--------------------------------------------------------------------------------