作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Dallas H. Snider's profile image

Dallas H. Snider

Dallas拥有22年的数据库应用程序开发经验. 他使用过SQL服务器 & Oracle, in both Windows & Linux.

Previously At

Northrop Grumman
Share

Introduction

By now, 你可能听说过Hadoop分布式文件系统(HDFS), 特别是如果您是数据分析师或负责将数据从一个系统转移到另一个系统的人. 但是,HDFS相对于关系数据库有什么好处呢?

HDFS是一个可扩展的、开源的解决方案,用于存储和处理大量数据. HDFS已经被证明是可靠和高效的 many modern data centers.

HDFS使用商用硬件 open source software 以降低每字节存储的总成本.

具有内置的复制和对磁盘故障的弹性, HDFS是存储和处理用于分析的数据的理想系统. 它不需要支持事务原子性的基础和开销, consistency, isolation, 和持久性(ACID),这是传统关系数据库系统所必需的.

Moreover, 与企业和商业数据库相比, such as Oracle, 使用Hadoop作为分析平台可以避免任何额外的许可成本.

许多人在第一次学习HDFS时会问的一个问题是:我如何将现有的数据放入HDFS?

在本文中,我们将研究如何将数据从PostgreSQL数据库导入HDFS. We will use Apache Sqoop, 目前哪一种效率最高, 开源解决方案,用于在HDFS和关系数据库系统之间传输数据. Apache Sqoop的设计目的是将数据从关系数据库批量加载到HDFS(导入),并将数据从HDFS批量写入到关系数据库(导出)。.

HDFS

通过将数据迁移到HDFS来加快分析速度.

本教程中的步骤是为具有执行SQL查询的基本知识和HDFS命令的基本知识的人编写的.

使用的数据库系统为PostgreSQL 9.Windows为5,HDFS版本为Cloudera Hadoop 2.5.0-cdh5.2.0 on a Centos 6.4 Linux virtual machine.

Apache Sqoop依赖于特定于关系数据库供应商和数据库版本的JDBC驱动程序JAR文件.

执行本文中所示的步骤, 用户需要远程连接到PostgreSQL数据库的权限, SELECT 关系数据库的权限, write permissions on the HDFS, 并在Sqoop可执行文件上执行权限.

为了本教程的目的,我们创建了一个名为PostgreSQL的数据库 Toptal,并使其可以通过端口5432访问.

PostgreSQL Data Source

首先,在我们的PostgreSQL中 Toptal 数据库中,我们将创建一个名为 sales. 我们将假设OpenSSL证书和私钥文件已经存在于PostgreSQL服务器上.

