文章目录
概述
编写一个程序,每天凌晨3点模拟生成当天的新能源车辆数据(字段信息必须包含:车架号、行驶总里程、车速、车辆状态、充电状态、剩余电量SOC、SOC低报警、数据生成时间等)。
要求
1、最终部署时,要将这些数据写到第一题的HDFS中。
2、车辆数据要按天存储,数据格式是JSON格式,另外如果数据文件大于100M,则另起一个文件存。每天的数据总量不少于300M。比如假设程序是2023-01-1 03点运行,那么就将当前模拟生成的数据写入到HDFS的/can_data/2023-01-01文件夹的can-2023-01-01.json文件中,写满100M,则继续写到can-2023-01-01.json.2文件中,依次类推;
3、每天模拟生成的车辆数据中,必须至少包含20辆车的数据,即要含有20个车架号(一个车架号表示一辆车,用字符串表示);
4、每天生成的数据中要有少量(20条左右)重复数据(所有字段都相同的两条数据则认为是重复数据),且同一辆车的两条数据的数据生成时间间隔两秒;
5、每天生成的数据中要混有少量前几天的数据(即数据生成时间不是当天,而是前几天的)。
准备
我们要先部署三个节点
在每台机器上上配置hosts文件,如下:
cat /etc/hosts
192.168.53.4 master
192.168.53.100 slave1
192.168.53.101 slave2
修改IP后重启网卡
systemctl restart network
master的hosts映射配置好后,可以通过scp命令,将master修改好的/etc/hosts文件,同步到slave1、slave2主机上。
scp /etc/hosts root@slave1:/etc
设置免密登录
这里因为master、slave1、slave2三个节点都是从之前的已经安装好Hadoop伪分布式的虚拟机复制得来,而当时已经设置了免密登录,故不需再设置了。
根据概述我们知道,编写的程序主要是用来生成数据的,结果中要呈现不同的字段,要求中存在规定,所以我们先来写一个函数,函数里写明每一个字段的要求,再建立一个空的列表将这些数据循环爬取到列表里,然后返回列表。
生成车辆数据
def generate_data():
vin_list = ['VIN{}'.format(i) for i in range(1, 21)] # 车架号列表
data_list = []
for vin in vin_list:
mileage = round(random.uniform(1000, 10000), 2) # 行驶总里程
speed = round(random.uniform(0, 120), 2) # 车速
status = random.choice(['running', 'stopped']) # 车辆状态
charge_status = random.choice(['charging', 'discharging', 'idle']) # 充电状态
soc = round(random.uniform(0, 100), 2) # 剩余电量SOC
soc_low_alert = random.choice([True, False]) # SOC低报警
timestamp = int(time.time()) # 数据生成时间
data = {
'vin': vin,
'mileage': mileage,
'speed': speed,
'status': status,
'charge_status': charge_status,
'soc': soc,
'soc_low_alert': soc_low_alert,
'timestamp': timestamp
}
data_list.append(data)
return data_list
我们将充电状态划分为三个值,分别为放电,充电和空闲,这些我们都让他们随机生成。
将数据写入到HDFS中
数据写入过程详解:
(1)客户端发送消息给namenode请求上传不少于300m文件。
(2)Namenode应答可以上传。
(3)客户端上传之前对文件进行切片。
(4)客户端拿到datanode信息后,与datanode1直接建立通信通道,开始上传数据。
按天数储存数据,文件名为当天采集的日期,用os.path.join路径拼凑文件路径,可以传入多个路径,在进行判断,查看文件的大小,如果大于100M我们就传入下一个文件,然后将数据写进表格里。
写入数据到HDFS
def write_to_hdfs(data, hdfs_path):
# 按天存储数据
date_str = time.strftime('%Y-%m-%d', time.localtime(data[0]['timestamp']))
file_name = 'can-{}.json'.format(date_str)
file_path = os.path.join(hdfs_path, date_str, file_name)
if os.path.exists(file_path):
file_size = os.path.getsize(file_path)
if file_size > 100 * 1024 * 1024:
file_name = 'can-{}.{}.json'.format(date_str, int(file_size / (100 * 1024 * 1024)) + 1)
file_path = os.path.join(hdfs_path, date_str, file_name)
else:
os.makedirs(os.path.join(hdfs_path, date_str), exist_ok=True)
# 写入数据
with open(file_path, 'a') as f:
for item in data:
f.write(json.dumps(item) + '\n')
传入的数据 格式为json格式。
什么是json文件
json字符串本质就是一个字符串,只不过它满足一定的格式。比如:{“name”: “ligl”, “course”: [{“name”: “java”, “score”: 67}, {“name”: “spark”, “score”: 80}], “age”: 12} ,即为一个满足json格式的json字符串。
一个普通的文本文件,如果其每一行都是一个json字符串,那么可以称它为一个json文件,文件的后缀一般为.json。
JSON 文件基本格式
{} 大括号表示对象,包含N对字段名:字段值,每对字段名:字段值之间用逗号分隔,字段名用双引号括起来。
字段名和字段值之间用冒号分割。字段值值可以是字符串、数字、也可以是一个数组或对象。
[] 中括号表示数组。
生成数据并写入HDFS
我们使用随机数添加重复数据,循化添加前几天的数据进表格,将数据进行拼接,用sort()函数将时间顺序进行排序,设置添加时间间隔为2秒的重复数据,然后将数据写入到HDFS中。
#生成数据并写入HDFS
def generate_and_write(hdfs_path):
data = generate_data()
# 添加重复数据
repeat_data = random.sample(data, 20)
data += repeat_data
# 添加前几天的数据
for i in range(20):
timestamp = int(time.time()) - (i + 1) * 24 * 60 * 60
vin = random.choice(['VIN{}'.format(i) for i in range(1, 21)])
data.append({
'vin': vin,
'mileage': round(random.uniform(1000, 10000), 2),
'speed': round(random.uniform(0, 120), 2),
'status': random.choice(['running', 'stopped']),
'charge_status': random.choice(['charging', 'discharging', 'idle']),
'soc': round(random.uniform(0, 100), 2),
'soc_low_alert': random.choice([True, False]),
'timestamp': timestamp
})
# 按时间排序
data.sort(key=lambda x: x['timestamp'])
# 添加时间间隔为2秒的重复数据
for i in range(len(data) - 1):
if data[i]['vin'] == data[i + 1]['vin']:
data.insert(i + 1, data[i].copy())
data[i + 1]['timestamp'] += 2
# 写入HDFS
write_to_hdfs(data, hdfs_path)
最终呈现效果:
文件名是当天日期
数据效果: