使用 MariaDB 处理 XML 文件

一月份我写了我的第一篇关于 node.js 和 MariaDB 的文章 。二月份我继续写了第二篇关于使用 jQuery 和一些 GIS 计算的文章。现在是第三篇了,这次的主要重点不再是 GIS 功能,而是 MariaDB 处理大量非结构化数据的能力。在本例中,我将重点介绍如何在不导入 XML 数据本身的情况下处理大量的 XML 文件。

MariaDB 10.0 于四月初正式发布 (GA),其中包含 Connect 引擎。它被开发用于动态访问各种数据源,从通过 ODBC 连接的其他数据库到 Web 日志文件。Connect 引擎与数据源建立连接,并将该数据源作为表暴露给 MariaDB。让我们开始吧!

首先,检查您是否没有安装 Connect 引擎,如果您以前没有使用过它,那么应该没有安装。它是一个单独的安装。要验证它是否已安装,请运行 SHOW ENGINES 命令。Connect 引擎在输出中简称为 CONNECT。我将在 Ubuntu 13.10 上运行此演示,因此以下说明将侧重于该平台,但我也会指出如何在其他平台上完成。

请确保您已配置 APT 以使用 MariaDB 仓库。有关说明可在 downloads.mariadb.org 的 MariaDB 仓库配置工具部分找到。添加仓库后,可以使用普通的 apt-get 命令安装 Connect 引擎。例如

sudo apt-get install mariadb-connect-engine-10.0
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libpango1.0-0 libpangox-1.0-0 libpangoxft-1.0-0
Use 'apt-get autoremove' to remove them.
The following extra packages will be installed:
  autotools-dev libltdl-dev libltdl7 libodbc1 libtool libxml2-dev odbcinst
  odbcinst1debian2 unixodbc unixodbc-dev
Suggested packages:
  libtool-doc libmyodbc odbc-postgresql tdsodbc unixodbc-bin autoconf automaken
  gfortran fortran95-compiler gcj pkg-config
The following NEW packages will be installed:
  autotools-dev libltdl-dev libltdl7 libodbc1 libtool libxml2-dev
  mariadb-connect-engine-10.0 odbcinst odbcinst1debian2 unixodbc unixodbc-dev
0 upgraded, 11 newly installed, 0 to remove and 7 not upgraded.
Need to get 2,472 kB of archives.
After this operation, 9,807 kB of additional disk space will be used.
Do you want to continue [Y/n]?

请注意,在 RPM 平台上,您可以使用 yum 执行类似操作,即yum install MariaDB-connect-engine .

接下来,告诉 MariaDB 启用 Connect 引擎

INSTALL SONAME 'ha_connect';

现在我们已经准备好所有前提条件来实际开始实现解决方案。由于我将继续使用我之前构建的开发演示,该演示是关于在 Google Maps 上显示跑步轨迹的,因此我将继续使用它。在本例中,我也会使用 GPX 文件。GPX 文件由许多 GPS 设备存储,包括跑步手表和智能手机。GPX 本身是一种数据表示格式,具有特定的 XML Schema

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="runtastic - makes sports funtastic, http://www.runtastic.com"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/1
    http://www.topografix.com/GPX/1/1/gpx.xsd
    http://www.garmin.com/xmlschemas/GpxExtensions/v3
    http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd
    http://www.garmin.com/xmlschemas/TrackPointExtension/v1
    http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd"
  xmlns="http://www.topografix.com/GPX/1/1"
  xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
  xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <metadata>
  <desc>Tillbaka för att plocka upp bilen från service</desc>
  <copyright author="www.runtastic.com">
  <year>2014</year>
  <license>http://www.runtastic.com</license>
  </copyright>
  <link href="http://www.runtastic.com">
  <text>runtastic</text>
  </link>
  <time>2013-09-23T13:30:54.000Z</time>
  </metadata>
  <trk>
  <link href="http://www.runtastic.com/sport-sessions/123539841">
  <text>Visit this link to view this activity on runtastic.com</text>
  </link>
  <trkseg>
  <trkpt lon="24.8140869140625000" lat="60.1844253540038991">
  <ele>1.84204363822937</ele>
  <time>2013-09-23T13:30:54.000Z</time>
  </trkpt>
  <trkpt lon="24.8141384124756001" lat="60.1844062805175994">
  <ele>1.72201466560364</ele>
  <time>2013-09-23T13:30:56.000Z</time>
  </trkpt>
