Sqoop 数据导入多分区Hive解决方法

本文介绍如何使用Sqoop将数据导入多分区的Hive表,包括直接加载数据到分区路径并通过ALTER TABLE整合的方法,以及修改Sqoop源码以支持多分区数据导入的技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sqoop数据导入多分区hive解决方法

本节内容针对sqoop1,版本1.4.6

sqoop自身支持直接抽取数据进入hive,同时支持单分区格式的hive表数据导入,命令如下:

sqoop import \
--connect jdbc:oracle:thin:@{IP}:@{PORT}:hive  \
--username test --password test  --table test --columns col1,col2  \
--fields-terminated-by '\001'  [--null-string '\\N']  \
-m 1 --create-hive-table   \
--hive-drop-import-delims  \
--hive-overwrite         \
--hive-import  --hive-partition-key KEY --hive-partition-value VALUE  \
--target-dir  /test/test_partition \
--delete-target-dir \

但是该方法针对多分区的hive表则无法使用。大体解决方法有两种,一种是直接加载数据到分区路径然后alter table,另一种就是更改sqoop源码中loadstmt的部分

1、加载数据进入分区路径的方式

过程如下:

1、创建多分区表

create table dbtest.testTable(ID int,NAME int,AGE int,Instruction string,CreateDate string) row format delimited fields terminated by '\001'  partitioned by (ORG_NO string,LOAD_DATA string)

2、创建分区

alter table dbtest.testTable add partition (ORG_NO='001',LOAD_DATA='2018-01-01')

3、数据导入

sqoop import --append --connect jdbc:oracle:thin:@{IP}:@{PORT}:hive  \
--username test --password test --query @{sql}  \
--target-dir "/hive/warehouse/dbtest.db/testTable/ORG_NO=001/LOAD_DATA=2018-01-01"  \
--fields-terminated-by '\\N' \
--hive-database “dbtest” --hive-table "testTable" \
--split-by ID -m 1

2、修改源码

之所以sqoop自身不支持多分区的表的原因,只是因为在数据加载完成后sqoop往hive中提交数据时的代码如下(org.apache.sqoop.hive.TableDefWriter):


  /**
   * @return the LOAD DATA statement to import the data in HDFS into hive.
   */
  public String getLoadDataStmt() throws IOException {
    Path finalPath = getFinalPath();

    StringBuilder sb = new StringBuilder();
    sb.append("LOAD DATA INPATH '");
    sb.append(finalPath.toString() + "'");
    if (options.doOverwriteHiveTable()) {
      sb.append(" OVERWRITE");
    }
    sb.append(" INTO TABLE `");
    if(options.getHiveDatabaseName() != null) {
      sb.append(options.getHiveDatabaseName()).append("`.`");
    }
    sb.append(outputTableName);
    sb.append('`');

    /** 这部分是重点 **/
    if (options.getHivePartitionKey() != null) {
      sb.append(" PARTITION (")
        .append(options.getHivePartitionKey())
        .append("='").append(options.getHivePartitionValue())
        .append("')");
    }

    LOG.debug("Load statement: " + sb.toString());
    return sb.toString();
  }

从代码中能看出来,sqoop取出HivePartitionKey和HivePartitionValue直接拼接,所以只支持单分区的情况。因此只需对这段逻辑修正就能实现多分区的数据导入,修改后代码如下:

 /**
   * @return the LOAD DATA statement to import the data in HDFS into hive.
   */
  public String getLoadDataStmt() throws IOException {
    Path finalPath = getFinalPath();

    StringBuilder sb = new StringBuilder();
    sb.append("LOAD DATA INPATH '");
    sb.append(finalPath.toString() + "'");
    if (options.doOverwriteHiveTable()) {
      sb.append(" OVERWRITE");
    }
    sb.append(" INTO TABLE `");
    if(options.getHiveDatabaseName() != null) {
      sb.append(options.getHiveDatabaseName()).append("`.`");
    }
    sb.append(outputTableName);
    sb.append('`');

    /** 修改为通过‘,’分割的多分区传参形式 **/
    if (options.getHivePartitionKey() != null) {
        String partitionKeys = options.getHivePartitionKey();
        String partitionValues = options.getHivePartitionValue();
        String[] pks = partitionKeys.split(",");
        String[] pvs = partitionValues.split(",");
        sb.append(" PARTITION (");
        for (int i = 0; i < pks.length; i++) {
            if (i != 0) {
                sb.append(" , ");
            } 
            sb.append(pks[i]).append("='").append(pvs[i]).append("'");
        }
        sb.append(")");
    }

    LOG.debug("Load statement: " + sb.toString());
    return sb.toString();
  }

为保证api create-hive-table的可用性,需同步对以下方法进行修改,内容如下:

/**
   * @return the CREATE TABLE statement for the table to load into hive.
   */
  public String getCreateTableStmt() throws IOException {
    ……
    boolean first = true;
    String partitionKeys = options.getHivePartitionKey();
    for (String col : colNames) {
    if (partitionKeys != null) {
      // 修正排除每个分区列      
    String[] pks = partitionKeys.split(",");
      for (String pk : pks) {
      if (col.equals(pk)) {
        throw new IllegalArgumentException("Partition key " + col + " cannot "
            + "be a column to import.");
      }
      }
      }

      if (!first) {
        sb.append(", ");
      }

      first = false;

      Integer colType = columnTypes.get(col);
      String hiveColType = userMapping.getProperty(col);
      if (hiveColType == null) {
        hiveColType = connManager.toHiveType(inputTableName, col, colType);
      }
      if (null == hiveColType) {
        throw new IOException("Hive does not support the SQL type for column "
            + col);
      }

      sb.append('`').append(col).append("` ").append(hiveColType);

      if (HiveTypes.isHiveTypeImprovised(colType)) {
        LOG.warn(
            "Column " + col + " had to be cast to a less precise type in Hive");
      }
    }

    sb.append(") ");

    if (commentsEnabled) {
      DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
      String curDateStr = dateFormat.format(new Date());
      sb.append("COMMENT 'Imported by sqoop on " + curDateStr + "' ");
    }

    if (partitionKeys != null) {
      sb.append("PARTITIONED BY (");
      // 修正拼接每个分区列      
    String[] pks = partitionKeys.split(",");
      for (String pk : pks) {
        sb.append(pk).append(" STRING,");
      }
      sb.setLength(sb.length()-1);
      sb.append(")");
     }

    sb.append("ROW FORMAT DELIMITED FIELDS TERMINATED BY '");
    sb.append(getHiveOctalCharCode((int) options.getOutputFieldDelim()));
    sb.append("' LINES TERMINATED BY '");
    sb.append(getHiveOctalCharCode((int) options.getOutputRecordDelim()));
    ……

    LOG.debug("Create statement: " + sb.toString());
    return sb.toString();
  }

修正后加载方式如下:

sqoop import \
--connect jdbc:oracle:thin:@{IP}:@{PORT}:hive  \
--username test --password test  --table test --columns col1,col2  \
--fields-terminated-by '\001'  [--null-string '\\N']  \
-m 1 --create-hive-table   \
--hive-drop-import-delims  \
--hive-overwrite         \
--hive-import    \
--hive-partition-key KEY1[,KEY2,...]  \
--hive-partition-value VALUE1[,VALUE2,...]  \
--target-dir  /test/test_partition \
--delete-target-dir \
### 使用 Sqoop数据导入Hive 中 要将 MySQL 数据库中的数据通过 Sqoop 导入Hive 表中,需遵循以下方法并注意相关参数配置: #### 1. 基本命令结构 以下是基本的 Sqoop 命令模板,用于从 MySQL 导入数据Hive[^2]: ```bash sqoop import \ --connect jdbc:mysql://<host>:<port>/<database> \ --username <username> \ --password <password> \ --table <source_table_name> \ --fields-terminated-by ',' \ --delete-target-dir \ --num-mappers 1 \ --hive-import \ --hive-database <target_hive_database> \ --hive-table <target_hive_table> ``` #### 2. 参数说明 - `--connect`: 指定 JDBC URL 地址,连接目标关系型数据库。 - `--username` 和 `--password`: 提供访问数据库所需的用户名和密码。 - `--table`: 要迁移的关系型数据库表名称。 - `--fields-terminated-by`: 定义字段之间的分隔符,默认为逗号 `,`。 - `--delete-target-dir`: 清除目标目录(如果有),以便重新导入数据。 - `--num-mappers`: 设置 MapReduce 的 Mapper 数量。通常建议设置为较小值以减少资源消耗。 - `--hive-import`: 启用此选项可自动将导入数据加载到 Hive 表中。 - `--hive-database`: 指定目标 Hive 数据库名称。 - `--hive-table`: 指定目标 Hive 表名称。 #### 3. 配置注意事项 为了成功完成数据迁移,需要注意以下几个方面: - **JDBC Driver**: 确保 Hadoop 或 Sqoop 所在节点已安装对应版本的 MySQL JDBC 驱动程序,并将其路径加入 CLASSPATH[^1]。 - **Hive Metastore**: 确认 Hive Metastore 正常启动且能够被 Sqoop 访问。 - **权限管理**: 确保使用的用户具有足够的权限操作源数据库以及目标 Hive 数据库/表。 - **分区支持**: 若需要按特定列进行分区存储,则可以通过附加参数实现[^3]: ```bash --split-by <partition_column> ``` #### 4. 示例代码 假设有一个名为 `student` 的 MySQL 表位于 IP 地址为 `192.168.10.102` 的服务器上,端口为 `3306`,所属数据库为 `kk`。现在希望将其全部记录迁移到 Hive 的 `db_msg.student` 表中,执行如下命令即可: ```bash sqoop import \ --connect jdbc:mysql://192.168.10.102:3306/kk \ --username root \ --password 1111 \ --table student \ --fields-terminated-by ',' \ --delete-target-dir \ --num-mappers 1 \ --hive-import \ --hive-database db_msg \ --hive-table student ``` 如果仅需部分符合条件的学生信息,可通过增加条件过滤器达成目的: ```bash sqoop import \ --connect jdbc:mysql://192.168.10.102:3306/kk \ --username root \ --password 1111 \ --table student \ --where "age >= 18 AND grade = 'A'" \ --fields-terminated-by ',' \ --delete-target-dir \ --num-mappers 1 \ --hive-import \ --hive-database db_msg \ --hive-table filtered_students ``` #### 5. 错误排查指南 当遇到问题时,可以从日志文件入手分析原因;常见错误及其解决方案包括但不限于: - **无法找到驱动类**:确认是否正确放置了 MySQL Connector/J 文件于 `$SQOOP_HOME/lib` 下。 - **权限不足**:核实所提供的账户是否有权读取指定表格或者写入相应位置。 - **网络连通性障碍**:测试主机间能否互相 ping 通,验证防火墙策略是否存在干扰因素。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值