• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

说说datax的那些事-string类型进行数据切分

武飞扬头像
生活老难了
帮助1

  • 源码背景
    com.alibaba.datax.common.util.RangeSplitUtil里有关于ASCIIString切分,但在实际生产中,对字符串切分,splitSql中有很多特殊字符,乱码的现象,这些原因导致一些排序规则不符合数据库实际的排序规格,每个切分sql中的数据会有很多交集,导致数据重复同步。
  • 改造原因

        医院的项目(很多年的老系统),种种的原因导致源端数据质量不好,无时间戳或时间戳字段质量不好等等导致某些表我们不得不全量同步过来,同时保证其传输速度。

        我们的目标源是hive,同步到hdfs上,由于表太大,如果不做切分,会导致同步过来的只有一个文件,同时文件又很大,hive在使用的时候io压力大,在map阶段就很慢。       

  • 代码改造

        common中自定义一个36进制的工具类,只支持字符数字的组合

  1.  
    package com.alibaba.datax.common.util;
  2.  
     
  3.  
    import java.math.BigInteger;
  4.  
     
  5.  
    /**
  6.  
    * @Description
  7.  
    * @Author yintongkai
  8.  
    **/
  9.  
    public class G36Util {
  10.  
    /**
  11.  
    * 0-9 a-z 36 位, 可以理解为 36 进制
  12.  
    */
  13.  
    private final static char[] numberSystem= new char[]{
  14.  
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  15.  
    'a', 'b','c','d','e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  16.  
    };
  17.  
    private final static BigInteger base = new BigInteger("36");
  18.  
     
  19.  
    /**
  20.  
    * 获取当前 36 进制 数的索引
  21.  
    * 即 一个字符时: 36 进制的 十进制表示
  22.  
    * @param c
  23.  
    * @return
  24.  
    */
  25.  
    private static BigInteger getNumberSystemIndex(String c) {
  26.  
    int index = 0;
  27.  
    for (int i = 0; i < numberSystem.length; i ) {
  28.  
    String s = String.valueOf(numberSystem[i]);
  29.  
    if (c.equals(s)) {
  30.  
    index = i;
  31.  
    break;
  32.  
    }
  33.  
    }
  34.  
    return new BigInteger(String.valueOf(index));
  35.  
    }
  36.  
     
  37.  
     
  38.  
    /**
  39.  
    * 自定义进制数转BigInteger
  40.  
    * @param s
  41.  
    * @return
  42.  
    */
  43.  
    public static BigInteger string2BigInteger(String s) {
  44.  
    if (null == s) {
  45.  
    throw new IllegalArgumentException("参数 字符串 不能为空.");
  46.  
    }
  47.  
    BigInteger result = BigInteger.ZERO;
  48.  
    char[] chars = s.toCharArray();
  49.  
    for (int i = 0; i < chars.length; i ) {
  50.  
    int pow = chars.length - i - 1;
  51.  
    BigInteger index = getNumberSystemIndex(String.valueOf(chars[i]));
  52.  
    result = result.add(index.multiply(base.pow(pow)));
  53.  
    }
  54.  
    return result;
  55.  
    }
  56.  
     
  57.  
    /**
  58.  
    * BigInter转成自定义进制数
  59.  
    * @param n
  60.  
    * @return
  61.  
    */
  62.  
    public static String bigInteger2String(BigInteger n) {
  63.  
    if (null == n) {
  64.  
    throw new IllegalArgumentException("参数 bigInteger 不能为空.");
  65.  
    }
  66.  
    String s = "";
  67.  
    if (n.compareTo(BigInteger.ZERO) == 0) {
  68.  
    s = "0";
  69.  
    }
  70.  
    while (n.compareTo(BigInteger.ZERO) != 0) {
  71.  
    BigInteger mod = n.mod(base);
  72.  
    char c = numberSystem[mod.intValue()];
  73.  
    s = c s;
  74.  
    n = n.divide(base);
  75.  
    }
  76.  
    return s;
  77.  
    }
  78.  
    }
学新通

common组件RangSliptUtil中添加一个方法

  1.  
    public static String[] doAlphabetStringSplit(String left, String right, int expectSliceNumber) {
  2.  
    //将最大值最小值都转化为小写字母,供数值运算
  3.  
    left = left.toLowerCase();
  4.  
    right = right.toLowerCase();
  5.  
    int biglength = left.length() > right.length() ? left.length() : right.length();
  6.  
    if (left.length() > right.length()) {
  7.  
    String tailZeroPatrern = "%-" biglength "s";
  8.  
    right = String.format(tailZeroPatrern, right).replace(" ","0");
  9.  
    }
  10.  
    BigInteger[] tempResult = doBigIntegerSplit(G36Util.string2BigInteger(left), G36Util.string2BigInteger(right), expectSliceNumber);
  11.  
    String[] result = new String[tempResult.length];
  12.  
    //最小值不变,假设原始left排序有大写,排序大于转为小写的,改变left比最小值下限还小不影响结果
  13.  
    result[0] = left;
  14.  
    //最大值转为大写字母,提高最大值的上限,不影响结果
  15.  
    result[tempResult.length - 1] = right.toUpperCase();
  16.  
    //中间数值用小写转化的结果,只是对数据切分,不影响结果
  17.  
    for (int i = 1, len = tempResult.length - 1; i < len; i ) {
  18.  
    if (G36Util.bigInteger2String(tempResult[i]).length() < biglength) {
  19.  
    String headZeroPattern = "%" biglength "s";
  20.  
    result[i] =String.format(headZeroPattern, G36Util.bigInteger2String(tempResult[i])).replace(" ","0");
  21.  
    }else {
  22.  
    result[i] = G36Util.bigInteger2String(tempResult[i]);
  23.  
    }
  24.  
    }
  25.  
    return result;
  26.  
    }
学新通

plugin-rdbms-util组件中

com.alibaba.datax.plugin.rdbms.util.RdbmsRangeSplitWrap中调用
doAsciiStringSplit,改成调用doAlphabetStringSplit

学新通

至此改造完成。

  • 打包测试下吧 

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiacaee
系列文章
更多 icon
同类精品
更多 icon
继续加载