这个项目构建了一个完整的天气预报大数据处理流水线,从数据采集到最终可视化呈现。作为一名长期从事大数据开发的工程师,我认为这类项目最核心的价值在于打通了从原始数据到业务洞察的全链路。我们团队最近刚完成一个类似的空气质量分析系统,踩了不少坑后总结出几个关键点:
首先,天气预报数据具有明显的时空特性,数据量大且增长迅速。以全国300个城市、每小时采集一次计算,单日数据量就超过7万条。传统单机处理方式在存储和计算上都会遇到瓶颈,这正是Hadoop生态系统大显身手的地方。
其次,气象数据的分析价值往往体现在长期趋势和异常检测上。比如去年夏季某城市连续高温天数的统计分析,或者突发暴雨前的湿度变化模式识别。这些都需要对海量历史数据进行高效处理。
我们的技术栈采用经典Lambda架构,兼顾批处理和实时性需求:
code复制数据源层 → 采集层 → 存储层 → 处理层 → 服务层 → 展示层
具体组件选型如下:
为什么选择Scrapy而不是Requests?
Scrapy的异步处理能力更适合大规模爬取。我们实测发现,在爬取中国天气网时,Scrapy的吞吐量是Requests的3-5倍。更重要的是其内置的:
HDFS存储设计要点
我们采用时间分区+城市编码的目录结构:
code复制/weather
/raw/dt=20230801/city=10128
/processed/dt=20230801
这种结构便于:
爬虫代码需要特别注意反爬策略。以中国天气网为例,我们通过以下方式保证稳定采集:
python复制class WeatherSpider(scrapy.Spider):
name = "weather"
custom_settings = {
'DOWNLOAD_DELAY': 2,
'CONCURRENT_REQUESTS_PER_DOMAIN': 4,
'RETRY_TIMES': 5,
'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
def start_requests(self):
cities = ['101280101', '101020100'] # 城市编码列表
for city in cities:
url = f'http://www.weather.com.cn/weather/{city}.shtml'
yield scrapy.Request(url, meta={'city_code': city})
重要提示:实际部署时需要配置代理IP池,建议使用Redis维护可用IP列表,每个请求随机选取代理。
数据清洗关键步骤
java复制// 示例MapReduce清洗逻辑
public class WeatherCleaner extends Mapper<LongWritable, Text, Text, NullWritable> {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
protected void map(LongWritable key, Text value, Context context) {
try {
WeatherRecord record = parseRecord(value);
if (isValid(record)) {
String output = String.format("%s,%s,%.1f,%d",
record.cityCode,
sdf.format(record.timestamp),
record.temperature,
record.humidity);
context.write(new Text(output), NullWritable.get());
}
} catch (Exception e) {
context.getCounter("CLEAN", "ERROR").increment(1);
}
}
}
我们采用Pyecharts生成动态图表,以下是一个温度趋势分析示例:
python复制from pyecharts import options as opts
from pyecharts.charts import Line
def draw_temperature_trend(data):
line = (
Line()
.add_xaxis(data['dates'])
.add_yaxis("最高温度", data['max_temp'],
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]))
.add_yaxis("最低温度", data['min_temp'],
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="min")]))
.set_global_opts(
title_opts=opts.TitleOpts(title="城市温度趋势"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
datazoom_opts=[opts.DataZoomOpts()]
)
)
return line
我们创建的Hive表采用了多重优化策略:
sql复制CREATE EXTERNAL TABLE weather.analysis (
city_code STRING,
timestamp TIMESTAMP,
temperature DECIMAL(3,1),
humidity SMALLINT
)
PARTITIONED BY (dt STRING, hour STRING)
CLUSTERED BY (city_code) INTO 32 BUCKETS
STORED AS ORC
LOCATION '/weather/analysis'
TBLPROPERTIES (
'orc.compress'='SNAPPY',
'orc.bloom.filter.columns'='city_code',
'orc.create.index'='true'
);
优化效果对比:
| 优化前 | 优化后 | 提升幅度 |
|---|---|---|
| 查询耗时 | 12.3s | 2.1s |
| 存储空间 | 1.2TB | 780GB |
问题1:HDFS写入速度慢
bash复制# 调整HDFS客户端配置
hadoop fs -Ddfs.blocksize=268435456 -put largefile /weather
问题2:Hive查询OOM
java.lang.OutOfMemoryError: GC overhead limit exceededsql复制SET hive.exec.reducers.bytes.per.reducer=256000000;
SET hive.auto.convert.join=false;
SET mapreduce.map.memory.mb=4096;
在实际部署后,我们发现几个有价值的扩展点:
实时分析扩展
预测模型集成
python复制from sklearn.ensemble import RandomForestRegressor
def train_model(data):
X = data[['temp_prev', 'humidity_prev']]
y = data['temperature']
model = RandomForestRegressor(n_estimators=100)
model.fit(X, y)
return model
多云架构支持
这个项目最让我有成就感的是,当看到气象部门使用我们的系统快速定位到某次寒潮的提前预警特征时。大数据技术真正的价值,就在于能让海量数据开口"说话",为决策提供有力支撑。