...

对于演示,我将使用目录 /home/rasmus/nodegpxmariadb/public/uploads/,其中预先加载了一组 GPX 文件。现在开始有趣的部分。我想将这些 XML 格式文件中的数据提供给 MariaDB。使用 Connect 引擎创建一个新表非常简单直接:

CREATE TABLE GPXSource (
  filename VARCHAR(100) NOT NULL special=FILEID,
  lon double(20,16) NOT NULL field_format='@',
  lat double(20,16) NOT NULL field_format='@',
  ele double(20,16) NOT NULL field_format="*[local-name()='ele']",
  time datetime date_format="YYYY-MM-DD 'T' hh:mm:ss '.000Z'"
  field_format="*[local-name()='time']"
) ENGINE=CONNECT table_type=XML
  file_name="/home/rasmus/nodegpxmariadb/public/uploads/runtastic_*.gpx"
  tabname="//*[local-name()='trkseg']" multiple=1;

CREATE TABLE 语句中,您可以看到 Connect 被指定为引擎,table_type 选项设置为 XML,multiple 设置为 1 以允许处理多个文件,file_name 包含我想要访问的 XML 文件的路径和模式。在 tabname 选项中,指定了数据所在的 XML 节点。此节点中的数据将表示为表行。在本例中,该节点称为 trkseg。此节点包含我们感兴趣的所有 trkpt 节点。单个 trkpt 节点表示跑步时以特定间隔存储的轨迹点。一个轨迹点包括经度、纬度、海拔和时间。通过组合这些轨迹点,您将获得跑步轨迹的表示。这就是我将要做的事情。

CREATE TABLE 语句中还有一件事需要注意。选项 tabname 和表字段 ele 都包含命名空间指令,这些指令提供给 XML 解析器,以便它知道如何获取正确的节点。这有点棘手,但这与 GPX 命名空间和使用的 XML 解析器有关。Connect 引擎在 Linux 上使用 libxml2。

有了表 GPXSource,我们来尝试对其执行 SELECT 操作

MariaDB [running]> SELECT filename, COUNT(*) FROM GPXSource GROUP BY filename ORDER BY filename;
+--------------------------------------------------------------------------------+----------+
| filename                                                                       | COUNT(*) |
+--------------------------------------------------------------------------------+----------+
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140325_1154_Running.gpx |     3383 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140408_1133_Running.gpx |     1043 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140411_1341_Running.gpx |     2977 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140417_1140_Running.gpx |     2441 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140423_1150_Running.gpx |     2710 |
+--------------------------------------------------------------------------------+----------+
5 rows in set (0.12 sec)

瞧!我们可以看到它工作了,并且我获得了每个 GPX 文件中的轨迹点数量。

让我们尝试另一个 SELECT,我将在实际应用中使用它。我们希望通过计算每个 GPX 文件的第一个和最后一个轨迹点之间的差值来获取每次跑步的持续时间

SELECT filename, TIMEDIFF(MAX(time), MIN(time)) AS duration  FROM GPXSource GROUP BY filename ORDER BY filename;
+--------------------------------------------------------------------------------+----------+
| filename                                                                       | duration |
+--------------------------------------------------------------------------------+----------+
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20130923_1631_Running.gpx | 00:20:44 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20130925_1008_Running.gpx | 00:22:39 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140325_1154_Running.gpx | 02:14:15 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140408_1133_Running.gpx | 00:44:32 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140411_1341_Running.gpx | 01:59:09 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140417_1140_Running.gpx | 01:37:15 |
| /home/rasmus/nodegpxmariadb/public/uploads/runtastic_20140423_1150_Running.gpx | 01:56:12 |
+--------------------------------------------------------------------------------+----------+
7 rows in set (0.26 sec)

现在我拥有了创建示例应用程序所需的所有数据。  在这篇博文中,我不会深入探讨 Node.js 应用程序代码部分,但我已像以前一样在 Github 上公开了所有源代码:https://github.com/rasmushoj/nodejs-gpx-mariadb 。 希望您觉得有用。然而,通过 MariaDB 访问 XML 文件而不导入数据的最终结果如下所示:

MariaDB connect engine XML