如何将数据拆分为sqoop中的部分文件

时间:2017-07-14 10:17:18

标签: hadoop sqoop hadoop-partitioning

我怀疑如果数据偏斜,数据如何被分割成部分文件。如果可能的话,请帮我澄清一下。

让我们将department表格作为主键department_id

mysql> select * from departments;
2 Fitness
3 Footwear
4 Apparel
5 Golf
6 Outdoors
7 Fan Shop

如果我通过在导入命令中提及sqoop import来使用-m 1,我知道我将只生成一个包含所有记录的部分文件。

现在我运行命令时没有指定任何映射器。所以默认情况下它应该需要4个映射器,它在HDFS中创建了4个部分文件。以下是每个零件文件分发记录的方式。

[cloudera@centsosdemo ~]$ hadoop fs -cat /user/cloudera/departments/part-m-00000
2,Fitness
3,Footwear
[cloudera@centsosdemo ~]$ hadoop fs -cat /user/cloudera/departments/part-m-00001
4,Apparel
[cloudera@centsosdemo ~]$ hadoop fs -cat /user/cloudera/departments/part-m-00002
5,Golf
[cloudera@centsosdemo ~]$ hadoop fs -cat /user/cloudera/departments/part-m-00003
6,Outdoors
7,Fan Shop

根据BoundingValsQuery,Min(department_id)= 2,Max(department_id)= 8,默认情况下将使用4个映射器。

经过计算,每个映射器应获得(8-2)/4=1.5条记录。

我在这里没有得到如何分发数据。我无法理解2个记录是如何在部分-m-00000中出现的,而只有1个部分在-m-00001,part-m-00002和部分-m-00003中有两个记录。

2 个答案:

答案 0 :(得分:0)

如果你有机会看看图书馆。它涉及一系列步骤。

  

Sqoop job阅读记录。通过DBRecordReader

 org.apache.sqoop.mapreduce.db.DBRecordReader

这里有两种方法可以解决。

方法1。

protected ResultSet executeQuery(String query) throws SQLException {
Integer fetchSize = dbConf.getFetchSize();
/*get fetchSize according to split which is calculated via getSplits() method of 
org.apache.sqoop.mapreduce.db.DBInputFormat.And no. of splits are calculated
via no. of (count from table/no. of mappers). */
 }

拆分计算: -

org.apache.sqoop.mapreduce.db.DBInputFormat
 public List<InputSplit> getSplits(JobContext job) throws IOException {
 .......//here splits are calculated accroding to count of source table
 .......query.append("SELECT COUNT(*) FROM " + tableName);
}   

方法2.

 protected String getSelectQuery() {
    if (dbConf.getInputQuery() == null) {
      query.append("SELECT ");

      for (int i = 0; i < fieldNames.length; i++) {
        query.append(fieldNames[i]);
        if (i != fieldNames.length -1) {
          query.append(", ");
        }
      }

      query.append(" FROM ").append(tableName);
      query.append(" AS ").append(tableName); 
      if (conditions != null && conditions.length() > 0) {
        query.append(" WHERE (").append(conditions).append(")");
      }

      String orderBy = dbConf.getInputOrderBy();
      if (orderBy != null && orderBy.length() > 0) {
        query.append(" ORDER BY ").append(orderBy);
      }
    } else {
      //PREBUILT QUERY
      query.append(dbConf.getInputQuery());
    }

    try {// main logic to decide division of records between mappers.
      query.append(" LIMIT ").append(split.getLength());
      query.append(" OFFSET ").append(split.getStart());
    } catch (IOException ex) {
      // Ignore, will not throw.
    }

    return query.toString();
  }

查看评论主要逻辑下的代码部分....... 这里的记录根据LIMIT和OFFSET进行划分。对于每个RDBMS,这种逻辑的实现方式都不同。只是寻找org.apache.sqoop.mapreduce.db.OracleDBRecordReader它与getSelectQuery()方法的实现差别不大。

希望这可以快速了解记录如何划分为不同的映射器。

答案 1 :(得分:0)

Sqoop在主键列或拆分列中找到最小值和最大值,然后尝试为给定数量的映射器划分范围。

示例,如果您有一个表,其主键列的id的最小值为0,最大值为1000,并且Sqoop被定向为使用4个任务,则Sqoop将运行四个进程,这些进程将每个执行的SQL语句的形式为SELECT * FROM sometable WHERE id> = lo AND id

此处min val = 2 max = 7,因此sqoop将以以下范围(2-4),(4-5),(5-6),(6-7)运行四个进程,这表示

  1. 第二和第三在一起
  2. 第4条记录
  3. 第5条记录
  4. 该范围内的第六和第七位