Server [localhost]:
Database [postgres]: Toptal
Port [5432]:
Username [postgres]:
Password for user postgres:
psql (9.5.3)
Toptal=# create table sales
Toptal-# (
total (# pkSales整数约束salesKey主键,
Toptal(#    saleDate date,
总销售额:
total (# orderID int不为空,
total (# itemID int不为空
Toptal(# );
CREATE TABLE

接下来,我们将向表中插入20行:

Toptal=# insert into sales values (1, '2016-09-27', 1 ..23, 1, 1);
INSERT 0 1
Toptal=# insert into sales values (2, '2016-09-27', 2.34, 1, 2);
INSERT 0 1
Toptal=# insert into sales values (3, '2016-09-27', 1 ..23, 2, 1);
INSERT 0 1
Toptal=# insert into sales values (4, '2016-09-27', 2.34, 2, 2);
INSERT 0 1
Toptal=# insert into sales values (5, '2016-09-27', 3.45, 2, 3);
INSERT 0 1
Toptal=# insert into sales values (6, '2016-09-28', 3.45, 3, 3);
INSERT 0 1
Toptal=# insert into sales values (7, '2016-09-28', 4 ..56, 3, 4);
INSERT 0 1
Toptal=# insert into sales values (8, '2016-09-28', 5.67, 3, 5);
INSERT 0 1
Toptal=# insert into sales values (9, '2016-09-28', 1 ..23, 4, 1);
INSERT 0 1
Toptal=# insert into sales values (10, '2016-09-28', 1 ..23, 5, 1);
INSERT 0 1
Toptal=# insert into sales values (11, '2016-09-28', 1 ..23, 6, 1);
INSERT 0 1
Toptal=# insert into sales values (12, '2016-09-29', 1 ..23, 7, 1);
INSERT 0 1
Toptal=# insert into sales values (13, '2016-09-29', 2 ..34, 7, 2);
INSERT 0 1
Toptal=# insert into sales values (14, '2016-09-29', 3.45, 7, 3);
INSERT 0 1
Toptal=# insert into sales values (15, '2016-09-29', 4 ..56, 7, 4);
INSERT 0 1
Toptal=# insert into sales values (16, '2016-09-29', 5.67, 7, 5);
INSERT 0 1
Toptal=# insert into sales values (17, '2016-09-29', 6 ..78, 7, 6);
INSERT 0 1
Toptal=# insert into sales values (18, '2016-09-29', 7.89, 7, 7);
INSERT 0 1
Toptal=# insert into sales values (19, '2016-09-29', 7.89, 8, 7);
INSERT 0 1
Toptal=# insert into sales values (20, '2016-09-30', 1.23, 9, 1);
INSERT 0 1

让我们选择数据来验证数据看起来是否正确:

Toptal=# select * from sales;
 Pksales | sales date | sales amount | orderid | itemid
---------+------------+------------+---------+--------
       1 | 2016-09-27 |      $1.23 |       1 |      1
       2 | 2016-09-27 |      $2.34 |       1 |      2
       3 | 2016-09-27 |      $1.23 |       2 |      1
       4 | 2016-09-27 |      $2.34 |       2 |      2
       5 | 2016-09-27 |      $3.45 |       2 |      3
       6 | 2016-09-28 |      $3.45 |       3 |      3
       7 | 2016-09-28 |      $4.56 |       3 |      4
       8 | 2016-09-28 |      $5.67 |       3 |      5
       9 | 2016-09-28 |      $1.23 |       4 |      1
      10 | 2016-09-28 |      $1.23 |       5 |      1
      11 | 2016-09-28 |      $1.23 |       6 |      1
      12 | 2016-09-29 |      $1.23 |       7 |      1
      13 | 2016-09-29 |      $2.34 |       7 |      2
      14 | 2016-09-29 |      $3.45 |       7 |      3
      15 | 2016-09-29 |      $4.56 |       7 |      4
      16 | 2016-09-29 |      $5.67 |       7 |      5
      17 | 2016-09-29 |      $6.78 |       7 |      6
      18 | 2016-09-29 |      $7.89 |       7 |      7
      19 | 2016-09-29 |      $7.89 |       8 |      7
      20 | 2016-09-30 |      $1.23 |       9 |      1
(20 rows)

数据看起来不错,所以让我们继续.

使用Sqoop导入HDFS

定义了数据源后,我们现在准备将数据导入HDFS. The sqoop 下面列出了我们将要检查的命令, 我们将在接下来的要点中分解每个论点. 请注意,该命令应该在一个完整的行或, as shown below, 在除最后一行以外的每行末尾加上反斜杠(Linux命令行延续字符).

Sqoop import——connect’jdbc:postgresql://aaa.bbb.ccc.ddd:5432/Toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \
--username 'postgres' -P \
--table 'sales' \
--target-dir 'sales' \
--split-by 'pksales' 
  • sqoop import - The executable is named sqoop,我们指示它将数据从数据库的表或视图导入到HDFS.
  • --connect - With the --connect 参数时,我们将传入用于PostgreSQL的JDBC连接字符串. 在本例中,我们使用IP地址、端口号和数据库名称. We also need to specify that SSL 是被利用的还是需要供应的 SSLSocketFactory class to be used.
  • --username —本例中,用户名为PostgreSQL登录用户,而不是Windows登录用户. 用户必须具有连接到指定数据库和从指定表中进行选择的权限.
  • -P -这将提示命令行用户输入密码. 如果很少执行Sqoop,这可能是一个不错的选择. 还有多种其他方法可以自动将密码传递给命令, 但我们试图在本文中保持简单.
  • --table -这是我们传递PostgreSQL表名的地方.
  • --target-dir —该参数指定要存放数据的HDFS目录.
  • --split-by 我们必须为Sqoop提供一个唯一的标识符,以帮助它分配工作负载. Later in the job output, 我们将看到Sqoop在哪里选择最小值和最大值来帮助设置分割边界.

出于可重复性和编辑目的,将命令放在脚本中是个好主意, as shown below:

[hdfs@localhost:/sqoop]$ cat sqoopCommand.sh
Sqoop import——connect’jdbc:postgresql://aaa.bbb.ccc.ddd:5432/toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \
--username 'postgres' -P \
--table 'sales' \
--target-dir 'sales' \
--split-by 'pksales' 
[hdfs@localhost:/sqoop]$

现在,是时候执行上面的Sqoop命令脚本了. Sqoop命令的输出如下所示.

[hdfs@localhost:/sqoop]$ ./sqoopCommand.sh
16/10/02 18:58:34 INFO sqoop.Sqoop:运行Sqoop版本:1.4.5-cdh5.2.0
Enter password: 
16/10/02 18:58:40信息经理.SqlManager:使用默认的1000 fetchSize
16/10/02 18:58:40 INFO tool.CodeGenTool:开始代码生成
16/10/02 18:58:41信息经理.SqlManager:执行SQL语句:SELECT t.* FROM "sales" AS t LIMIT 1
16/10/02 18:58:41 INFO orm.CompilationManager: HADOOP_MAPRED_HOME是/usr/lib/hadoop-0.20-mapreduce
注意:/ tmp / sqoop-training /编译/ 77 f9452788024792770d52da72ae871f /销售.java使用或覆盖已弃用的API.
注意:使用-Xlint:deprecation重新编译以获取详细信息.
16/10/02 18:58:43 INFO orm.CompilationManager:编写jar文件:/tmp/sqoop-training/compile/77f9452788024792770d52da72ae871f/sales.jar
16/10/02 18:58:43警告经理.PostgresqlManager:看起来你正在从postgresql导入.
16/10/02 18:58:43警告经理.PostgresqlManager:这个传输可以更快! Use the --direct
16/10/02 18:58:43警告经理.PostgresqlManager:选项,用于执行特定于postgresql的快速路径.
16/10/02 18:58:43 INFO mapreduce.ImportJobBase:销售的开始导入
16/10/02 18:58:45警告映射.JobClient:使用GenericOptionsParser解析参数. 应用程序应该实现相同的工具.
16/10/02 18:58:46 INFO db.DBInputFormat:使用读提交事务隔离
16/10/02 18:58:46 INFO db.DataDrivenDBInputFormat: boundingvalquery: SELECT MIN("pksales"), MAX("pksales") FROM "sales"
16/10/02 18:58:47信息映射.JobClient:正在运行的作业:job_201609280401_0005
16/10/02 18:58:48信息映射.JobClient:  map 0% reduce 0%
16/10/02 18:59:04信息已映射.JobClient: map 50% reduce 0%
16/10/02 18:59:14 INFO映射.JobClient: map 75% reduce 0%
16/10/02 18:59:15 INFO已映射.JobClient: map 100% reduce 0%
16/10/02 18:59:18信息映射.JobClient: Job complete: job_201609280401_0005
16/10/02 18:59:18信息映射.JobClient: Counters: 23
16/10/02 18:59:18信息映射.JobClient:文件系统计数器
16/10/02 18:59:18信息映射.JobClient: FILE:读取的字节数=0
16/10/02 18:59:18信息映射.JobClient: FILE: Number of bytes written=1190344
16/10/02 18:59:18信息映射.JobClient: FILE:读取操作数=0
16/10/02 18:59:18信息映射.JobClient: FILE: Number of large read操作=0
16/10/02 18:59:18信息映射.JobClient: FILE:写操作数=0
16/10/02 18:59:18信息映射.JobClient: HDFS: Number of bytes read=438
16/10/02 18:59:18信息映射.JobClient: HDFS: Number of bytes written=451
16/10/02 18:59:18信息映射.JobClient: HDFS: Number of read operations=4
16/10/02 18:59:18信息映射.JobClient: HDFS: Number of large read operations=0
16/10/02 18:59:18信息映射.JobClient: HDFS:写操作数=4
16/10/02 18:59:18信息映射.JobClient:   Job Counters 
16/10/02 18:59:18信息映射.JobClient:已启动的映射任务=4
16/10/02 18:59:18信息映射.JobClient:所有映射在已占用槽中花费的总时间(ms)=48877
16/10/02 18:59:18信息映射.JobClient:所有减少的占用槽的总时间(ms)=0
16/10/02 18:59:18信息映射.JobClient:所有映射预留槽后等待的总时间(ms)=0
16/10/02 18:59:18信息映射.JobClient:预留槽位(ms)=0后,所有人花费的总等待时间减少
16/10/02 18:59:18信息映射.JobClient: Map-Reduce框架
16/10/02 18:59:18信息映射.JobClient:映射输入记录=20
16/10/02 18:59:18信息映射.JobClient:映射输出记录=20
16/10/02 18:59:18信息映射.JobClient:输入分割字节=438
16/10/02 18:59:18信息映射.JobClient:溢出记录=0
16/10/02 18:59:18信息映射.JobClient: CPU时间(ms)=3980
16/10/02 18:59:18信息映射.JobClient:物理内存(字节)快照=481574912
16/10/02 18:59:18信息映射.JobClient:虚拟内存(字节)快照=2949685248
16/10/02 18:59:18信息映射.JobClient:总提交堆使用(字节)=127401984
16/10/02 18:59:18信息映射uce.ImportJobBase:在33中传输了451字节.7555 seconds (13.3608 bytes/sec)
16/10/02 18:59:18信息映射uce.ImportJobBase:检索了20条记录.
[hdfs@localhost:/sqoop]$ 

注意,上面输出的最后一行显示检索了20条记录, 对应于20条记录在表上的PostgreSQL数据库.

在执行了Sqoop命令之后,我们可以执行 hdfs dfs -ls 命令查看在HDFS上使用表名默认创建的目录.

[hdfs@localhost:/sqoop]$ HDFS DFS -ls
Found 1 items
DRWXRWXRWX -总数据0 2016-10-02 18:59销售
[hdfs@localhost:/sqoop]$

We can use the hdfs dfs -ls 命令中列出的内容 sales directory. If you look on the HDFS, 您可以注意到,默认情况下,数据被分区并分布在四个文件中, not just contained in one.

[hdfs@localhost:/sqoop]$ HDFS DFS -ls sales
Found 6 items
-rw-rw-rw- 1总数据0 2016-10-02 18:59 sales/_SUCCESS
DRWXRWXRWX - total data 0 2016-10-02 18:58 sales/_logs . log
-rw-rw-rw- 1总数据110 2016-10-02 18:59销售/部分-00000
-rw-rw-rw- 1总数据111 2016-10-02 18:59销售/部分-00001
-rw-rw-rw- 1总数据115 2016-10-02 18:59销售/部分m-00002
-rw-rw-rw- 1汇总数据115 2016-10-02 18:59 sales/part-m-00003
[hdfs@localhost:/sqoop]$ 

The hdfs dfs -cat 命令将显示HDFS上销售数据的第一个分区中的所有记录.

[hdfs@localhost:/sqoop]$ HDFS DFS -cat sales/part-m-00000
1,2016-09-27,1.23,1,1
2,2016-09-27,2.34,1,2
3,2016-09-27,1.23,2,1
4,2016-09-27,2.34,2,2
5,2016-09-27,3.45,2,3
[hdfs@localhost:/sqoop]$

注意,默认的文件分隔符是逗号. Also, 注意,每个分区中只有5行, 因为源中的20行均匀地分布在四个分区中.

为了限制输出到屏幕的行数,我们可以通过管道输出 cat command to the head 命令,检查其他三个分区的内容,如下所示.

The -n 5 argument to the head 命令将屏幕输出限制为前五行.

(Note that in our case, 这是不必要的,因为开始时每个分区中只有5行. In practice, though, 每个分区中可能有比这更多的行,并且只需要检查前几行以确保它们看起来正确, 这就告诉你怎么做.)

[hdfs@localhost:/sqoop]$ HDFS DFS -cat sales/part-m-00001 |head -n
6,2016-09-28,3.45,3,3
7,2016-09-28,4.56,3,4
8,2016-09-28,5.67,3,5
9,2016-09-28,1.23,4,1
10,2016-09-28,1.23,5,1
[hdfs@localhost:/sqoop]$ HDFS DFS -cat sales/part-m-00002 |head -n
11,2016-09-28,1.23,6,1
12,2016-09-29,1.23,7,1
13,2016-09-29,2.34,7,2
14,2016-09-29,3.45,7,3
15,2016-09-29,4.56,7,4
[hdfs@localhost:/sqoop]$ HDFS DFS -cat sales/part-m-00003 |head -n
16,2016-09-29,5.67,7,5
17,2016-09-29,6.78,7,6
18,2016-09-29,7.89,7,7
19,2016-09-29,7.89,8,7
20,2016-09-30,1.23,9,1
[hdfs@localhost:/sqoop]$

如果您需要运行查询从PostgreSQL数据库中的多个表中提取数据, 这可以用下面的命令来完成:

[hdfs@localhost:/sqoop]$ cat sqoopCommand.sh
Sqoop import——connect’jdbc:postgresql://aaa.bbb.ccc.ddd:5432/toptal?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory' \
--username 'postgres' -P \
——target-dir 'creditCardOrders' \
--split-by 'pksales' \
--query "select s.pksales, s.saledate, s.saleamount, o.shippingtype, o.从销售中付款的方法是内部连接订单.orderid=o.orderid where o.methodofpayment='credit card' and \$CONDITIONS"
[hdfs@localhost:/sqoop]$

In the above command, 我们对Sqoop命令使用了一些相同的参数, 但是当与SQL命令一起使用时,它们的重要性有所不同.

  • --target-dir —目标目录告诉Sqoop将选择的数据存储在HDFS的哪个目录. 在使用自由格式查询时,Sqoop需要此参数.
  • --split-by -即使我们选择的是销售表的主键, 我们仍然需要为Sqoop提供唯一标识符,以帮助它分配工作负载.
  • --query -这是我们提供SQL查询的参数. 上面的查询用双引号括起来. Notice that there is not 包含查询的多行中的反斜杠(行连续字符). Also notice the and \$CONDITIONS at the end of the WHERE clause. 这是Sqoop所要求的,因为Sqoop会自动替换 $CONDITIONS 具有唯一表达式的令牌.

问题或没有问题:您应该考虑HDFS

与关系数据库相比,HDFS有很多优点. 如果您正在进行数据分析,那么您应该考虑将数据迁移到HDFS.

With the skills learned here, 将数据从关系数据库系统导入HDFS是一个简单直接的过程,只需一个命令即可完成. 虽然这些示例只有少量的行, 从PostgreSQL数据库表导入大量数据到HDFS的机制是相同的.

您甚至可以尝试导入大型表和不同的存储分隔符. 使用Apache Sqoop比将数据库数据导出到文件更有效, 将文件从数据库服务器传输到HDFS, 然后将文件加载到HDFS.

就这一主题咨询作者或专家.
Schedule a call
Dallas H. Snider's profile image
Dallas H. Snider

Located in Pace, FL, United States

Member since June 18, 2020

About the author

Dallas拥有22年的数据库应用程序开发经验. 他使用过SQL服务器 & Oracle, in both Windows & Linux.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Previously At

Northrop Grumman

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.