使用 SAP HANA 和 Amazon SageMaker 分析 200 年的气候数据






4.50/5 (6投票s)
利用全球历史气候网络项目的数据,我们可以使用 SAP HANA 内存数据库和 Amazon SageMaker 托管的 Jupyter notebook 来处理、分析和预测过去两个世纪收集到的数千兆字节的数值气候数据。
引言
在本文中,我将介绍一个端到端的系统,用于使用 SAP 的 HANA 内存数据库和 Amazon 的 SageMaker 云托管 Jupyter notebook 来探索和分析大量的气候数据。HANA 能够将数万亿字节的数据存储和查询在内存中,并且集成了图数据库和空间数据库引擎,使其成为探索性和统计数据分析的绝佳后端数据库平台,适用于研究气候变化所遇到的来自不同领域的各种大型数据集。Jupyter notebook 是当今数据探索和可视化的首选基于 Web 的环境,而 HANA 的客户端库可以直接与 Pandas 等 Python 数据框库集成。这使得 Jupyter notebook 用户可以执行在 HANA 实例上服务器端运行的查询,并将结果填充到客户端的 Pandas 数据框中,然后可以使用当今可用的数十个 Python 数据科学和机器学习库进行处理。Jupyter 和 Python 的易用性以及丰富的数据探索和可视化功能,结合 HANA 对大型数据集的低延迟内存查询,使其成为任何有兴趣研究气候变化的人的理想数据科学系统。
我们将使用运行在 Amazon EC2 服务上的 32GB SAP HANA 云实例来摄取来自 全球历史气候网络项目的数据,该项目聚合并公开了来自世界各地超过两个世纪的天气站观测数据。我们将使用免费的 SAP HANA Studio 作为我们的主要桌面 IDE,来管理和开发我们的云托管 HANA 数据库服务器。最后,我们将使用 Jupyter notebook 作为我们系统的用户前端,连接到我们的气候数据并运行查询,以及创建用于预测的模型。
背景
气候变化
气候变化是我们这个时代最具决定性的全球性问题之一,许多科学家、平民和政治领导人认为,我们必须迅速改变我们目前的生活方式,以避免在不久的将来发生灾难。研究气候变化及其后果意味着要处理从气象观测到地理数据,再到经济和人口数据等人类生活各个领域收集到的海量数据。
与此同时,也有许多气候变化怀疑论者。人们质疑气候科学家使用的理论假设和模型、收集数据的准确性和有效性,以及倡导需要对我们的经济体系和生活方式进行认真改革的科学家和公民的政治动机。
我们应该相信科学的一个重要原因是它的可重复性。使用气候科学家和其他科学家相同的数据,我们应该能够得出与科学家相同的结论。我们希望利用现有数据回答的有关全球气候的问题类型是:
- 全球气温是否逐年上升?
- 人类历史的每个世纪,全球气温如何变化?
- 世界上哪些地区的气温上升最快?
在云计算和用于数据科学与机器学习的开源软件框架出现之前,分析可用的气候数据将是一项艰巨的任务,需要超级计算机并产生可观的成本。如今,从气候变化的支持者到怀疑论者,任何人都可以随时在 AWS 上启动虚拟机,利用许多公开可用的气候数据集,并处理气候科学家所做的相同数字,以尝试重现他们的发现。
GHCN
全球历史气候网络(Global Historical Climatology Network)项目汇总了来自世界各地的气候数据,并通过一个托管 CSV 文件集合的 FTP 服务器向公众提供。GHCN-Daily 数据库是一个每日更新的数据集,收集了两个多世纪的天气站观测数据。
引用GHCN-Daily 数据库收集了来自世界各地天气站的每日数据,可能是最全面的日常现场气候测量全球数据集(Menne et al., 2012b)。自 Menne 等人(2012b)的概述以来,数据库中又增加了 38 个国家和地区(表 1)。该集合现在包含来自 218 个国家和地区的数据,其中一些记录可以追溯到 1763 年。GHCN-Daily 是按操作顺序更新的,尽管站点记录取决于来源。澳大利亚、日本、欧洲和北美可以获得相对密集的最新数据网络。对于某些地区,尤其是巴西、印度和南非,GHCN-Daily 的历史数据可用性很广泛,而更新数据仅提供给少数气象站。
-Jasmine B. D. Jaffrés GHCN-Daily:一个等待发现的气候数据宝库
GHCN-Daily 比 GHCN-Monthly 等其他 GHCN 数据集具有更详细的数据,后者仅包含月平均气温读数。使用 SAP HANA 和 Pandas、scikit-learn 等免费可用的数据科学库以及 Jupyter 等数据科学环境,任何人都可以分析和可视化 GHCN 收集的数据。
SAP HANA
HANA 是一个内存列式数据库,非常适合对数值数据进行聚合计算。从管理员的角度来看,SAP HANA 允许我们为不同的用户或项目规避不同的数据库系统(如 OLAP 多维数据集)。我们可以使用 HANA 的计算视图和分析视图,在单一数据源上创建低延迟视图,以满足从数据探索到聚合和统计计算的各种需求。每天更新的气候或其他数据可以插入到我们的数据库中,并在查询中得到反映,而无需重建多维数据集或其他分析结构。从开发者的角度来看,SAP 提供了免费的桌面和基于 Web 的开发环境,如 HANA Studio 和 Web Studio,并且 HANA 拥有庞大的数据库功能集和数据建模能力,可用于构建数据驱动的应用程序。
Amazon SageMaker
SageMaker 是 Amazon 的托管 Jupyter notebook 服务,它还附带一个 Amazon 托管的机器学习服务,让您可以创建和管理从数据标注到训练再到预测的整个机器学习工作流。SageMaker notebook 预装了 Pandas、scikit、TensorFlow、PyTorch 等数据科学和机器学习库。这些库可以通过 HANA Python 客户端库与我们的 HANA 数据库进行通信并执行服务器端查询,该库将 Pandas 数据框操作(如选择和过滤)映射为由服务器执行的 SQL 查询。
安装
我们的系统需要完成三个主要的安装任务:在 AWS 上创建运行 HANA 服务器的 EC2 实例,在我们的桌面机器上安装 HANA Studio IDE,以及创建我们的 Amazon SageMaker notebook 实例,其中包括 HANA Python 数据库客户端库。
AWS 上的 SAP HANA
SAP 提供了几个预装了 HANA express edition 的 AMI。32GB 镜像允许您创建使用高达 32GB RAM 的数据库,并且可以免费使用;您只需支付使用 EC2 实例和其他基础设施成本(如 AWS 上的存储)的费用。这使您可以相对便宜地试用功能齐全的 HANA 版本,而无需在自己的服务器上进行安装。您可以在 m4.2xlarge 实例上从 AWS Marketplace 快速启动 HANA 实例,该实例提供配备 8 个 vCPU 和 32GB RAM 的 Xeon E5-2686 处理器。SAP 提供的剩余配置说明 说明非常详细,应该可以很快地使服务器启动并运行。还有一些额外的要点需要补充:
- 确保为您的机器分配一个卷,并有足够的 EBS 存储空间来存储您要导入 HANA 的数据。对于大于 100GB 的大型数据文件,EC2 使用的默认卷大小不足。
- 您应该在您的 HOSTS 文件中为主机名 hxehosts 创建一个条目,指向您的 EC2 机器的公共 IP,并使用此主机名进行所有到 HANA 数据库的网络连接,无论是从 IDE 还是 Web 浏览器。
- 如果您只需要从您当前所在的工作站进行 SSH 访问,则请将 EC2 安全组中的入站 SSH 流量限制为您自己的 IP。
- 如果您想运行 SAP HANA Web IDE,则可能需要在 EC2 安全组中打开额外的端口。
SAP HANA Studio
SAP HANA Studio 是一个基于 Eclipse 的 IDE,用于管理和开发 SAP HANA。HANA Studio 可以连接到本地服务器实例以及托管在 AWS 上的实例。
HANA Studio 可以 免费下载和安装,只需要一个 JVM(如 Oracle Java 8)和一个较新的 Eclipse 版本。一旦启动并运行,您就可以使用在 EC2 服务器上的 HANA 设置步骤中配置的 SYSTEM 用户连接到运行 HANA 的 EC2 实例。确保您在从 HANA Studio 到数据库的客户端连接中选择使用 SSL,但取消选中验证 SSL 证书的选项,因为您最初将在新配置的服务器上使用自签名证书。
为了连接到运行在云端的 HANA 实例,我们必须确保我们的 EC2 实例被分配了一个具有正确入站规则的安全组。正如 Ryan 的教程一样,如果您想使用 Web Studio 或其他基于 Web 的 HANA 工具,您必须在您的 HOSTS 文件中添加一个条目,或者提供另一种方法来解析主机名 hxehost 到您的 HANA 服务器的公共 IP 地址。
Amazon SageMaker
可以从 AWS 控制台创建 Jupyter notebook 实例。
生命周期配置允许我们在 notebook 创建或运行时执行代码或 shell 脚本。理论上,我们可以使用生命周期配置在 notebook 运行之前安装 HANA Python 客户端库,但实际上我无法使其正常工作,因为在 notebook 环境之外安装 Python 包存在 已知问题。但是,我们可以在 notebook 开头的单元格中轻松安装所需的包。ml.t2.medium notebook 实例有 4GB 内存,足以运行针对我们数据库的查询。
开发
批量将数据导入 HANA
GHCN FTP 服务器有一个名为 superghcnd 的文件夹,其中包含一个单独的压缩 CSV 文件,该文件包含截至当前日期的整个 GHCN-Daily 数据集。* 整个 GCHN-Daily 数据集解压后超过 100GB,由于我们的 HANA 服务器内存有限,我们无法摄取整个数据集。幸运的是,在 *nix 系统上,我们有命令行工具可以轻松地将文件切分成更小的子集,而无需将整个文件读入内存。从我们 HANA 服务器的 shell 中,我们可以使用 curl
和 tar
下载并解压缩 superghcnd CSV 文件。然后可以使用 wc
命令计算 CSV 文件中的行数。
hxeadm@hxehost:~> cd /import
hxeadm@hxehost:/import> wc -l superghcnd.csv
2911313414 superghcnd.csv
hxeadm@hxehost:/import>
所以文件中大约有 30 亿行。HANA 的建议是将 50% 的 RAM 用于主表,其余用于视图。为了安全起见,我们现在只摄取 10GB 的数据,这大约是 3 亿行。我们将使用 head
命令从原始文件中获取前 3 亿行,并将其写入一个新的 CSV 文件。
hxeadm@hxehost:/import> head -n 300000000 superghcnd.csv > superghcnd_1.csv
hxeadm@hxehost:/import> ls
superghcnd.csv superghcnd_1.csv superghcnd_2.csv
hxeadm@hxehost:/import> ls -alF
total 109215760
drwxr-xrwx 2 root root 4096 Oct 30 19:31 ./
drwxr-xr-x 26 root root 4096 Oct 30 15:44 ../
-rw-r--rw- 1 hxeadm sapsys 101365375181 Oct 30 01:15 superghcnd.csv
-rw-r----- 1 hxeadm sapsys 10471526993 Oct 30 02:28 superghcnd_1.csv
所以我们现在有一个 10GB 的文件,可以导入到我们的 32GB HANA 实例中,这样应该会留下足够的 RAM 用于视图和查询。我们可以将此文件复制到我们的 HANA 实例的工作目录,该目录通常是 /usr/sap/HXE/HDB90/work。默认情况下,HANA 允许从该文件夹导入平面文件数据。然后我们必须创建将用于存储导入数据的表。一种简单的方法是使用 HANA Studio 中的导入向导加载一个与我们的数据集具有相同架构的小型 CSV 文件。
向导为我们提供了一个很好的 GUI,用于定义 CSV 文件字段到表列的映射。HANA Studio 将生成最符合导入数据的表定义,我们可以使用 GUI 将其调整为我们想要的。
我们可以使用 GUI 定义一个与 CSV 文件具有相同架构的表,并从我们的开发机器导入少量数据,然后删除这些数据,保留表定义。我们表定义的 DDL 看起来像:
CREATE COLUMN TABLE "GHCN"."DAILY" (
"ID" NVARCHAR(11) COMMENT 'Station ID',
"ODATE" DATE CS_DAYDATE COMMENT 'Observation Date',
"ELEMENT" NVARCHAR(4) COMMENT 'Element',
"OVALUE" INTEGER CS_INT COMMENT 'Observation Value',
"M" NVARCHAR(1) COMMENT 'Measurement flag',
"Q" NVARCHAR(1) COMMENT 'Quality flag',
"S" NVARCHAR(1) COMMENT 'Source flag'
) UNLOAD PRIORITY 5 AUTO MERGE
但这对于位于远程服务器上的 10GB 主导入文件不起作用。主要的 HANA 批量导入功能是通过 IMPORT SQL 语句调用的。
IMPORT FROM CSV FILE '/usr/sap/HXE/HDB90/work/superghcnd_1.csv' INTO GHCN.DAILY
WITH RECORD DELIMITED BY '\n'
FIELD DELIMITED BY ','
COLUMN LIST ("ID", "ODATE", "ELEMENT", "OVALUE" "M", "Q", "S")
FAIL ON INVALID DATA;
IMPORT 语句提供了许多可以提高批量导入性能的选项(例如要使用的线程数),但此代码段足以在合理的时间内将我们的 3 亿条记录导入 HANA。然后我们可以使用 hdbsql 工具从命令行查询服务器上 GHCN.DAILY 表中的行数。
hxeadm@hxehost:/usr/sap/HXE/HDB90> hdbsql -n hxehost:39013 -i 90 -u SYSTEM
Password:
Welcome to the SAP HANA Database interactive terminal.
Type: \h for help with commands
\q to quit
hdbsql SYSTEMDB=> SELECT COUNT(1) FROM GHCN.DAILY;
COUNT(1)
300000000
1 row selected (overall time 2808.359 msec; server time 629 usec)
数据导入完成后,我们可以着手在数据库中构建列视图包,这些视图提供了我们查询的主要分析结构。
使用 SageMaker Jupyter notebook 前端
安装
HANA
在数据库端,我们只需要为 notebook 创建一个 HANA 用户,这可以在 HANA Studio 中轻松完成。
最低要求,该用户需要对 GHCN.DAILY 表具有 SELECT 权限,并对我们在 _SYS_.BIC 模式下创建的列视图具有 SELECT 权限,这些视图在我们创建的 ghcn 包下。
Jupyter
当 notebook 启动时,我们应该将所有必要的 Python 包安装到我们的 notebook 实例中。我们需要 HANA 数据库客户端(hdbcli
),它可以在 PyPi 上找到并通过 pip
安装。我们还需要安装 hana_ml
库,它提供了 Pandas 数据框库与 HANA 客户端的集成。hana_ml
似乎不在 PyPi 上,因此必须手动安装。为了方便起见,我将包存档放在 S3 存储桶中,以便在需要时可以下载并从那里安装。
!pip install hdbcli > /dev/null 2>&1
!if [ ! -f hana_ml-1.0.7.tar.gz ]; then wget https://allisterb-hana.s3.us-east-2.amazonaws.com/hana_ml-1.0.7.tar.gz > /dev/null 2>&1; fi
!pip install hana_ml-1.0.7.tar.gz > /dev/null 2>&1
!pip show hana
一旦安装了必要的包,我们就可以从 notebook 中测试数据库连接。首先,我们创建一个名为 db.py 的小型脚本来存储我们的连接设置。
hxehost = my server ip
user = my user
passwd = my pass
然后我们可以测试连接。
import db #Store our HANA db settings in this module
import sys
from hdbcli import dbapi
conn = dbapi.connect(db.hxehost, 39013, db.user, db.passwd)
#Test that the connection is successfully established
print (conn.isconnected())
#Test we can access the GHCN.DAILY table
with conn.cursor() as cursor:
cursor.execute("SELECT COUNT(1) FROM GHCN.DAILY")
result = cursor.fetchone()
print (f'{result[0]} rows in table.')
这会产生以下输出:
True 300000000 rows in table.
现在我们准备开始查询了!
import pandas as pd
from hana_ml import dataframe
conn = dataframe.ConnectionContext(db.hxehost, 39013, db.user, db.passwd)
df = conn.table('DAILY', schema='GHCN')
df.head(5).collect()
DataFrame
对象执行与客户端上的数据框操作相对应的 SQL 语句,例如,我们可以询问 DataFrame
对象,调用 head()
函数对应的 SQL 语句是什么。
df.head(5).select_statement
这将打印出:
'SELECT TOP 5 * FROM (SELECT * FROM "GHCN"."DAILY") dt'
调用 DataFrame
对象上的 collect()
方法实际上会将 SQL 查询发送到服务器。我们还可以查询我们在 ghcn
包中创建的每日观测计算视图。
df = conn.table("ghcn/DAILY_STATION_OBSERVATION", schema="_SYS_BIC")
df.head(5).collect()
这将产生以下结果: