

# 在 DynamoDB 和 HDFS 之间复制数据
<a name="EMRforDynamoDB.CopyingData.HDFS"></a>

如果 DynamoDB 表有数据，则可以使用 Hive 将数据复制到 Hadoop Distributed File System（HDFS）。

如果运行的 MapReduce 任务需要 DynamoDB 数据，则可以执行此操作。如果将数据从 DynamoDB 复制到 HDFS，Hadoop 可以并行使用 Amazon EMR 集群的所有可用节点进行处理。MapReduce 任务完成后，可以将结果从 HDFS 写入 DDB。

在以下示例中，Hive 将读取和写入以下 HDFS 目录：`/user/hadoop/hive-test`

**注意**  
本部分中的示例假定已遵循 [教程：使用 Amazon DynamoDB 和 Apache Hive](EMRforDynamoDB.Tutorial.md) 步骤，在 DynamoDB 中有一个名为 *ddb\$1features* 的外部表。

**Topics**
+ [使用 Hive 默认格式复制数据](#EMRforDynamoDB.CopyingData.HDFS.DefaultFormat)
+ [使用用户指定格式复制数据](#EMRforDynamoDB.CopyingData.HDFS.UserSpecifiedFormat)
+ [复制没有列映射的数据](#EMRforDynamoDB.CopyingData.HDFS.NoColumnMapping)
+ [访问 HDFS 的数据](#EMRforDynamoDB.CopyingData.HDFS.ViewingData)

## 使用 Hive 默认格式复制数据
<a name="EMRforDynamoDB.CopyingData.HDFS.DefaultFormat"></a>

**Example 从 DynamoDB 到 HDFS**  
使用 `INSERT OVERWRITE` 语句直接写入 HDFS。  

```
INSERT OVERWRITE DIRECTORY 'hdfs:///user/hadoop/hive-test'
SELECT * FROM ddb_features;
```
HDFS 的数据文件如下所示：  

```
920709^ASoldiers Farewell Hill^ASummit^ANM^A32.3564729^A-108.33004616135
1178153^AJones Run^AStream^APA^A41.2120086^A-79.25920781260
253838^ASentinel Dome^ASummit^ACA^A37.7229821^A-119.584338133
264054^ANeversweet Gulch^AValley^ACA^A41.6565269^A-122.83614322900
115905^AChacaloochee Bay^ABay^AAL^A30.6979676^A-87.97388530
```
每个字段由一个 SOH 字符分隔（标题开头，0x01）。在文件中，SOH 显示为 **^A**。

**Example 从 HDFS 到 DynamoDB**  

1. 创建一个映射到 HDFS 中未设置格式数据的外部表。

   ```
   CREATE EXTERNAL TABLE hdfs_features_unformatted
       (feature_id       BIGINT,
       feature_name      STRING ,
       feature_class     STRING ,
       state_alpha       STRING,
       prim_lat_dec      DOUBLE ,
       prim_long_dec     DOUBLE ,
       elev_in_ft        BIGINT)
   LOCATION 'hdfs:///user/hadoop/hive-test';
   ```

1. 将数据复制到 DynamoDB。

   ```
   INSERT OVERWRITE TABLE ddb_features
   SELECT * FROM hdfs_features_unformatted;
   ```

## 使用用户指定格式复制数据
<a name="EMRforDynamoDB.CopyingData.HDFS.UserSpecifiedFormat"></a>

如果要使用不同字段分隔符，则可以创建映射到 HDFS 目录的外部表。可以使用此技术创建具有逗号分隔值 (CSV) 的数据文件。

**Example 从 DynamoDB 到 HDFS**  

1. 创建映射到 HDFS 的 Hive 外部表。执行此操作时，请确保数据类型与 DynamoDB 外部表的数据类型一致。

   ```
   CREATE EXTERNAL TABLE hdfs_features_csv
       (feature_id       BIGINT,
       feature_name      STRING ,
       feature_class     STRING ,
       state_alpha       STRING,
       prim_lat_dec      DOUBLE ,
       prim_long_dec     DOUBLE ,
       elev_in_ft        BIGINT)
   ROW FORMAT DELIMITED
   FIELDS TERMINATED BY ','
   LOCATION 'hdfs:///user/hadoop/hive-test';
   ```

1. 从 DynamoDB 复制数据。

   ```
   INSERT OVERWRITE TABLE hdfs_features_csv
   SELECT * FROM ddb_features;
   ```
HDFS 中的数据文件如下所示：  

```
920709,Soldiers Farewell Hill,Summit,NM,32.3564729,-108.3300461,6135
1178153,Jones Run,Stream,PA,41.2120086,-79.2592078,1260
253838,Sentinel Dome,Summit,CA,37.7229821,-119.58433,8133
264054,Neversweet Gulch,Valley,CA,41.6565269,-122.8361432,2900
115905,Chacaloochee Bay,Bay,AL,30.6979676,-87.9738853,0
```

**Example 从 HDFS 到 DynamoDB**  
使用单个 HiveQL 语句，可以用 HDFS 的数据填充 DynamoDB 表：  

```
INSERT OVERWRITE TABLE ddb_features
SELECT * FROM hdfs_features_csv;
```

## 复制没有列映射的数据
<a name="EMRforDynamoDB.CopyingData.HDFS.NoColumnMapping"></a>

可以采用原始格式从 DynamoDB 复制数据，写入 HDFS，无需指定任何数据类型或列映射。您可以使用此方法创建 DynamoDB 数据存档，存储在 HDFS。



**注意**  
如果 DynamoDB 表包含 Map、List、Boolean 或 Null 类型的属性，则这是使用 Hive 将数据从 DynamoDB 复制到 HDFS 的唯一方法。

**Example 从 DynamoDB 到 HDFS**  

1. 创建与 DynamoDB 表关联的外部表。（此 HiveQL 语句中没有 `dynamodb.column.mapping`。）

   ```
   CREATE EXTERNAL TABLE ddb_features_no_mapping
       (item MAP<STRING, STRING>)
   STORED BY 'org.apache.hadoop.hive.dynamodb.DynamoDBStorageHandler'
   TBLPROPERTIES ("dynamodb.table.name" = "Features");
   ```

   

1. 创建另一个与 HDFS 目录关联的外部表。

   ```
   CREATE EXTERNAL TABLE hdfs_features_no_mapping
       (item MAP<STRING, STRING>)
   ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\t'
   LINES TERMINATED BY '\n'
   LOCATION 'hdfs:///user/hadoop/hive-test';
   ```

1. 将数据从 DynamoDB 复制到 HDFS。

   ```
   INSERT OVERWRITE TABLE hdfs_features_no_mapping
   SELECT * FROM ddb_features_no_mapping;
   ```
HDFS 中的数据文件如下所示：  

```
Name^C{"s":"Soldiers Farewell Hill"}^BState^C{"s":"NM"}^BClass^C{"s":"Summit"}^BElevation^C{"n":"6135"}^BLatitude^C{"n":"32.3564729"}^BId^C{"n":"920709"}^BLongitude^C{"n":"-108.3300461"}
Name^C{"s":"Jones Run"}^BState^C{"s":"PA"}^BClass^C{"s":"Stream"}^BElevation^C{"n":"1260"}^BLatitude^C{"n":"41.2120086"}^BId^C{"n":"1178153"}^BLongitude^C{"n":"-79.2592078"}
Name^C{"s":"Sentinel Dome"}^BState^C{"s":"CA"}^BClass^C{"s":"Summit"}^BElevation^C{"n":"8133"}^BLatitude^C{"n":"37.7229821"}^BId^C{"n":"253838"}^BLongitude^C{"n":"-119.58433"}
Name^C{"s":"Neversweet Gulch"}^BState^C{"s":"CA"}^BClass^C{"s":"Valley"}^BElevation^C{"n":"2900"}^BLatitude^C{"n":"41.6565269"}^BId^C{"n":"264054"}^BLongitude^C{"n":"-122.8361432"}
Name^C{"s":"Chacaloochee Bay"}^BState^C{"s":"AL"}^BClass^C{"s":"Bay"}^BElevation^C{"n":"0"}^BLatitude^C{"n":"30.6979676"}^BId^C{"n":"115905"}^BLongitude^C{"n":"-87.9738853"}
```
每个字段以 STX 字符（文本开头，0x02）开头，以 ETX 字符（文本末尾，0x03）结尾。在文件中，STX 显示为 **^B**，ETX 显示为 **^C**。

**Example 从 HDFS 到 DynamoDB**  
使用单个 HiveQL 语句，可以用 HDFS 的数据填充 DynamoDB 表：  

```
INSERT OVERWRITE TABLE ddb_features_no_mapping
SELECT * FROM hdfs_features_no_mapping;
```

## 访问 HDFS 的数据
<a name="EMRforDynamoDB.CopyingData.HDFS.ViewingData"></a>

HDFS 是一个分布式文件系统，可供 Amazon EMR 集群的所有节点访问。如果使用 SSH 连接主节点，则可以使用命令行工具访问 Hive 写入 HDFS 的数据。

HDFS 与主节点的本地文件系统不一样。无法使用标准 Linux 命令（例如 `cat`、`cp`、`mv` 或 `rm`）处理 HDFS 的文件和目录。应使用 `hadoop fs` 命令执行此类任务。

以下步骤假设已使用本节介绍的一种方法，将数据从 DynamoDB 复制到 HDFS。

1. 如果当前处于 Hive 命令提示符下，请退出到 Linux 命令提示符。

   ```
   hive> exit;
   ```

1. 列出 HDFS 的 /user/hadoop/hive-test 目录的内容。（这是 Hive 从 DynamoDB 复制数据的位置。）

   ```
   hadoop fs -ls /user/hadoop/hive-test
   ```

   结果应如下所示：

   ```
   Found 1 items
   -rw-r--r-- 1 hadoop hadoop 29504 2016-06-08 23:40 /user/hadoop/hive-test/000000_0
   ```

   文件名 (*000000\$10*) 系统生成。

1. 查看文件的内容：

   ```
   hadoop fs -cat /user/hadoop/hive-test/000000_0
   ```
**注意**  
在此示例中，文件相对较小（约 29 KB）。对非常大或包含不可打印字符的文件使用此命令时，请小心。

1. （可选）可以将数据文件从 HDFS 复制到主节点的本地文件系统。执行此操作后，可以使用标准 Linux 命令行实用程序处理文件中的数据。

   ```
   hadoop fs -get /user/hadoop/hive-test/000000_0
   ```

   此命令不会覆盖文件。
**注意**  
主节点的本地文件系统容量有限。请勿将此命令用于大于本地文件系统可用空间的文件。