Impala 使用文本数据文件


Impala支持使用文本文件作为输入和输出的存储格式。文本文件是一种方便的格式,可用于与其他生成或读取分隔文本文件的应用程序或脚本进行交换,例如使用逗号或制表符作为分隔符的CSV或TSV。

文本文件的列定义也非常灵活。例如,一个文本文件可能有比Impala表更多的字段,这些额外的字段在查询过程中会被忽略;或者它的字段可能比Impala表少,而那些缺失的字段NULL在查询中被视为值。您可以在表中将字段视为数字或时间戳,然后用于ALTER TABLE ... REPLACE COLUMNS将它们切换为字符串,或者反过来。

文件类型

格式

压缩编解码器

是否支持Impala创建

是否支持Impala插入

Text

非结构化

bzip2、deflate、gzip、LZO、Snappy、zstd

是的。对于CREATE TABLEwith noSTORED AS子句,默认文件格式是未压缩的文本,值由 ASCII0x01字符分隔 (通常表示为 Ctrl-A)。

如果未压缩则支持,相反则不支持

如果使用LZO压缩,则必须在Hive中创建表并加载数据。

如果使用其他类型的压缩,则必须通过LOAD DATA、Hive 或在 HDFS 中手动加载数据。

Impala 文本表的查询性能

以文本格式存储的数据相对庞大,查询效率不如Parquet等二进制格式。如果文本表是您接收数据的格式并且您无法控制该过程,或者您是一个相对较新的Hadoop用户并且不熟悉以其他格式生成文件的技术,则您通常将文本表与Impala一起使用。(因为默认格式CREATE TABLE是文本,您可以将第一个Impala表创建为文本而不考虑性能。)无论哪种方式,寻找机会为最关键的性能查询中使用的表使用更有效的文件格式。

对于经常查询的数据,可以将原始文本数据文件加载到一个Impala表中,然后使用INSERT语句将数据转移到另一个使用Parquet文件格式的表中;数据在存储在目标表中时会自动转换。

对于更紧凑的数据,请考虑对文本文件使用LZO压缩。LZO是Impala支持文本数据的唯一压缩编解码器,因为LZO数据文件的“可拆分”性质允许不同节点并行处理同一文件的不同部分。

您还可以使用以bzip2、deflate、gzip、Snappy或zstd格式压缩的文本数据。由于这些压缩格式不像LZO那样“可拆分”,因此Impala对它们进行并行查询的机会较少。因此,如果这些类型的压缩数据是您接收数据的格式,请仅为方便起见使用这些类型的压缩数据。如果有选择,最好对文本数据使用LZO压缩,或者使用INSERT ... SELECT语句将数据转换为Parquet,将原始数据复制到Parquet表中。

笔记:Impala支持由该bzip2命令创建的bzip文件,但不支持该命令创建的具有多个流的bzip文件pbzip2。Impala仅解码来自此类文件第一部分的数据,导致结果不完整。

Impala可以容纳单个bzip文件的最大大小为1 GB(解压缩后)。

Impala支持由zstd命令行工具创建的zstd文件。

在Impala 2.6及更高版本中,Impala查询针对存储在Amazon S3 中的文件进行了优化。对于使用文件格式的Parquet,ORC,RCFile,SequenceFile,Avro的,和未压缩文本Impala表中,设置fs.s3a.block.size了在核心的site.xml 配置文件决定Impala如何划分的读取数据文件的I/O工作。此配置设置以字节为单位指定。默认情况下,此值为33554432 (32 MB),这意味着Impala将文件上的S3读取操作并行化,就好像它们由32MB 块组成一样。例如,如果您的S3查询主要访问由MapReduce或Hive编写的 Parquet文件,则增加fs.s3a.block.size到134217728 (128 MB) 以匹配这些文件的行组大小。如果大多数S3查询涉及Impala编写的Parquet文件,请增加到fs.s3a.block.size268435456 (256 MB) 以匹配Impala生成的行组大小。

创建文本表

要使用文本数据文件创建表格:

如果文本数据文件的确切格式(例如分隔符)不重要,请使用CREATE TABLE末尾不带额外子句的 语句来创建文本格式表。例如:

create table my_table(id int, s string, n int, t timestamp, b boolean);

任何INSERT语句创建的数据文件都将使用 Ctrl-A 字符(十六进制 01)作为每个列值之间的分隔符。

一个常见的用例是将现有的文本文件导入 Impala 表。语法更冗长;重要的部分是FIELDS TERMINATED BY子句,它必须在ROW FORMAT DELIMITED子句之前 。该语句可以以STORED AS TEXTFILE子句结尾,但该子句是可选的,因为文本格式表是默认设置。例如:

