目录
3. 使用 HdfsTextSimple Profile 写数据
HAWQ 不但可以读写自身系统中的表,而且能够访问 HDFS、Hive、HBase 等外部系统的数据,这是通过一个名为 PXF 的扩展框架实现的。大部分外部数据是以 HAWQ 外部表的形式进行访问的,但对于 Hive,除外部表方式,PXF 还能够与 HCatalog 结合直接查询 Hive 表。PXF 内建多个连接器,用户也可以按照 PXF API 创建自己的连接器,访问其他并行数据存储或处理引擎。
一、安装配置 PXF
如果使用 Ambari 安装管理 HAWQ 集群,那么不需要执行任何手工命令行安装步骤,从 Ambari web 接口就可以安装所有需要的 PXF 插件。详细安装步骤参考“HAWQ 技术解析(二) —— 安装部署”。如果使用命令行安装 PXF,参见“Installing PXF from the Command Line”。PXF 相关的缺省安装目录和文件如表1 所示。
目录 | 描述 |
/usr/lib/pxf | PXF 库目录。 |
/etc/pxf/conf | PXF 配置目录,该目录下包含 pxf-public.classpath、pxf-private.classpath 及其他配置文件。 |
/var/pxf/pxf-service | PXF 服务实例所在目录。 |
/var/log/pxf | 该目录包含 pxf-service.log 和所有 Tomcat 相关的日志文件。PXF 需要在主机上运行 Tomcat,用 Ambari 安装 PXF 时会自动安装 Tomcat,这些文件的属主是 pxf:pxf,对其他用户是只读的。 |
/var/run/pxf/catalina.pid | PXF Tomcat 容器的 PID 文件,存储进程号。 |
表1
与安装一样,PXF 也可以使用 Ambari 的图形界面进行交互式配置,完成后重启 PXF 服务以使配置生效。手工配置步骤参考“Configuring PXF”,注意,手工配置需要修改所有集群主机上的相关配置文件,然后重启所有节点上的 PXF 服务。
二、PXF profile
PXF profile 是一组通用元数据属性的集合,用于简化外部数据读写。PXF 自带多个内建的 profile,每个 profile 将一组元数据属性归于一类,使得对以下数据存储系统的访问更加容易:
- HDFS 文件数据(读写)
- Hive(只读)
- HBase(只读)
- JSON(只读)
表2 说明了 PXF 的内建 profile 及其相关 Java 类,这些 profile 在 /etc/pxf/conf/pxf-profiles.xml 文件中定义。
Profile | 描述 | 相关Java类 |
HdfsTextSimple | 读写 HDFS 上的平面文本文件,每条记录由固定分隔符的一行构成。 | org.apache.hawq.pxf.plugins.hdfs.HdfsDataFragmenter org.apache.hawq.pxf.plugins.hdfs.LineBreakAccessor org.apache.hawq.pxf.plugins.hdfs.StringPassResolver |
HdfsTextMulti | 从 HDFS 上的平面文件中读取具有固定分隔符的记录,每条记录由一行或多行(记录中包含换行符)构成。此 profile 是不可拆分的(非并行),比 HdfsTextSimple 读取慢。 | org.apache.hawq.pxf.plugins.hdfs.HdfsDataFragmenter org.apache.hawq.pxf.plugins.hdfs.QuotedLineBreakAccessor org.apache.hawq.pxf.plugins.hdfs.StringPassResolver |
Hive | 读 Hive 表,支持 text、RC、ORC、Sequence 或 Parquet 存储格式。 | org.apache.hawq.pxf.plugins.hive.HiveDataFragmenter org.apache.hawq.pxf.plugins.hive.HiveAccessor org.apache.hawq.pxf.plugins.hive.HiveResolver org.apache.hawq.pxf.plugins.hive.HiveMetadataFetcher org.apache.hawq.pxf.service.io.GPDBWritable |
HiveRC | 优化读取 RCFile 存储格式的 Hive 表,必须指定 DELIMITER 参数。 | org.apache.hawq.pxf.plugins.hive.HiveInputFormatFragmenter org.apache.hawq.pxf.plugins.hive.HiveRCFileAccessor org.apache.hawq.pxf.plugins.hive.HiveColumnarSerdeResolver org.apache.hawq.pxf.plugins.hive.HiveMetadataFetcher org.apache.hawq.pxf.service.io.Text |
HiveORC | 优化读取 ORCFile 存储格式的 Hive 表。 | org.apache.hawq.pxf.plugins.hive.HiveInputFormatFragmenter org.apache.hawq.pxf.plugins.hive.HiveORCAccessor org.apache.hawq.pxf.plugins.hive.HiveORCSerdeResolver org.apache.hawq.pxf.plugins.hive.HiveMetadataFetcher org.apache.hawq.pxf.service.io.GPDBWritable |
HiveText | 优化读取 TextFile 存储格式的 Hive 表,必须指定 DELIMITER 参数。 | org.apache.hawq.pxf.plugins.hive.HiveInputFormatFragmenter org.apache.hawq.pxf.plugins.hive.HiveLineBreakAccessor org.apache.hawq.pxf.plugins.hive.HiveStringPassResolver org.apache.hawq.pxf.plugins.hive.HiveMetadataFetcher org.apache.hawq.pxf.service.io.Text |
HBase | 读取 HBase 数据存储引擎。 | org.apache.hawq.pxf.plugins.hbase.HBaseDataFragmenter org.apache.hawq.pxf.plugins.hbase.HBaseAccessor org.apache.hawq.pxf.plugins.hbase.HBaseResolver |
Avro | 读取 Avro 文件。 | org.apache.hawq.pxf.plugins.hdfs.HdfsDataFragmenter org.apache.hawq.pxf.plugins.hdfs.AvroFileAccessor org.apache.hawq.pxf.plugins.hdfs.AvroResolver |
JSON | 读取 HDFS 上的 JSON 文件。 | org.apache.hawq.pxf.plugins.hdfs.HdfsDataFragmenter org.apache.hawq.pxf.plugins.json.JsonAccessor org.apache.hawq.pxf.plugins.json.JsonResolver |
表2
三、访问 HDFS 文件
HDFS 是 Hadoop 应用的主要分布式存储机制,PXF 的 HDFS 插件用于读取存储在 HDFS 文件中的数据,支持具有固定分隔符的文本和 Avro 两种文件格式。在使用 PXF 访问 HDFS 文件前,确认已经在集群所有节点上安装了 PXF HDFS 插件(Ambari 会自动安装),并授予了 HAWQ 用户(典型的是 gpadmin)对 HDFS 文件相应的读写权限。
1. PXF 支持的 HDFS 文件格式
PXF HDFS 插件支持对以下两种文件格式的读取:
- comma-separated value(.csv)或其他固定分隔符的平面文本文件。
- 由 JSON 定义的、基于 Schema 的 Avro 文件格式。
PXF HDFS 插件包括以下 Profile 支持上面的两类文件:
- HdfsTextSimple - 单行文本文件
- HdfsTextMulti - 内嵌换行符的多行文本文件
- Avro - Avro 文件
2. 查询外部 HDFS 数据
HAWQ 通过外部表的形式访问 HDFS 文件。下面是创建一个 HDFS 外部表的语法。
CREATE EXTERNAL TABLE <table_name>
( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<host>[:<port>]/<path-to-hdfs-file>
?PROFILE=HdfsTextSimple|HdfsTextMulti|Avro[&<custom-option>=<value>[...]]')
FORMAT '[TEXT|CSV|CUSTOM]' (<formatting-properties>);
CREATE EXTERNAL TABLE 语句中使用的各个关键字和相应值的描述如表3 所示。
关键字 | 值 |
<host>[:<port>] | HDFS NameNode 主机名、端口。 |
<path-to-hdfs-file> | HDFS 文件路径。 |
PROFILE | PROFILE 关键字指定为 HdfsTextSimple、HdfsTextMulti 或 Avro 之一。 |
<custom-option> | 与特定 PROFILE 对应的定制选项。 |
FORMAT 'TEXT' | 当 <path-to-hdfs-file> 指向一个单行固定分隔符的平面文件时,使用该关键字。 |
FORMAT 'CSV' | 当 <path-to-hdfs-file> 指向一个单行或多行的逗号分隔值(CSV)平面文件时,使用该关键字。 |
FORMAT 'CUSTOM' | Avro 文件使用该关键字。Avro 'CUSTOM' 格式只支持内建的(formatter='pxfwritable_import')格式属性。 |
<formatting-properties> | 与特定 PROFILE 对应的格式属性。 |
表3
下面是几个 HAWQ 访问 HDFS 文件的例子。
(1)使用 HdfsTextSimple Profile
HdfsTextSimple Profile 用于读取一行表示一条记录的平面文本文件或 CSV 文件,支持的 <formatting-properties> 是 delimiter,用来指定文件中每条记录的字段分隔符。
为 PXF 创建一个 HDFS 目录。
su - hdfs
hdfs dfs -mkdir -p /data/pxf_examples
hdfs dfs -chown -R gpadmin:gpadmin /data/pxf_examples
建立一个名为 pxf_hdfs_simple.txt 的平面文本文件,生成四条记录,使用逗号作为字段分隔符。
echo 'Prague,Jan,101,4875.33
Rome,Mar,87,1557.39
Bangalore,May,317,8936.99
Beijing,Jul,411,11600.67' > /tmp/pxf_hdfs_simple.txt
将文件传到 HDFS 上。
hdfs dfs -put /tmp/pxf_hdfs_simple.txt /data/pxf_examples/
显示 HDFS 上的 pxf_hdfs_simple.txt 文件内容。
hdfs dfs -cat /data/pxf_examples/pxf_hdfs_simple.txt
使用 HdfsTextSimple profile 创建一个可从 pxf_hdfs_simple.txt 文件查询数据的 HAWQ 外部表。delimiter=e',' 中的 e 表示转义,就是说如果记录正文中含有逗号,需要用 \ 符号进行转义。
su - gpadmin
psql -d db1
db1=# create external table pxf_hdfs_textsimple(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/data/pxf_examples/pxf_hdfs_simple.txt?profile=hdfstextsimple')
db1-# format 'text' (delimiter=e',');
CREATE EXTERNAL TABLE
db1=# select * from pxf_hdfs_textsimple;
location | month | num_orders | total_sales
-----------+-------+------------+-------------
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
(4 rows)
用 CSV 格式创建第二个外部表。当指定格式为‘CSV’时,逗号是缺省分隔符,不再需要使用 delimiter 说明。
db1=# create external table pxf_hdfs_textsimple_csv(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/data/pxf_examples/pxf_hdfs_simple.txt?profile=hdfstextsimple')
db1-# format 'csv';
CREATE EXTERNAL TABLE
db1=# select * from pxf_hdfs_textsimple_csv;
location | month | num_orders | total_sales
-----------+-------+------------+-------------
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
(4 rows)
(2)使用 HdfsTextMulti Profile
HdfsTextMulti profile 用于读取一条记录中含有换行符的平面文本文件。因为 PXF 将换行符作为行分隔符,所以当数据中含有换行符时需要用 HdfsTextMulti 进行特殊处理。HdfsTextMulti Profile 支持的 <formatting-properties> 是 delimiter,用来指定文件中每条记录的字段分隔符。
创建一个平面文本文件。
vim /tmp/pxf_hdfs_multi.txt
输入以下记录,以冒号作为字段分隔符,第一个字段中含有换行符。
"4627 Star Rd.
San Francisco, CA 94107":Sept:2017
"113 Moon St.
San Diego, CA 92093":Jan:2018
"51 Belt Ct.
Denver, CO 90123":Dec:2016
"93114 Radial Rd.
Chicago, IL 60605":Jul:2017
"7301 Brookview Ave.
Columbus, OH 43213":Dec:2018
将文件传到 HDFS 上。
su - hdfs
hdfs dfs -put /tmp/pxf_hdfs_multi.txt /data/pxf_examples/
使用 HdfsTextMulti profile 创建一个可从 pxf_hdfs_multi.txt 文件查询数据的外部表,指定分隔符是冒号。
db1=# create external table pxf_hdfs_textmulti(address text, month text, year int)
db1-# location ('pxf://hdp1:51200/data/pxf_examples/pxf_hdfs_multi.txt?profile=hdfstextmulti')
db1-# format 'csv' (delimiter=e':');
CREATE EXTERNAL TABLE
db1=# select * from pxf_hdfs_textmulti;
address | month | year
--------------------------+-------+------
4627 Star Rd. | Sept | 2017
San Francisco, CA 94107
113 Moon St. | Jan | 2018
San Diego, CA 92093
51 Belt Ct. | Dec | 2016
Denver, CO 90123
93114 Radial Rd. | Jul | 2017
Chicago, IL 60605
7301 Brookview Ave. | Dec | 2018
Columbus, OH 43213
(5 rows)
(3)Avro Profile
参见"Avro Profile"。
(4)访问 HDFS HA 集群中的文件
为了访问 HDFS HA 集群中的外部数据,将 CREATE EXTERNAL TABLE LOCATION 子句由 <host>[:<port>] 修改为 <HA-nameservice>。
gpadmin=# create external table pxf_hdfs_textmulti_ha (address text, month text, year int)
location ('pxf://mycluster/data/pxf_examples/pxf_hdfs_multi.txt?profile=hdfstextmulti')
format 'csv' (delimiter=e':');
gpadmin=# select * from pxf_hdfs_textmulti_ha;
查询结果如图1 所示。
图1
四、访问 Hive 数据
Hive 是 Hadoop 的分布式数据仓库框架,支持多种文件格式,如 CVS、RC、ORC、parquet 等,PXF 的 Hive 插件用于读取存储在 Hive 表中的数据。PXF 提供两种方式查询 Hive 表:
- 通过整合 PXF 与 HCatalog 直接查询。
- 通过外部表查询。
1. PXF 访问 Hive 的前提条件
在使用 PXF 访问 Hive 前,确认满足以下前提条件:
- 在 HAWQ 和 HDFS 集群的所有节点上(master、segment、NameNode、DataNode)安装了 PXF HDFS 插件。
- 在 HAWQ 和 HDFS 集群的所有节点上安装了 PXF Hive 插件。
- 如果配置了 Hadoop HA,PXF 也必须安装在所有运行 NameNode 服务的 HDFS 节点上。
- 所有 PXF 节点上都安装了 Hive 客户端。
- 集群所有节点上都安装了 Hive JAR 文件目录和 conf 目录。
- 已经测试了 PXF 访问 HDFS。
- 在集群中的一台主机上运行 Hive Metastore 服务。
- 在 NameNode 上的 hive-site.xml 文件中设置了 hive.metastore.uris 属性。
看似条件不少,但是如果使用 Ambari 安装管理 HAWQ 集群,并安装了 Hadoop 相关服务,则所有这些前置条件都已自动配置好,不需要任何手工配置。
2. PXF 支持的 Hive 文件格式
PXF Hive 插件支持的 Hive 文件格式及其访问这些格式对应的 profile 如表4 所示。
文件格式 | 描述 | Profile |
TextFile | 逗号、tab或空格分隔的平面文件格式或JSON格式。 | Hive、HiveText |
SequenceFile | 二进制键值对组成的平面文件。 | Hive |
RCFile | 记录由键值对组成的列数据,具有行高压缩率。 | Hive、HiveRC |
ORCFile | 优化的列式存储,减小数据大小。 | Hive |
Parquet | 压缩的列式存储。 | Hive |
Avro | 基于schema的、由JSON所定义的序列化格式。 | Hive |
表4
3. 数据类型映射
为了在 HAWQ 中表示 Hive 数据,需要将使用 Hive 私有数据类型的数据值映射为等价的 HAWQ 类型值。表5 是对 Hive 私有数据类型的映射规则汇总。
Hive 数据类型 | HAWQ 数据类型 |
boolean | bool |
int | int4 |
smallint | int2 |
tinyint | int2 |
bigint | int8 |
float | float4 |
double | float8 |
string | text |
binary | bytea |
timestamp | timestamp |
表5
除简单类型外,Hive 还支持 array、struct、map 等复杂数据类型,由于 HAWQ 原生不支持这些类型,PXF 将它们统一映射为 text 类型。可以创建 HAWQ 函数或使用应用程序抽取复杂数据类型子元素的数据。
下面是一些 HAWQ 访问 Hive 表的例子。
4. 准备示例数据
(1)准备数据文件
添加如下记录,用逗号分隔字段。
vi /tmp/pxf_hive_datafile.txt
Prague,Jan,101,4875.33
Rome,Mar,87,1557.39
Bangalore,May,317,8936.99
Beijing,Jul,411,11600.67
San Francisco,Sept,156,6846.34
Paris,Nov,159,7134.56
San Francisco,Jan,113,5397.89
Prague,Dec,333,9894.77
Bangalore,Jul,271,8320.55
Beijing,Dec,100,4248.41
(2)创建文本格式的 Hive 表 sales_info
create database test;
use test;
create table sales_info (location string, month string,
number_of_orders int, total_sales double)
row format delimited fields terminated by ','
stored as textfile;
(3)向 sales_info 表装载数据
load data local inpath '/tmp/pxf_hive_datafile.txt' into table sales_info;
(4)查询 sales_info 表数据验证装载数据是否成功
select * from sales_info;
(5)确认 sales_info 表在 HDFS 上的位置
在创建 HAWQ 外部表时需要用到该信息。
describe extended sales_info;
...
location:hdfs://mycluster/apps/hive/warehouse/test.db/sales_info
...
5. 使用 PXF 和 HCatalog 查询 Hive
HAWQ 可以获取存储在 HCatalog 中的元数据,通过 HCatalog 直接访问 Hive 表,而不用关心 Hive 表对应的底层文件存储格式。HCatalog 建立在 Hive metastore 之上,包含 Hive 的 DDL 语句。使用这种方式的好处是:
- 不须要知道 Hive 表结构。
- 不须要手工输入 Hive 表的位置与格式信息。
- 如果表的元数据改变,HCatalog 自动提供更新后的元数据,这是使用 PXF 静态外部表方式无法做到的。
图2 所示 HAWQ 如何使用 HCatalog 查询 Hive 表。
图2
- HAWQ 使用 PXF 从 HCatalog 查询表的元数据。
- HAWQ 用查询到的元数据创建一个内存目录表,如果一个查询中多次引用了同一个表,内存目录表可以减少对外部 HCatalog 的调用次数。
- PXF 使用内存目录表的元数据信息查询 Hive 表,查询结束后,内存目录表将被删除。
如果使用 Ambari 安装管理 HAWQ,并且已经启动了 Hive 服务,则不需要任何额外配置,就可以查询 Hive 表。
db1=# select * from hcatalog.test.sales_info;
location | month | number_of_orders | total_sales
---------------+-------+------------------+-------------
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
San Francisco | Sept | 156 | 6846.34
Paris | Nov | 159 | 7134.56
San Francisco | Jan | 113 | 5397.89
Prague | Dec | 333 | 9894.77
Bangalore | Jul | 271 | 8320.55
Beijing | Dec | 100 | 4248.41
(10 rows)
获取 Hive 表的字段和数据类型映射。
db1=# \d+ hcatalog.test.sales_info;
PXF Hive Table "test.sales_info"
Column | Type | Source type
------------------+--------+-------------
location | text | string
month | text | string
number_of_orders | int4 | int
total_sales | float8 | double
可以使用通配符获取所有 Hive 库表的信息。
\d+ hcatalog.test.*;
\d+ hcatalog.*.*;
还可以使用 pxf_get_item_fields 函数获得 Hive 表的描述信息,该函数目前仅支持 Hive profile。
db1=# select * from pxf_get_item_fields('hive','test.sales_info');
path | itemname | fieldname | fieldtype | sourcefieldtype
------+------------+------------------+-----------+-----------------
test | sales_info | location | text | string
test | sales_info | month | text | string
test | sales_info | number_of_orders | int4 | int
test | sales_info | total_sales | float8 | double
(4 rows)
pxf_get_item_fields 函数同样也支持通配符。
select * from pxf_get_item_fields('hive','test.*');
select * from pxf_get_item_fields('hive','*.*');
6. 查询 Hive 外部表
使用外部表方式需要标识适当的 profile。PXF Hive 插件支持三种 Hive 相关的 profile,Hive、HiveText 和 HiveRC。HiveText 和 HiveRC 分别针对 TEXT 和 RC 文件格式做了特别优化,而 Hive profile 可用于所有 PXF 支持的 Hive 文件存储类型。当底层 Hive 表由多个分区组成,并且分区使用了不同的文件格式,需要使用 Hive profile。
以下语法创建一个 HAWQ 的 Hive 外部表:
CREATE EXTERNAL TABLE <table_name>
( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<host>[:<port>]/<hive-db-name>.<hive-table-name>
?PROFILE=Hive|HiveText|HiveRC[&DELIMITER=<delim>'])
FORMAT 'CUSTOM|TEXT' (formatter='pxfwritable_import' | delimiter='<delim>')
CREATE EXTERNAL TABLE 语句中 Hive 插件使用关键字和相应值的描述如表6 所示。
关键字 | 值 |
<host>[:] | HDFS NameNode 主机名、端口号 |
<hive-db-name> | Hive 数据库名,如果忽略,缺省是 defaults。 |
<hive-table-name> | Hive 表名。 |
PROFILE | 必须是 Hive、HiveText 或 HiveRC 之一。 |
DELIMITER | 指定字段分隔符,必须是单个 ascii 字符或相应字符的十六进制表示。 |
FORMAT (Hive profile) | 必须指定为 CUSTOM,仅支持内建的 pxfwritable_import 格式属性。 |
FORMAT (HiveText and HiveRC profiles) | 必须指定为 TEXT,并再次指定字段分隔符。 |
表6
(1)Hive Profile
Hive profile 适用于任何 PXF 支持的 Hive 文件存储格式,它实际上是为底层文件存储类型选择最优的 Hive* profile。
db1=# create external table salesinfo_hiveprofile(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/test.sales_info?profile=hive')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=#
db1=# select * from salesinfo_hiveprofile;
location | month | num_orders | total_sales
---------------+-------+------------+-------------
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
San Francisco | Sept | 156 | 6846.34
Paris | Nov | 159 | 7134.56
San Francisco | Jan | 113 | 5397.89
Prague | Dec | 333 | 9894.77
Bangalore | Jul | 271 | 8320.55
Beijing | Dec | 100 | 4248.41
(10 rows)
注意外部表和 Hcatalog 查询计划的区别,如图3 所示。
图3
外部表查询使用了全部 24 个虚拟段,而 Hcatalog 查询只使用了 1 个虚拟段,显然外部表更加有效地利用了资源。
(2)HiveText Profile
使用 HiveText profile 时,必须在 LOCATION 和 FORMAT 两个子句中都指定分隔符选项。
db1=# create external table salesinfo_hivetextprofile(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/test.sales_info?profile=hivetext&delimiter=,')
db1-# format 'text' (delimiter=e',');
CREATE EXTERNAL TABLE
db1=# select * from salesinfo_hivetextprofile where location='Beijing';
location | month | num_orders | total_sales
----------+-------+------------+-------------
Beijing | Jul | 411 | 11600.67
Beijing | Dec | 100 | 4248.41
(2 rows)
(3)HiveRC Profile
建立一个 rcfile 格式的 Hive 表,并插入数据。
create table sales_info_rcfile (location string, month string,
number_of_orders int, total_sales double)
row format delimited fields terminated by ','
stored as rcfile;
insert into table sales_info_rcfile select * from sales_info;
查询 Hive 表。
db1=# create external table salesinfo_hivercprofile(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/test.sales_info_rcfile?profile=hiverc&delimiter=,')
db1-# format 'text' (delimiter=e',');
CREATE EXTERNAL TABLE
db1=#
db1=# select location, total_sales from salesinfo_hivercprofile;
location | total_sales
---------------+-------------
Prague | 4875.33
Rome | 1557.39
Bangalore | 8936.99
Beijing | 11600.67
San Francisco | 6846.34
Paris | 7134.56
San Francisco | 5397.89
Prague | 9894.77
Bangalore | 8320.55
Beijing | 4248.41
(10 rows)
(4)访问 Parquet 格式的 Hive 表
PXF Hive profile 支持分区或非分区的 Parquet 存储格式。建立一个 Parquet 格式的 Hive 表,并插入数据。
create table sales_info_parquet (location string, month string,
number_of_orders int, total_sales double)
stored as parquet;
insert into sales_info_parquet select * from sales_info;
查询 Hive 表。
db1=# create external table salesinfo_parquet (location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/test.sales_info_parquet?profile=hive')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=#
db1=# select * from salesinfo_parquet;
location | month | num_orders | total_sales
---------------+-------+------------+-------------
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
San Francisco | Sept | 156 | 6846.34
Paris | Nov | 159 | 7134.56
San Francisco | Jan | 113 | 5397.89
Prague | Dec | 333 | 9894.77
Bangalore | Jul | 271 | 8320.55
Beijing | Dec | 100 | 4248.41
(10 rows)
7. 复杂数据类型
(1)准备数据文件,添加如下记录,用逗号分隔字段,第三个字段是 array 类型,第四个字段是 map 类型。
vi /tmp/pxf_hive_complex.txt
3,Prague,1%2%3,zone:euro%status:up
89,Rome,4%5%6,zone:euro
400,Bangalore,7%8%9,zone:apac%status:pending
183,Beijing,0%1%2,zone:apac
94,Sacramento,3%4%5,zone:noam%status:down
101,Paris,6%7%8,zone:euro%status:up
56,Frankfurt,9%0%1,zone:euro
202,Jakarta,2%3%4,zone:apac%status:up
313,Sydney,5%6%7,zone:apac%status:pending
76,Atlanta,8%9%0,zone:noam%status:down
(2)建立 Hive 表
create table table_complextypes( index int, name string, intarray array<int>, propmap map<string, string>)
row format delimited fields terminated by ','
collection items terminated by '%'
map keys terminated by ':'
stored as textfile;
(3)向 Hive 表装载数据
load data local inpath '/tmp/pxf_hive_complex.txt' into table table_complextypes;
(4)查询 Hive 表,验证数据正确导入
select * from table_complextypes;
(5)建立 Hive 外部表并查询数据
db1=# create external table complextypes_hiveprofile(index int, name text, intarray text, propmap text)
db1-# location ('pxf://hdp1:51200/test.table_complextypes?profile=hive')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=# select * from complextypes_hiveprofile;
index | name | intarray | propmap
-------+------------+----------+------------------------------------
3 | Prague | [1,2,3] | {"zone":"euro","status":"up"}
89 | Rome | [4,5,6] | {"zone":"euro"}
400 | Bangalore | [7,8,9] | {"zone":"apac","status":"pending"}
183 | Beijing | [0,1,2] | {"zone":"apac"}
94 | Sacramento | [3,4,5] | {"zone":"noam","status":"down"}
101 | Paris | [6,7,8] | {"zone":"euro","status":"up"}
56 | Frankfurt | [9,0,1] | {"zone":"euro"}
202 | Jakarta | [2,3,4] | {"zone":"apac","status":"up"}
313 | Sydney | [5,6,7] | {"zone":"apac","status":"pending"}
76 | Atlanta | [8,9,0] | {"zone":"noam","status":"down"}
(10 rows)
可以看到,复杂数据类型都被简单地转化为 HAWQ 的 TEXT 类型。
8. 访问 Hive 分区表
PXF Hive 插件支持 Hive 的分区特性与目录结构,并且提供了所谓的分区过滤下推功能,可以利用 Hive 的分区消除特性,以降低网络流量和 I/O 负载。PXF 的分区过滤下推与 MySQL 的索引条件下推(Index Condition Pushdown,ICP)概念上类似,都是将过滤条件下推至更底层的存储上,以提高性能。
为了利用 PXF 的分区过滤下推功能,查询的 where 子句中应该只使用分区字段,否则,PXF 忽略分区过滤,过滤将在 HAWQ 端执行,影响查询性能。PXF 的 Hive 插件只对分区键执行过滤下推。
分区过滤下推缺省是启用的:
db1=# show pxf_enable_filter_pushdown;
pxf_enable_filter_pushdown
----------------------------
on
(1 row)
(1)使用 Hive Profile 访问同构分区数据
创建 Hive 表并装载数据。
create table sales_part (name string, type string, supplier_key int, price double)
partitioned by (delivery_state string, delivery_city string)
row format delimited fields terminated by ',';
insert into table sales_part partition(delivery_state = 'CALIFORNIA', delivery_city = 'Fresno')
values ('block', 'widget', 33, 15.17);
insert into table sales_part partition(delivery_state = 'CALIFORNIA', delivery_city = 'Sacramento')
values ('cube', 'widget', 11, 1.17);
insert into table sales_part partition(delivery_state = 'NEVADA', delivery_city = 'Reno')
values ('dowel', 'widget', 51, 31.82);
insert into table sales_part partition(delivery_state = 'NEVADA', delivery_city = 'Las Vegas')
values ('px49', 'pipe', 52, 99.82);
查询 sales_part 表。
select * from sales_part;
检查 sales_part 表在 HDFS 上的目录结构。
sudo -u hdfs hdfs dfs -ls -R /apps/hive/warehouse/test.db/sales_part
建立 PXF 外部表并查询数据。
db1=# create external table pxf_sales_part(
db1(# item_name text, item_type text,
db1(# supplier_key integer, item_price double precision,
db1(# delivery_state text, delivery_city text)
db1-# location ('pxf://hdp1:51200/test.sales_part?profile=hive')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=# select * from pxf_sales_part;
item_name | item_type | supplier_key | item_price | delivery_state | delivery_city
-----------+-----------+--------------+------------+----------------+---------------
block | widget | 33 | 15.17 | CALIFORNIA | Fresno
dowel | widget | 51 | 31.82 | NEVADA | Reno
cube | widget | 11 | 1.17 | CALIFORNIA | Sacramento
px49 | pipe | 52 | 99.82 | NEVADA | Las Vegas
(4 rows)
执行一个非过滤下推的查询。
db1=# select * from pxf_sales_part where delivery_city = 'Sacramento' and item_name = 'cube';
item_name | item_type | supplier_key | item_price | delivery_state | delivery_city
-----------+-----------+--------------+------------+----------------+---------------
cube | widget | 11 | 1.17 | CALIFORNIA | Sacramento
(1 row)
该查询会利用 Hive 过滤 delivery_city='Sacramento' 的分区,但 item_name 上的过滤条件不会下推至 Hive,因为它不是分区列。当所有 Sacramento 分区的数据传到 HAWQ 后,在 HAWQ 端执行 item_name 的过滤。
执行一个过滤下推的查询。
db1=# select * from pxf_sales_part where delivery_state = 'CALIFORNIA';
item_name | item_type | supplier_key | item_price | delivery_state | delivery_city
-----------+-----------+--------------+------------+----------------+---------------
cube | widget | 11 | 1.17 | CALIFORNIA | Sacramento
block | widget | 33 | 15.17 | CALIFORNIA | Fresno
(2 rows)
(2)使用 Hive Profile 访问异构分区数据
一个 Hive 表中的不同分区可能有不同的存储格式,PXF Hive profile 也支持这种情况。
建立 Hive 表。
$ HADOOP_USER_NAME=hdfs hive
create external table hive_multiformpart( location string, month string, number_of_orders int, total_sales double)
partitioned by( year string )
row format delimited fields terminated by ',';
记下 sales_info 和 sales_info_rcfile 表在 HDFS 中的位置。
describe extended sales_info;
describe extended sales_info_rcfile;
在我的环境中两个表的目录分别是:
location:hdfs://mycluster/apps/hive/warehouse/test.db/sales_info
location:hdfs://mycluster/apps/hive/warehouse/test.db/sales_info_rcfile
给 hive_multiformpart 表增加两个分区,位置分别指向 sales_info 和 sales_info_rcfile。
alter table hive_multiformpart add partition (year = '2013') location 'hdfs://mycluster/apps/hive/warehouse/test.db/sales_info';
alter table hive_multiformpart add partition (year = '2016') location 'hdfs://mycluster/apps/hive/warehouse/test.db/sales_info_rcfile';
显式标识与 sales_info_rcfile 表对应分区的文件格式。
alter table hive_multiformpart partition (year='2016') set fileformat rcfile;
此时查看两个分区的存储格式可以看到,sales_info 表对应的分区使用的是缺省的 TEXTFILE 格式,而 sales_info_rcfile 表对应的分区是 RCFILE 格式,分别如图4、图5 所示。
show partitions hive_multiformpart;
desc formatted hive_multiformpart partition(year=2013);
desc formatted hive_multiformpart partition(year=2016);
图4
图5
使用 Hcatalog 方式查询 hive_multiformpart 表。
db1=# select * from hcatalog.test.hive_multiformpart;
location | month | number_of_orders | total_sales | year
---------------+-------+------------------+-------------+------
...
Prague | Dec | 333 | 9894.77 | 2013
Bangalore | Jul | 271 | 8320.55 | 2013
Beijing | Dec | 100 | 4248.41 | 2013
Prague | Jan | 101 | 4875.33 | 2016
Rome | Mar | 87 | 1557.39 | 2016
Bangalore | May | 317 | 8936.99 | 2016
...
(20 rows)
使用外部表方式查询 hive_multiformpart 表。
db1=# create external table pxf_multiformpart(location text, month text, num_orders int, total_sales float8, year text)
db1-# location ('pxf://hdp1:51200/test.hive_multiformpart?profile=hive')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=# select * from pxf_multiformpart;
location | month | num_orders | total_sales | year
---------------+-------+------------+-------------+------
...
Prague | Dec | 333 | 9894.77 | 2013
Bangalore | Jul | 271 | 8320.55 | 2013
Beijing | Dec | 100 | 4248.41 | 2013
Prague | Jan | 101 | 4875.33 | 2016
Rome | Mar | 87 | 1557.39 | 2016
Bangalore | May | 317 | 8936.99 | 2016
...
(20 rows)
db1=# select sum(num_orders) from pxf_multiformpart where month='Dec' and year='2013';
sum
-----
433
(1 row)
五、访问 JSON 数据
PXF 的 JSON 插件用于读取存储在 HDFS 上的 JSON 文件,支持 N 层嵌套。为了使用 HAWQ 访问 JSON 数据,必须将 JSON 文件存储在 HDFS 上,并从 HDFS 数据存储创建外部表。在使用 PXF 访问 JSON 文件前,确认满足以下前提条件:
- 已经在集群所有节点上安装了 HDFS 插件(Ambari 会自动安装)。
- 已经在集群所有节点上安装了 JSON 插件(Ambari 会自动安装)。
- 已经测试了 PXF 对 HDFS 的访问。
1. PXF 与 JSON 文件协同工作
JSON 是一种基于文本的数据交换格式,其数据通常存储在一个以 .json 为后缀的文件中。一个 .json 文件包含一组对象的集合,一个 JSON 对象是一组无序的名/值对,值可以是字符串、数字、true、false、null,或者一个对象或数组,对象和数组可以嵌套。例如,下面是一个 JSON 数据文件的内容:
{
"created_at":"MonSep3004:04:53+00002013",
"id_str":"384529256681725952",
"user": {
"id":31424214,
"location":"COLUMBUS"
},
"coordinates":null
}
(1)JSON 到 HAWQ 的数据类型映射
为了在 HAWQ 中表示 JSON 数据,需要将使用私有数据类型的 JSON 值映射为等价的 HAWQ 数据类型值。表7 是对 JSON 数据映射规则的总结。
JSON 数据类型 | HAWQ 数据类型 |
integer、float、string、boolean | 使用对应的 HAWQ 内建数据类型(integer、real、double precision、char、varchar、text、boolean) |
Array | 使用 [] 标识一个特定数组中具有私有数据类型成员的下标。 |
Object | 使用 . 点标识符指定每个级别的具有私有数据类型的嵌套成员。 |
表7
(2)JSON 文件读模式
PXF 的 JSON 插件用两个模式之一读取数据。缺省模式是每行一个完整的 JSON 记录,同时也支持对多行构成的 JSON 记录的读操作。下面是每种读模式的例子,示例 schema 包含数据列的名称和数据类型如下:
- “created_at” - text
- “id_str” - text
- “user” - object(“id” - integer,“location” - text)
- “coordinates” - object(“type” - text,“values” - array(integer))
例1 - 每行一条 JSON 记录的读模式:
{"created_at":"FriJun0722:45:03+00002013","id_str":"343136551322136576","user":{"id":395504494,"location":"NearCornwall"},"coordinates":{"type":"Point","values": [ 6, 50 ]}},
{"created_at":"FriJun0722:45:02+00002013","id_str":"343136547115253761","user":{"id":26643566,"location":"Austin,Texas"}, "coordinates": null},
{"created_at":"FriJun0722:45:02+00002013","id_str":"343136547136233472","user":{"id":287819058,"location":""}, "coordinates": null}
例2 - 多行 JSON 记录读模式:
{
"root":[
{
"record_obj":{
"created_at":"MonSep3004:04:53+00002013",
"id_str":"384529256681725952",
"user":{
"id":31424214,
"location":"COLUMBUS"
},
"coordinates":null
},
"record_obj":{
"created_at":"MonSep3004:04:54+00002013",
"id_str":"384529260872228864",
"user":{
"id":67600981,
"location":"KryberWorld"
},
"coordinates":{
"type":"Point",
"values":[
8,
52
]
}
}
}
]
}
下面从 PXF 的 JSON 外部表查询上面的示例数据。
2. 将 JSON 数据装载到 HDFS
PXF 的 JSON 插件读取存储在 HDFS 中的 JSON 文件,因此在 HAWQ 查询 JSON 数据前,必须先将 JSON 文件传到 HDFS 上。将前面的单行和多行 JSON 记录分别保存到 singleline.json 和 multiline.json 文件中,而且确保 JSON 文件中没有空行,然后将文件传到 HDFS。
su - hdfs
hdfs dfs -mkdir /user/data
hdfs dfs -chown -R gpadmin:gpadmin /user/data
hdfs dfs -put singleline.json /user/data
hdfs dfs -put multiline.json /user/data
文件传到 HDFS 后,就可以通过 HAWQ 查询 JSON 数据。
3. 查询外部的 JSON 数据
使用下面的语法创建一个表示 JSON 数据的 HAWQ 外部表。
CREATE EXTERNAL TABLE <table_name>
( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ( 'pxf://<host>[:<port>]/<path-to-data>?PROFILE=Json[&IDENTIFIER=<value>]' )
FORMAT 'CUSTOM' ( FORMATTER='pxfwritable_import' );
CREATE EXTERNAL TABLE 语句中使用的各个关键字和相应值的描述如表8 所示。
关键字 | 值 |
<host>[:<port>] | HDFS NameNode 主机名、端口。 |
PROFILE | PROFILE 关键字必须指定为 Json。 |
IDENTIFIER | 只有当 JSON 文件是多行记录格式时,LOCATION 字符串中才包含 IDENTIFIER 关键字及其对应的值。<value>应该标识用以确定一个返回的 JSON 对象的成员名称,例如上面的示例2 中,应该指定 &IDENTIFIER=created_at。 |
FORMAT | FORMAT 子句必须指定为 CUSTOM。 |
FORMATTER | JSON 'CUSTOM'格式只支持内建的'pxfwritable_import'格式属性。 |
表8
创建一个基于单行记录的 JSON 外部表。
create external table sample_json_singleline_tbl(
created_at text,
id_str text,
text text,
"user.id" integer,
"user.location" text,
"coordinates.values[0]" integer,
"coordinates.values[1]" integer
)
location('pxf://hdp1:51200/user/data/singleline.json?profile=json')
format 'custom' (formatter='pxfwritable_import');
select * from sample_json_singleline_tbl;
查询结果如图6 所示。
图6
注意,原来 JSON 中的嵌套数据都被平面化展开。在查询结果中,使用 . 访问嵌套 user 对象(user.id和user.location),使用 [] 访问 coordinates.values 数组的元素(coordinates.values[0] 和 coordinates.values[1])。
多行记录的 JSON 外部表与单行的类似,只是需要指定 identifier,指定标识记录的键。
db1=# create external table sample_json_multiline_tbl(
db1(# created_at text,
db1(# id_str text,
db1(# text text,
db1(# "user.id" integer,
db1(# "user.location" text,
db1(# "coordinates.values[0]" integer,
db1(# "coordinates.values[1]" integer
db1(# )
db1-# location('pxf://hdp1:51200/user/data/multiline.json?profile=json&identifier=created_at')
db1-# format 'custom' (formatter='pxfwritable_import');
CREATE EXTERNAL TABLE
db1=# select * from sample_json_multiline_tbl;
created_at | id_str | text | user.id | user.location | coordinates.values[0] | coordinates.v
alues[1]
---------------------------+--------------------+------+----------+---------------+-----------------------+--------------
---------
MonSep3004:04:53+00002013 | 384529256681725952 | | 31424214 | COLUMBUS | |
MonSep3004:04:54+00002013 | 384529260872228864 | | 67600981 | KryberWorld | 8 |
52
(2 rows)
六、向 HDFS 中写入数据
PXF 只能向 HDFS 文件中写入数据,而对 Hive、HBase 和 JSON 等外部数据都是只读的。在使用 PXF 向 HDFS 文件写数据前,确认已经在集群所有节点上安装了 PXF HDFS 插件(Ambari 会自动安装),并授予了 HAWQ 用户(典型的是 gpadmin)对 HDFS 文件相应的读写权限。
1. 写 PXF 外部表
PXF HDFS 插件支持两种可写的 profile:HdfsTextSimple 和 SequenceWritable。创建 HAWQ 可写外部表的语法如下:
CREATE WRITABLE EXTERNAL TABLE <table_name>
( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<host>[:<port>]/<path-to-hdfs-file>
?PROFILE=HdfsTextSimple|SequenceWritable[&<custom-option>=<value>[...]]')
FORMAT '[TEXT|CSV|CUSTOM]' (<formatting-properties>);
CREATE EXTERNAL TABLE 语句中使用的各个关键字和相应值的描述如表9 所示。
关键字 | 值 |
<host>[:<port>] | HDFS NameNode 主机名、端口。 |
<path-to-hdfs-file> | HDFS 文件路径。 |
PROFILE | PROFILE 关键字指定为 HdfsTextSimple 或 SequenceWritable。 |
<custom-option> | 与特定 PROFILE 对应的定制选项。 |
FORMAT 'TEXT' | 当<path-to-hdfs-file>指向一个单行固定分隔符的平面文件时,使用该关键字。 |
FORMAT 'CSV' | 当<path-to-hdfs-file>指向一个单行或多行的逗号分隔值(CSV)平面文件时,使用该关键字。 |
FORMAT 'CUSTOM' | SequenceWritable profile 使用该关键字。SequenceWritable 'CUSTOM'格式仅支持内建的formatter='pxfwritable_export(写)和formatter='pxfwritable_import(读)格式属性。 |
表9
2. 定制选项
HdfsTextSimple 和 SequenceWritable profile 支持表10 所示的定制选项:
选项 | 值描述 | Profile |
COMPRESSION_CODEC | 压缩编解码对应的 Java 类名。如果不提供,不会执行数据压缩。支持的压缩编解码包括:org.apache.hadoop.io.compress.DefaultCodec 和 org.apache.hadoop.io.compress.BZip2Codec | HdfsTextSimple、SequenceWritable |
COMPRESSION_CODEC | org.apache.hadoop.io.compress.GzipCodec | HdfsTextSimple |
COMPRESSION_TYPE | 使用的压缩类型,支持的值为 RECORD(缺省)或 BLOCK。 | HdfsTextSimple、SequenceWritable |
DATA-SCHEMA | 写入器的序列化/反序列化类名。类所在的 jar 文件必须在 PXF classpath 中,该选项被 SequenceWritable profile 使用,并且没有缺省值。 | SequenceWritable |
THREAD-SAFE | 该 Boolean 值决定表查询是否运行在多线程模式,缺省值为 TRUE。 | HdfsTextSimple、SequenceWritable |
表10
3. 使用 HdfsTextSimple Profile 写数据
HdfsTextSimple profile 用于向单行每记录(不含内嵌换行符)的固定分隔符平面文件写数据。使用 HdfsTextSimple Profile 的建立可写表时,可以选择记录或块压缩,支持以下压缩编解码方法。
- org.apache.hadoop.io.compress.DefaultCodec
- org.apache.hadoop.io.compress.GzipCodec
- org.apache.hadoop.io.compress.BZip2Codec
HdfsTextSimple profile 支持的格式属性为'delimiter',标识字段分隔符,缺省值为逗号(,)。
(1)创建可写外部表,数据写到 HDFS 的 /data/pxf_examples/pxfwritable_hdfs_textsimple1 目录中,字段分隔符为逗号。
create writable external table pxf_hdfs_writabletbl_1(location text, month text, num_orders int, total_sales float8)
location ('pxf://hdp1:51200/data/pxf_examples/pxfwritable_hdfs_textsimple1?profile=hdfstextsimple')
format 'text' (delimiter=e',');
(2)向 pxf_hdfs_writabletbl_1 表插入数据。
insert into pxf_hdfs_writabletbl_1 values ( 'Frankfurt', 'Mar', 777, 3956.98 );
insert into pxf_hdfs_writabletbl_1 values ( 'Cleveland', 'Oct', 3812, 96645.37 );
insert into pxf_hdfs_writabletbl_1 select * from pxf_hdfs_textsimple;
(3)查看 HDFS 文件的内容。
[hdfs@hdp1 ~]$ hdfs dfs -cat /data/pxf_examples/pxfwritable_hdfs_textsimple1/*
Frankfurt,Mar,777,3956.98
Cleveland,Oct,3812,96645.37
Prague,Jan,101,4875.33
Rome,Mar,87,1557.39
Bangalore,May,317,8936.99
Beijing,Jul,411,11600.67
[hdfs@hdp1 ~]$ hdfs dfs -ls /data/pxf_examples/pxfwritable_hdfs_textsimple1
Found 3 items
-rw-r--r-- 3 pxf gpadmin 26 2017-03-22 10:45 /data/pxf_examples/pxfwritable_hdfs_textsimple1/236002_0
-rw-r--r-- 3 pxf gpadmin 28 2017-03-22 10:45 /data/pxf_examples/pxfwritable_hdfs_textsimple1/236003_0
-rw-r--r-- 3 pxf gpadmin 94 2017-03-22 10:46 /data/pxf_examples/pxfwritable_hdfs_textsimple1/236004_15
[hdfs@hdp1 ~]$ hdfs dfs -cat /data/pxf_examples/pxfwritable_hdfs_textsimple1/236002_0
Frankfurt,Mar,777,3956.98
[hdfs@hdp1 ~]$ hdfs dfs -cat /data/pxf_examples/pxfwritable_hdfs_textsimple1/236003_0
Cleveland,Oct,3812,96645.37
[hdfs@hdp1 ~]$ hdfs dfs -cat /data/pxf_examples/pxfwritable_hdfs_textsimple1/236004_15
Prague,Jan,101,4875.33
Rome,Mar,87,1557.39
Bangalore,May,317,8936.99
Beijing,Jul,411,11600.67
[hdfs@hdp1 ~]$
可以看到,一共写入了 6 条记录,生成了 3 个文件。其中两个文件各有 1 条记录,另外一个文件中有 4 条记录,记录以逗号作为字段分隔符。
(4)查询可写外部表。
HAWQ 不支持对可写外部表的查询,为了查询可写外部表的数据,需要建立一个可读外部表,指向 HDFS 的相应文件。
db1=# select * from pxf_hdfs_writabletbl_1;
ERROR: External scan error: It is not possible to read from a WRITABLE external table. Create the table as READABLE instead. (CTranslatorDXLToPlStmt.cpp:1041)
db1=# create external table pxf_hdfs_textsimple_r1(location text, month text, num_orders int, total_sales float8)
db1-# location ('pxf://hdp1:51200/data/pxf_examples/pxfwritable_hdfs_textsimple1?profile=hdfstextsimple')
db1-# format 'csv';
CREATE EXTERNAL TABLE
db1=# select * from pxf_hdfs_textsimple_r1;
location | month | num_orders | total_sales
-----------+-------+------------+-------------
Cleveland | Oct | 3812 | 96645.37
Frankfurt | Mar | 777 | 3956.98
Prague | Jan | 101 | 4875.33
Rome | Mar | 87 | 1557.39
Bangalore | May | 317 | 8936.99
Beijing | Jul | 411 | 11600.67
(6 rows)
(5)建立一个使用 Gzip 压缩,并用冒号(:)做字段分隔符的可写外部表,注意类名区分大小写。
create writable external table pxf_hdfs_writabletbl_2 (location text, month text, num_orders int, total_sales float8)
location ('pxf://hdp1:51200/data/pxf_examples/pxfwritable_hdfs_textsimple2?profile=hdfstextsimple&compression_codec=org.apache.hadoop.io.compress.GzipCodec')
format 'text' (delimiter=e':');
(6)插入数据。
insert into pxf_hdfs_writabletbl_2 values ( 'Frankfurt', 'Mar', 777, 3956.98 );
insert into pxf_hdfs_writabletbl_2 values ( 'Cleveland', 'Oct', 3812, 96645.37 );
(7)使用 -text 参数查看压缩的数据。
[hdfs@hdp1 ~]$ hdfs dfs -text /data/pxf_examples/pxfwritable_hdfs_textsimple2/*
Frankfurt:Mar:777:3956.98
Cleveland:Oct:3812:96645.37
[hdfs@hdp1 ~]$
可以看到刚插入的两条记录,记录以冒号作为字段分隔符。
七、删除外部表
使用 drop external table <table_name> 语句删除外部表,该语句并不删除外部数据,因为外部数据不是由 HAWQ 管理的。