Cloudera Impala 支持使用文本文件作为输入输出的存储格式。Text files are a convenient format to use for interchange with other applications or scripts that produce or read delimited text files, such as CSV or TSV with commas or tabs for delimiters.
文本文件在列定义方面同样非常灵活。例如,文本文件中可以包含比 Impala 表中定义的更多的字段,在查询时这些额外的字段会被忽略掉;也可以包含比 Impala 表更少的字段,在查询时这些缺少的字段被视为 NULL 值。你可以包含表中被视为数值或时间戳的字段,然后使用 ALTER TABLE ... REPLACE COLUMNS 来设置为字符串,或者相反。
继续阅读:
数据存放成文本文件是相当笨重的,并且不如二进制格式如 Parquet 高效。通常在这些情况下才在 Imapla 中使用文本文件格式:接收到的是文本文件并且在这个流程中无法控制,或者你是 Hadoop 新手不熟悉产生其他格式文件的技术(因为 CREATE TABLE 的默认文件格式是文本,你可以使用文本文件格式创建你的第一个表而无需过多考虑性能问题)。没关系,找机会在更关注性能的查询中使用更高效的文件格式。
对于频繁查询的数据,你应当把原始的文本文件加载到 Impala 表里,然后使用 INSERT 语句把数据传输到使用 Parquet 文件格式的其他表中;当数据被存放到目标表后,数据格式自动进行了转换。
对于更紧凑的数据,考虑使用 LZO 压缩的文本文件。 LZO 是 Impala 唯一支持的文本文件压缩编解码器,因为 LZO 数据文件的 "可分割(splittable)" 性使得不同的节点可以并行处理相同文件的不同部分。参见 Using LZO-Compressed Text Files 了解详细信息。
创建一个使用文本数据文件的表:
加入数据文件没有使用其他的格式(例如分隔符) ,使用后面不包括其他子句的 CREATE TABLE 语句创建一个文本文件格式的表。例如:
create table my_table(id int, s string, n int, t timestamp, b boolean);
INSERT 语句创建的数据文件将使用 Ctrl-A (十六进制的 01) 字符作为列的分隔符。
常见的使用情况是把一个已有的文本文件导入 Impala 表中。语法更详细,后面包括几个子句;重要的是其中的 FIELDS TERMINATED BY 子句。例如:
create table csv(id int, s string, n int, t timestamp, b boolean) stored as textfile fields terminated by ','; create table tsv(id int, s string, n int, t timestamp, b boolean) stored as textfile fields terminated by '\t'; create table pipe_separated(id int, s string, n int, t timestamp, b boolean) stored as textfile fields terminated by '|';
你可以创建使用指定分隔符的表,来用格式熟悉的格式如 CSV, TSV, 数显分割(pipe-separated) 导入文本文件。你也可以使用这些表生成数据数据文件,先通过 INSERT ... SELECT 语法把数据复制到 Impala 表里,然后导出这些表数据目录下的数据文件。
不要在你构建的文本数据文件中的值上包以引号。假如你需要在字段值里包含分隔符,例如把一个包含逗号的字符串值放入 CSV 格式的数据文件里,应在 CREATE TABLE 语句中使用 ESCAPED BY 子句设置转义字符, 并在需要转移的字符前加上转义符号。
执行 DESCRIBE FORMATTED table_name 语句来查看每一个表在 Impala 内部表示的详细信息。
当 Impala 查询一个包含文本文件格式数据的表时,将查询这个表的数据目录下的所有数据文件。Impala 忽略所有的隐藏文件,也就是说,以 . 开头的所有文件名。另外,文件名是没有特定含义的(not significant)。
通过 Impala INSERT 语句产生的数据文件名被赋予唯一的文件名,以避免文件名冲突。
INSERT ... SELECT 语句在每一个处理 SELECT 部分的节点上产生一个数据文件。INSERT ... VALUES 语句为其中的每一个语句产生一个单独的数据文件;因为 Impala 查询少量的巨大文件比查询大量的小文件更高效, 所以不推荐使用 INSERT ... VALUES 语法加载大量的数据。假如你发现你的表是因为包含太多小文件而低效,通过执行 INSERT ... SELECT 传输数据到新表,重组这些数据到少量的大文件中。
加载已有的文本文件到 Impala 文本文件表时,请使用 LOAD DATA 语句,并指定文件在 HDFS 中的路径。这些文件会移动到对应的 Impala 数据目录下。
加载已有的多个文本文件到 Impala 文本文件表时,请使用 LOAD DATA 语句,并指定包含这些文件的 HDFS 目录。所有非隐藏的文件都会移动到对应的 Impala 数据目录下。
请使用如下语句,将 Impala 支持的其他文件格式转换为文本格式:
INSERT INTO text_table SELECT column_list FROM other_file_format_table; -- 默认分隔符为十六进制的 01 CREATE TABLE text_table AS SELECT column_list FROM other_file_format_table; -- 为生成的 CSV,TSV 等文件设置分隔符 CREATE TABLE text_table AS SELECT column_list FROM other_file_format_table ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
这是一个很有用的技术,可以查看 Impala 如何表示特殊值。
请使用 INSERT ... VALUES 语法,创建用于测试的包含少量数据的文本文件表:
INSERT INTO text_table VALUES ('string_literal',100,hex('hello world'));
当为 Impala 文本文件表创建文本文件时,请使用 \N 表示 NULL。关于 NULL 和空字符串的不同,请参考 NULL。
假如文本文件中的字段比 Impala 表中的字段少,当 Impala 查询读取文件中的数据时,所有对应(缺少)的列被设置为 NULL。
假如文本文件中的字段比 Impala 表中的字段多,当 Impala 查询读取文件中的数据时,多余的字段会被忽略。
你同样可以使用手工 HDFS 操作如 hdfs dfs -put 或 hdfs dfs -cp 把数据文件放入 Impala 表数据目录。当你复制或移动新的数据文件到 Impala 表数据目录时,在执行对应这个表的查询之前,请先在 impala-shell 中执行 REFRESH table_name 语句,以便 Impala 识别到新增加的文件。
Cloudera Impala 支持采用 LZO 压缩的文本数据文件。当可行时,Cloudera 推荐压缩文本文件。 Impala 查询通常是 I/O密集的(I/O-bound);减少从硬盘上读取数据的数量通常会提高查询的速度,尽管在内存中解压数据时需要额外的 CPU 工作。
Impala 可以处理 LZO压缩文本文件,不支持 GZip 压缩文本文件。LZO 压缩文件是 "可分割的(splittable)",意味着文件的不同部分可以在不同的节点上独立的解压缩和处理。GZip 压缩文件是不可分割的,标志着它不适合 Impala 类型的分布式查询。
因为目前 Impala 可以读取 LZO 压缩数据文件而不能写入,你应当使用 Hive 进行初始化 CREATE TABLE 和加载数据,然后切换回 Impala 执行查询。关于为 Hive CREATE TABLE 和 INSERT 语句设置 LZO 压缩,参见 the LZO page on the Hive wiki。当你创建了 LZO 文本文件表之后,你也可以手工添加由 lzop 命令或类似方法产生的 LZO 压缩文本文件。
在 Impala 中使用 LZO压缩表之前,为集群中的每一台机器执行下面的一次性操作。使用 Cloudera 公共库、你建立的私有库、或者使用包文件,来安装所需的包。无论你是否使用 Cloudera Manager 产品来管理你的集群,你都需要手工执行这些步骤。
在使用 Cloudera Manager 管理的系统中,使用 parcels方式:
参考 Cloudera Manager 文档中的 setup instructions for the LZO parcel。
在使用 Cloudera Manager 管理的系统中,或非 Cloudera Manager 管理的系统中,使用包方式:
在你所有希望使用 LZO 的 Impala 机器上,下载并安装对应的文件。这些文件都下载自 Cloudera GPL extras 下载站点。安装以下文件:
使用以下各组命令之一来刷新你的包管理系统库信息,为 Hadoop 安装基础的 LZO 支持,并为 Impala 安装 LZO 支持。
RHEL/CentOS:
$ sudo yum update $ sudo yum install hadoop-lzo-cdh4 # For clusters running CDH 4. $ sudo yum install hadoop-lzo # For clusters running CDH 5 or higher. $ sudo yum install impala-lzo
SUSE:
$ sudo apt-get update $ sudo zypper install hadoop-lzo-cdh4 # For clusters running CDH 4. $ sudo zypper install hadoop-lzo # For clusters running CDH 5 or higher. $ sudo zypper install impala-lzo
Debian/Ubuntu:
$ sudo zypper update $ sudo apt-get install hadoop-lzo-cdh4 # For clusters running CDH 4. $ sudo apt-get install hadoop-lzo # For clusters running CDH 5 or higher. $ sudo apt-get install impala-lzo
impala-lzo-cdh4 包的版本与你所使用的 Impala 版本紧密相关。当你更新了 Impala 之后,请在每一台应用机器上重新执行 impala-lzo 的安装命令,以确保你使用这个包的对应的版本。
<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
假如 core-site.xml 文件中缺少 io.compression.codecs 属性,则只添加 com.hadoop.compression.lzo.LzopCodec 属性值,而不是像前面例子那样加上所有的编解码器。
包含 LZO压缩文本文件的表必须在 Hive 中使用一下存储子句创建:
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 压缩文本文件表之后,你可以通过在 Hive 中使用 INSERT ... SELECT 语句转换存储在其他表里(无论文件是何格式)的数据。
LZO压缩表的数据文件必须使用 .lzo 扩展名。当在 Hive 中执行 INSERT 之后,检查 HDFS 数据目录下的文件,确保这些文件具有正确的扩展名。 假如没有正确设置,带着正常的为压缩的文件结束,因为数据文件包含错误的格式(未压缩),Impala 将无法正确访问这个表(If the required settings are not in place, you end up with regular uncompressed files, and Impala cannot access the table because it finds data files with the wrong (uncompressed) format)。
当向 LZO 压缩文本文件表加载数据之后,请索引这些文件以便他们可分割(index the files so that they can be split)。通过运行 Java 类 com.hadoop.compression.lzo.DistributedLzoIndexer 来索引这些文件,需要在 Linux 命令行中执行。这一 Java 类包含在 hadoop-lzo 包里。
使用类似下面的命令运行索引器:
$ hadoop jar /usr/lib/hadoop/lib/hadoop-lzo-cdh4-0.4.15-gplextras.jar com.hadoop.compression.lzo.DistributedLzoIndexer /hdfs_location_of_table/
索引文件具有与他们所索引的文件相同的名称,后跟 .index 扩展名。加入数据文件没有被索引, Impala 查询将依然工作,但是查询将读取远端数据节点的数据,这将非常低效(Indexed files have the same name as the file they index, with the .index extension. If the data files are not indexed, Impala queries still work, but the queries read the data from remote DataNodes, which is very inefficient)。
当 LZO 压缩表创建,并且数据被加载和索引,你可以通过 Impala 查询它们。与往常一样,当在 Hive 中创建表之后,第一次启动 impala-shell 时,请先执行 INVALIDATE METADATA 语句以便 Impala 识别出新创建的表(在 Impala 1.2 及以上版本,你只需要在一个节点上运行 INVALIDATE METADATA ,而不是在所有的 Impala 节点上运行)。