create table csv(id int, s string, n int, t timestamp, b boolean)
  row format delimited
  fields terminated by ',';

create table tsv(id int, s string, n int, t timestamp, b boolean)
  row format delimited
  fields terminated by '\t';

create table pipe_separated(id int, s string, n int, t timestamp, b boolean)
  row format delimited
  fields terminated by '|'
  stored as textfile;

您可以创建带有特定分隔符的表格,以导入熟悉的格式(例如 CSV、TSV 或竖线分隔)的文本文件。您还可以使用这些表来生成输出数据文件,方法是通过INSERT ... SELECT语法将数据复制到其中,然后从 Impala 数据目录中提取数据文件。

在 Impala 1.3.1 及更高版本中,您可以指定分隔符'\0'以将 ASCII 0 ( nul) 字符用于文本表:

create table nul_separated(id int, s string, n int, t timestamp, b boolean)
  row format delimited
  fields terminated by '\0'
  stored as textfile;

笔记:不要在您构建的文本数据文件中用引号将字符串值括起来。如果您需要在字段值中包含分隔符,例如将带逗号的字符串值放入 CSV 格式的数据文件中,请在CREATE TABLE带有ESCAPED BY子句的语句中指定转义字符,并在任何分隔符之前立即插入该字符需要转义的字符。

发出语句以查看每个表如何在 Impala 内部表示的详细信息。 DESCRIBE FORMATTED table_name

复杂类型注意事项:虽然您可以使用Impala 2.3及更高版本中提供的复杂类型(ARRAYSTRUCT、 和 MAP)以这种文件格式创建表,但目前,Impala 只能在 Parquet 表中查询这些类型。 上述规则的一个例外是对包含复杂类型的 RCFile 表的查询。Impala 2.6及更高版本中允许此类查询 。COUNT(*)

文本表的数据文件

当 Impala 查询包含文本格式数据的表时,它会查询该表的数据目录中的所有数据文件,但有一些例外:

  • Impala 会忽略任何隐藏文件,即名称以点或下划线开头的文件。
  • Impala 查询会忽略带有 Hadoop 工具常用的临时工作文件扩展名的文件。任何带有扩展名.tmp或 .copying不属于 Impala 表的文件。后缀匹配不区分大小写,因此例如 Impala 会忽略 .copying.COPYING后缀。
  • Impala 使用后缀来识别文本数据文件何时是压缩文本。对于黑斑羚识别压缩的文本文件,它们必须有对应的压缩编解码器相应的文件扩展名,要么.bz2.deflate.gz.snappy,或.zst。扩展名可以是大写或小写。
  • 否则,文件名不重要。当您通过 ETL 作业将文件放入 HDFS 目录,或使用该CREATE EXTERNAL TABLE语句将Impala 指向现有 HDFS 目录时,或使用该语句将数据文件移动到外部控制下时LOAD DATA,Impala 会保留原始文件名。

通过 ImpalaINSERT 语句生成的数据的文件名被赋予唯一的名称以避免文件名冲突。

一个INSERT ... SELECT语句从处理所述每个节点产生一个数据文件 SELECT的语句的一部分。一条INSERT ... VALUES语句为每条语句生成一个单独的数据文件;由于 Impala 查询少量大文件比查询大量小文件更有效,因此INSERT ... VALUES不建议在加载大量数据时使用该语法。如果您发现自己的表由于太多小数据文件而效率低下,请通过INSERT ... SELECT将数据传输到新表来将数据重组为几个大文件。

文本数据文件中的特殊值:

  • 帕拉识别文字字符串inf为无穷大,并且nan对于 “非数”,对于FLOATDOUBLE列。

Impala 识别\N要表示的文字字符串NULL。使用 Sqoop 时,请指定选项--null-non-string并 --null-string确保NULL 在 Sqoop 输出文件中正确表示所有值。 \N需要转义,如下例所示:

--null-string '\\N' --null-non-string '\\N'
  • 默认情况下,SqoopNULL使用 string写入值null,当 Impala 评估此类行时会导致转换错误。现有表和数据文件的解决方法是通过 .ALTER TABLE name SET TBLPROPERTIES("serialization.null.format"="null")

在Impala 2.6及更高版本中,Impala 可以根据 表元数据字段中的skip.header.line.count值选择性地从 HDFS 上的文本输入文件中跳过任意数量的标题行 TBLPROPERTIES。例如:

create table header_line(first_name string, age int)
  row format delimited fields terminated by ',';

