常见问题解答

什么是坏记录?

由于数据类型不兼容、数据为空或者格式不兼容而导致无法加载到 CarbonData 中的记录归类为坏记录。

CarbonData 在哪里存储坏记录?

坏记录存储在 carbon.properties 文件 carbon.badRecords.location 属性设置的位置。默认情况,carbon.badRecords.location 设置的路径为 /opt/Carbon/Spark/badrecords

如何启用坏记录日志?

在加载数据时,我们可以指定处理坏记录的方法。如果想分析坏记录产生的原因,BAD_RECORDS_LOGGER_ENABLE 参数必须设置成 TRUE。有很多方式来处理坏记录,我们可以通过设置 BAD_RECORDS_ACTION 参数。

  • 要用 NULL 值来填充不正确的 csv 行数据,并在 CarbonData 中加载数据,请在查询中设置一下参数:
'BAD_RECORDS_ACTION'='FORCE'
  • 要在 CSV 文件中写入坏记录,而不是使用 NULL 来处理(文件路径通过 carbon.badRecords.location 参数设置),请在查询中设置一下参数:
'BAD_RECORDS_ACTION'='REDIRECT'

如何忽略坏记录?

如果想忽略将坏记录存储在 csv 文件中,请在查询中设置一下参数:

'BAD_RECORDS_ACTION'='IGNORE'

在创建 carbon session 时如何指定存储位置?

创建 carbon session 时指定的存储路径,在 CarbonData 中主要用于存储元数据,比如模式、字典文件,字典元数据以及排序索引。

尝试使用以下方式来在创建 carbonsession 的时候指定 storepath :

val carbon = SparkSession.builder().config(sc.getConf)
             .getOrCreateCarbonSession(<store_path>)

示例:

val carbon = SparkSession.builder().config(sc.getConf)
             .getOrCreateCarbonSession("hdfs://localhost:9000/carbon/store")

Carbon 的锁类型都有哪些?

Apache CarbonData 获取文件锁用于防止并发修改相同文件的操作。锁的类型取决于存储路径,对于 HDFS 路径,锁的类型为 HDFSLOCK。默认情况下,锁类型为 LOCALLOCK。 carbon.lock.type 属性指定在表上执行并发操作期间要获取锁的类型。 该属性可以使用以下值进行设置:

  • LOCALLOCK : 这种锁以文件的形式在本地文件系统上创建。如果一台机器上仅仅有一个 spark driver (thrift server) 运行并且没有其他 CarbonData spark 应用程序同时启动的情况下很有用。
  • HDFSLOCK : 这种锁以文件的形式在 HDFS 文件系统上创建。当启动多个 CarbonData spark 应用程序并且集群中没有运行 ZooKeeper,而且 HDFS 支持基于文件的锁的情况下很有用。

如何解决 Abstract Method Error?

为了构建 CarbonData 工程,需要我们指定 spark 相关配置。spark 配置指定 Spark 的版本。当使用 Maven 构建工程时,你需要指定 spark version

在异常情况下执行插入操作时 Carbon 如何处理?

Carbon 支持插入操作,你可以参考 CarbonData 上的 DML 操作 中提到的语法。首先,在 spark-sql 中创建一张源表,并将数据加载到已经创建好的的表中。

CREATE TABLE source_table(
id String,
name String,
city String)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ",";
SELECT * FROM source_table;
id  name    city
1   jack    beijing
2   erlu    hangzhou
3   davi    shenzhen

场景 1 :

假设 carbon 表列的顺序与源表不同,使用语句 "SELECT * FROM carbon table" 进行查询时,将获得与源表一样的列顺序,而不是预期的 carbon 表列顺序。

CREATE TABLE IF NOT EXISTS carbon_table(
id String,
city String,
name String)
STORED BY 'carbondata';
INSERT INTO TABLE carbon_table SELECT * FROM source_table;
SELECT * FROM carbon_table;
id  city    name
1   jack    beijing
2   erlu    hangzhou
3   davi    shenzhen

正如结果显示的,carbon 表的第二列是 city,但是查出来的是 name,比如 jack。这种现象和将数据插入 hive 表中一样。

如果你想将数据插入到 carbon 表对应的列中,则必须在插入语句中指定好列的顺序。

INSERT INTO TABLE carbon_table SELECT id, city, name FROM source_table;

场景 2 :

当 carbon 表列数与 select 语句中指定的列数不相同时,插入操作将失败。下面的插入操作将会失败。

INSERT INTO TABLE carbon_table SELECT id, city FROM source_table;

场景 3 :

当 carbon 表列类型与 select 语句中指定的列类型不相同时,插入操作仍然会成功,但是结果可能为 NULL,因为在转换类型失败时,将使用 NULL 替代。

为什么聚合查询不是从聚合表中获取数据?

以下聚合查询不会从聚合表中获取数据:

  • 场景 1 :当查询中存在子查询谓词时

示例:

create table gdp21(cntry smallint, gdp double, y_year date) stored by 'carbondata';
create datamap ag1 on table gdp21 using 'preaggregate' as select cntry, sum(gdp) from gdp21 group by cntry;
select ctry from pop1 where ctry in (select cntry from gdp21 group by cntry);
  • 场景 2 :当集合函数与 in 过滤器一起使用时

示例:

create table gdp21(cntry smallint, gdp double, y_year date) stored by 'carbondata';
create datamap ag1 on table gdp21 using 'preaggregate' as select cntry, sum(gdp) from gdp21 group by cntry;
select cntry, sum(gdp) from gdp21 where cntry in (select ctry from pop1) group by cntry;
  • 场景 3 :当聚合函数与 join 一起使用,且使用了相等过滤操作时

示例:

create table gdp21(cntry smallint, gdp double, y_year date) stored by 'carbondata';
create datamap ag1 on table gdp21 using 'preaggregate' as select cntry, sum(gdp) from gdp21 group by cntry;
select cntry,sum(gdp) from gdp21,pop1 where cntry=ctry group by cntry;

为什么 Dataload 命令在驱动程序端失败, Spark UI 上的 executors 却显示成功?

Spark executor 在重试次数达到最大值后才显示任务失败,但加载具有坏记录的数据并将 BAD_RECORDS_ACTION(carbon.bad.records.action)设置为 FAIL 将只尝试一次,并且将给驱动程序发送失败信号,而不是抛出异常来重试,因为如果发现坏记录并且 BAD_RECORDS_ACTION 设置为 FAIL,则无法重试。因此,Spark executor 显示这一尝试是成功的状态,但该命令实际上却执行失败了。 我们可以检查任务尝试或执行程序日志以观察失败的原因。

为什么查询 SDK writer 输出的数据时选择查询输出的时区结果会一样?

SDK writer 是一个独立的实体,因此 SDK writer 可以从具有不同时区的非群集机器生成 carbondata 文件。 但是在群集中读取这些文件时,它总是获取到群集时区。 因此,时间戳和日期数据类型字段的值不是原始值。 如果想要在写入时控制数据的时区,则通过调用以下 API 在 SDK writer 中设置集群的时区。

TimeZone.setDefault(timezoneValue)

示例:

cluster timezone is Asia/Shanghai
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))