Sqoop 导入按列数据类型拆分

Sqoop Import Split by Column Data type

sqoop import中Split by column的数据类型是否应该始终是数字数据类型(integer、bignint、numeric)?不能是字符串吗?

不,它必须是数字,因为根据规范:"By default , sqoop will use query select min(), max() from to find out boundaries for creating splits."替代方法是使用 --boundary-query,它也需要数字列。否则,Sqoop 作业将失败。如果您的 table 中没有这样的列,唯一的解决方法是仅使用 1 个映射器:“-m 1”。

是的,您可以拆分任何非数字数据类型。

但不推荐这样做

为什么?

对于拆分数据,Sqoop 触发

SELECT MIN(col1), MAX(col2) FROM TABLE

然后根据您的映射器数量进行分配。

现在以整数为例--split-by

Table 有一些 id 列的值为 1 到 100,并且您使用了 4 个映射器(-m 4 在您的 sqoop 命令中)

Sqoop 使用以下方法获取最小值和最大值:

SELECT MIN(id), MAX(id) FROM TABLE

输出:

1,100

按整数拆分很容易。您将制作 4 个部分:

  • 1-25
  • 25-50
  • 51-75
  • 76-100

现在字符串为 --split-by

Table 有一些 name 列的值为 "dev" 到 "sam" 并且您使用了 4 个映射器(-m 4 在您的 sqoop 命令中)

Sqoop 使用以下方法获取最小值和最大值:

SELECT MIN(id), MAX(id) FROM TABLE

输出:

开发人员,山姆

现在怎么分成4个部分。根据 sqoop docs,

/**
   * This method needs to determine the splits between two user-provided
   * strings.  In the case where the user's strings are 'A' and 'Z', this is
   * not hard; we could create two splits from ['A', 'M') and ['M', 'Z'], 26
   * splits for strings beginning with each letter, etc.
   *
   * If a user has provided us with the strings "Ham" and "Haze", however, we
   * need to create splits that differ in the third letter.
   *
   * The algorithm used is as follows:
   * Since there are 2**16 unicode characters, we interpret characters as
   * digits in base 65536. Given a string 's' containing characters s_0, s_1
   * .. s_n, we interpret the string as the number: 0.s_0 s_1 s_2.. s_n in
   * base 65536. Having mapped the low and high strings into floating-point
   * values, we then use the BigDecimalSplitter to establish the even split
   * points, then map the resulting floating point values back into strings.
   */

你会在代码中看到警告:

LOG.warn("Generating splits for a textual index column.");
LOG.warn("If your database sorts in a case-insensitive order, "
    + "this may result in a partial import or duplicate records.");
LOG.warn("You are strongly encouraged to choose an integral split column.");

在 Integer 示例的情况下,所有映射器将获得平衡负载(所有映射器将从 RDBMS 中获取 25 条记录)

在字符串的情况下,数据排序的可能性较小。因此,很难为所有映射器提供相似的负载。


简而言之,将整数列作为 --split-by 列。

是的,我们可以,但由于性能问题,不推荐。因为我们知道 SQOOP 运行s 边界查询 "select min(pk/split-by column), max(pk/split-by column) from table where condition " 来计算映射器的拆分大小。 split-size = (max - min)/映射器数量

假设有 table 名员工。

id      name  age
  1       baba  20
  2       kishor 30
  3       jay    40
  ..........
  10001   pk    60

场景 1:

对 id 列执行拆分

在这种情况下,SQOOP 将触发员工的边界查询 select min(id),max(id) 以计算拆分大小。

min = 1
max = 100001

default no of mapper = 4

split-size = (10001-1)/4 = 25000

so each mapper will process 25000 lines of record.
mapper 1:  1 - 25000
mapper 2:  25001-50000
mapper 3:  50001-75000
mapper 4:  75001-100000

所以如果我们有完整的列,SQOOP 很容易分割记录。

场景 2:

对名称列执行拆分

在这种情况下,SQOOP 将触发“select min(name),max(name) from employee”来计算拆分大小。

min = baba, max= pk

SQOOP 无法轻松计算拆分大小,因为最小值和最大值具有文本值((最小值-最大值)/映射器的数量),因此它将 运行 TextSplitter class 执行拆分,这会产生额外的开销并可能影响性能。

注意:我们需要传递额外的参数 -D org.apache.sqoop.splitter.allow_text_splitter= true 才能使用 TextSplitter class.