-- Back in the shell, load data into the table with commands such as:
-- cat >data.csv
-- Name,Age
-- Alice,25
-- Bob,19
-- hdfs dfs -put data.csv /user/hive/warehouse/header_line

refresh header_line;

-- Initially, the Name,Age header line is treated as a row of the table.
select * from header_line limit 10;
+------------+------+
| first_name | age  |
+------------+------+
| Name       | NULL |
| Alice      | 25   |
| Bob        | 19   |
+------------+------+

alter table header_line set tblproperties('skip.header.line.count'='1');

-- Once the table property is set, queries skip the specified number of lines
-- at the beginning of each text data file. Therefore, all the files in the table
-- should follow the same convention for header lines.
select * from header_line limit 10;
+------------+-----+
| first_name | age |
+------------+-----+
| Alice      | 25  |
| Bob        | 19  |
+------------+-----+

将数据加载到 Impala 文本表中

要将现有文本文件加载到 Impala 文本表中,请使用该LOAD DATA语句并指定文件在 HDFS 中的路径。该文件被移动到相应的 Impala 数据目录中。

要将多个现有文本文件加载到 Impala 文本表中,请使用该LOAD DATA 语句并指定包含这些文件的目录的 HDFS 路径。所有非隐藏文件都移动到相应的 Impala 数据目录中。

要将数据从 Impala 支持的任何其他文件格式转换为文本,请使用 SQL 语句,例如:

-- Text table with default delimiter, the hex 01 character.
CREATE TABLE text_table AS SELECT * FROM other_file_format_table;

-- Text table with user-specified delimiter. Currently, you cannot specify
-- the delimiter as part of CREATE TABLE LIKE or CREATE TABLE AS SELECT.
-- But you can change an existing text table to have a different delimiter.
CREATE TABLE csv LIKE other_file_format_table;
ALTER TABLE csv SET SERDEPROPERTIES ('serialization.format'=',', 'field.delim'=',');
INSERT INTO csv SELECT * FROM other_file_format_table;

这是查看 Impala 如何在文本格式数据文件中表示特殊值的有用技术。使用该DESCRIBE FORMATTED语句查看存储数据文件的 HDFS 目录,然后使用诸如和 之类的 Linux 命令来显示 Impala 创建的文本文件的内容。 hdfs dfs -ls hdfs_directoryhdfs dfs -cat hdfs_file

要在文本表中创建几行用于测试目的,您可以使用以下INSERT ... VALUES 语法:

INSERT INTO text_table VALUES ('string_literal',100,hex('hello world'));

注意: 由于 Impala 和 HDFS 基础架构针对多兆字节文件进行了优化,因此INSERT ... VALUES在插入多行时避免使用符号。每个INSERT ... VALUES 语句都会生成一个新的小文件,从而导致碎片化和性能降低。创建大量新数据时,请使用其中一种批量加载技术,例如LOAD DATA 或INSERT ... SELECT。或者,将 HBase 表用于单行INSERT操作,因为 HBase 表不会遇到与存储在 HDFS 上的表相同的碎片问题。

当您创建用于 Impala 文本表的文本文件时,指定 \N表示一个NULL值。有关NULL空字符串和空字符串之间的差异,请参阅 NULL

如果文本文件的字段少于相应 Impala 表中的列,则NULL当 Impala 查询读取该文件中的数据时,所有相应的列都将设置为。

如果文本文件的字段多于相应 Impala 表中的列,则当 Impala 查询读取该文件中的数据时,将忽略额外的字段。

您还可以使用手动 HDFS 操作,例如hdfs dfs -puthdfs dfs -cp将数据文件放入 Impala 表的数据目录中。当您将新数据文件复制或移动到 Impala 表的 HDFS 目录时,在针对该表发出下一个查询之前,在impala-shell 中发出一条语句,以使 Impala 识别新添加的文件。 REFRESH table_name

使用 LZO 压缩的文本文件

Impala 支持使用采用 LZO 压缩的文本数据文件。在可行的情况下,对文本数据文件应用压缩。Impala 查询通常受 I/O 限制;尽管需要额外的 CPU 工作来解压缩内存中的数据,但减少从磁盘读取的数据量通常会加快查询速度。

Impala 可以处理 LZO 压缩的文本文件,优于其他编解码器压缩的文件,因为 LZO 压缩的文件是“可拆分的”,这意味着文件的不同部分可以由不同的节点独立解压缩和处理。

Impala 目前不支持写入 LZO 压缩的文本文件。

因为 Impala 可以查询 LZO 压缩的文件,但目前无法写入它们,所以您使用 Hive 进行初始化CREATE TABLE并加载数据,然后切换回 Impala 运行查询。有关为 HiveCREATE TABLE和 INSERT语句设置 LZO 压缩的说明,请参阅 Hive wiki 上的 LZO 页面。创建 LZO 文本表后,您还可以手动向其中添加 LZO 压缩的文本文件,由 lzop命令或类似方法生成。

准备使用 LZO 压缩的文本文件

在 Impala 中使用 LZO 压缩表之前,请为集群中的每台机器执行以下一次性设置。使用公共存储库、您建立的私有存储库或使用包安装必要的包。无论您是否使用集群管理软件,您都必须手动执行这些步骤。

  1. 通过下载和安装适当的库,准备您的系统以使用 LZO:将适当的文件下载并安装到您打算将 LZO 与 Impala 一起使用的每台机器上。

配置 Impala 以使用 LZO:

使用一个下面的命令集的刷新你的软件包管理系统的存储库的信息,安装Hadoop的基础LZO支持,并安装因帕拉的LZO支持。

笔记:Hadoop LZO 包的名称在遥远的过去发生了变化。目前,包名是hadoop-lzo

对于 RHEL/CentOS 系统:$ sudo yum update
$ sudo yum install hadoop-lzo
$ sudo yum install impala-lzo
对于 SUSE 系统:$ sudo apt-get update
$ sudo zypper install hadoop-lzo
$ sudo zypper install impala-lzo
对于 Debian/Ubuntu 系统:$ sudo zypper update
$ sudo apt-get install hadoop-lzo
$ sudo apt-get install impala-lzo

笔记:impala-lzo包 的级别与您使用的 Impala 版本密切相关。impala-lzo每次升级 Impala 时,请在每台适用的机器上重新执行安装命令, 以确保您拥有该软件包的适当版本。

对于core-site.xml在客户端服务器上(即在 Impala 和 Hadoop 的配置目录中),附加com.hadoop.compression.lzo.LzopCodec 到以逗号分隔的编解码器列表。例如:

<property>
  <name>io.compression.codecs</name>
  <value>org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.GzipCodec,
        org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.DeflateCodec,
        org.apache.hadoop.io.compress.SnappyCodec,com.hadoop.compression.lzo.LzopCodec</value>
</property>

笔记:

如果这是您第一次编辑 Hadoop core-site.xml文件,请注意/etc/hadoop/conf目录通常是一个符号链接,因此规范的core-site.xml可能位于不同的目录中:

$ ls -l /etc/hadoop
total 8
lrwxrwxrwx. 1 root root   29 Feb 26  2013 conf -> /etc/alternatives/hadoop-conf
lrwxrwxrwx. 1 root root   10 Feb 26  2013 conf.dist -> conf.empty
drwxr-xr-x. 2 root root 4096 Feb 26  2013 conf.empty
drwxr-xr-x. 2 root root 4096 Oct 28 15:46 conf.pseudo
  1. 如果core-site.xml 中io.compression.codecs缺少该属性 ,则只添加 到新的属性值,而不是前面示例中的所有名称。 com.hadoop.compression.lzo.LzopCodec
  2. 重新启动 MapReduce 和 Impala 服务。

创建 LZO 压缩文本表

必须在 Hive 中使用以下存储子句创建包含 LZO 压缩文本文件的表:

STORED AS
    INPUTFORMAT 'com.hadoop.mapred.DeprecatedLzoTextInputFormat'
    OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'

此外,某些 Hive 设置需要生效。例如:

hive> SET mapreduce.output.fileoutputformat.compress=true;
hive> SET hive.exec.compress.output=true;
hive> SET mapreduce.output.fileoutputformat.compress.codec=com.hadoop.compression.lzo.LzopCodec;
hive> CREATE TABLE lzo_t (s string) STORED AS
  > INPUTFORMAT 'com.hadoop.mapred.DeprecatedLzoTextInputFormat'
  > OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat';
hive> INSERT INTO TABLE lzo_t SELECT col1, col2 FROM uncompressed_text_table;

创建 LZO 压缩文本表后,您可以使用INSERT ... SELECTHive 中的语句转换存储在其他表中的数据(无论文件格式如何)。

LZO 压缩表中的文件必须使用.lzo扩展名。INSERT在 Hive 中执行后检查 HDFS 数据目录中的文件,以确保文件具有正确的扩展名。如果所需的设置没有到位,您最终会得到常规的未压缩文件,并且 Impala 无法访问该表,因为它会找到具有错误(未压缩)格式的数据文件。

将数据加载到 LZO 压缩的文本表后,为文件编制索引,以便它们可以被拆分。您可以com.hadoop.compression.lzo.DistributedLzoIndexer通过 Linux 命令行运行 Java 类来索引文件 。这个 Java 类包含在hadoop-lzo包中。

使用如下命令运行索引器:

$ hadoop jar /usr/lib/hadoop/lib/hadoop-lzo-version-gplextras.jar
  com.hadoop.compression.lzo.DistributedLzoIndexer /hdfs_location_of_table/

注意: 如果无法识别上例中的 JAR 文件的路径,请执行find 命令以定位hadoop-lzo-*-gplextras.jar并使用该路径。

索引文件与它们索引的文件同名,带有.index扩展名。如果数据文件没有被索引,Impala 查询仍然有效,但查询从远程 DataNode 读取数据,这是非常低效的。

创建 LZO 压缩表并加载数据并建立索引后,您可以通过 Impala 查询它们。与往常一样,在 Hive 中创建表后第一次启动impala-shell 时,发出一条INVALIDATE METADATA语句,以便 Impala 识别新表。(在 Impala 1.2 及更高版本中,您只需INVALIDATE METADATA在一个节点上运行,而不是在所有 Impala 节点上运行。)

使用 bzip2、deflate、gzip、Snappy 或 zstd 文本文件

Impala 支持使用采用 bzip2、deflate、gzip、Snappy 或 zstd 压缩的文本数据文件。这些压缩类型主要是为了方便现有 ETL 管道而不是最大性能。尽管与同等的未压缩文本相比,读取压缩文本所需的 I/O 更少,但这些编解码器压缩的文件不是 “可拆分的”,因此无法充分利用 Impala 并行查询功能。Impala 可以读取 Hive 编写的压缩文本文件。

在处理每个 Snappy 压缩文件时,执行工作的节点会将整个文件读入内存,然后对其进行解压缩。因此,节点必须有足够的内存来保存来自文本文件的压缩和未压缩数据。保存未压缩数据所需的内存很难提前估计,这可能会导致内存限制较低或启用资源管理的系统出现问题。对于 bzip2-、deflate-、gzip- 和 zstd-压缩的文本文件,这种内存开销减少了。压缩数据在读取时被解压缩,而不是一次解压缩。

要创建一个表来保存压缩文本,请创建一个没有特殊压缩选项的文本表。如果需要,使用ROW FORMAT子句指定分隔符和转义字符。

因为 Impala 可以查询压缩文本文件但目前不能写入它们,所以在 Impala 之外生成压缩文本文件并使用LOAD DATA语句,手动 HDFS 命令将它们移动到适当的 Impala 数据目录。(或者,您可以使用CREATE EXTERNAL TABLELOCATION属性并将其指向包含现有压缩文本文件的目录。)

以下示例展示了如何创建常规文本表,将不同类型的压缩和未压缩文件放入其中,Impala 会根据文件扩展名自动识别和解压缩每个文件:

create table csv_compressed (a string, b string, c string)
  row format delimited fields terminated by ",";

insert into csv_compressed values
  ('one - uncompressed', 'two - uncompressed', 'three - uncompressed'),
  ('abc - uncompressed', 'xyz - uncompressed', '123 - uncompressed');
...make equivalent .bz2, .gz, .snappy, and .zst files and load them into same table directory...

select * from csv_compressed;
+--------------------+--------------------+----------------------+
| a                  | b                  | c                    |
+--------------------+--------------------+----------------------+
| one - snappy       | two - snappy       | three - snappy       |
| one - uncompressed | two - uncompressed | three - uncompressed |
| abc - uncompressed | xyz - uncompressed | 123 - uncompressed   |
| one - bz2          | two - bz2          | three - bz2          |
| abc - bz2          | xyz - bz2          | 123 - bz2            |
| one - gzip         | two - gzip         | three - gzip         |
| abc - gzip         | xyz - gzip         | 123 - gzip           |
| one - zstd         | two - zstd         | three - zstd         |
| abc - zstd         | xyz - zstd         | 123 - zstd           |
| one - deflate      | two - deflate      | three - deflate      |
| abc - deflate      | xyz - deflate      | 123 - deflate        |
+--------------------+--------------------+----------------------+

$ hdfs dfs -ls 'hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/';
...truncated for readability...
75 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/csv_compressed.snappy
79 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/csv_compressed_bz2.csv.bz2
80 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/csv_compressed_gzip.csv.gz
58 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/csv_compressed_zstd.csv.zst
48 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/csv_compressed_deflate.csv.deflate
116 hdfs://127.0.0.1:8020/user/hive/warehouse/file_formats.db/csv_compressed/dd414df64d67d49b_data.0.