说说datax的那些事-string类型进行数据切分
- 源码背景
com.alibaba.datax.common.util.RangeSplitUtil里有关于ASCIIString切分,但在实际生产中,对字符串切分,splitSql中有很多特殊字符,乱码的现象,这些原因导致一些排序规则不符合数据库实际的排序规格,每个切分sql中的数据会有很多交集,导致数据重复同步。
- 改造原因
医院的项目(很多年的老系统),种种的原因导致源端数据质量不好,无时间戳或时间戳字段质量不好等等导致某些表我们不得不全量同步过来,同时保证其传输速度。
我们的目标源是hive,同步到hdfs上,由于表太大,如果不做切分,会导致同步过来的只有一个文件,同时文件又很大,hive在使用的时候io压力大,在map阶段就很慢。
- 代码改造
common中自定义一个36进制的工具类,只支持字符数字的组合
-
package com.alibaba.datax.common.util;
-
-
import java.math.BigInteger;
-
-
/**
-
* @Description
-
* @Author yintongkai
-
**/
-
public class G36Util {
-
/**
-
* 0-9 a-z 36 位, 可以理解为 36 进制
-
*/
-
private final static char[] numberSystem= new char[]{
-
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-
'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'
-
};
-
private final static BigInteger base = new BigInteger("36");
-
-
/**
-
* 获取当前 36 进制 数的索引
-
* 即 一个字符时: 36 进制的 十进制表示
-
* @param c
-
* @return
-
*/
-
private static BigInteger getNumberSystemIndex(String c) {
-
int index = 0;
-
for (int i = 0; i < numberSystem.length; i ) {
-
String s = String.valueOf(numberSystem[i]);
-
if (c.equals(s)) {
-
index = i;
-
break;
-
}
-
}
-
return new BigInteger(String.valueOf(index));
-
}
-
-
-
/**
-
* 自定义进制数转BigInteger
-
* @param s
-
* @return
-
*/
-
public static BigInteger string2BigInteger(String s) {
-
if (null == s) {
-
throw new IllegalArgumentException("参数 字符串 不能为空.");
-
}
-
BigInteger result = BigInteger.ZERO;
-
char[] chars = s.toCharArray();
-
for (int i = 0; i < chars.length; i ) {
-
int pow = chars.length - i - 1;
-
BigInteger index = getNumberSystemIndex(String.valueOf(chars[i]));
-
result = result.add(index.multiply(base.pow(pow)));
-
}
-
return result;
-
}
-
-
/**
-
* BigInter转成自定义进制数
-
* @param n
-
* @return
-
*/
-
public static String bigInteger2String(BigInteger n) {
-
if (null == n) {
-
throw new IllegalArgumentException("参数 bigInteger 不能为空.");
-
}
-
String s = "";
-
if (n.compareTo(BigInteger.ZERO) == 0) {
-
s = "0";
-
}
-
while (n.compareTo(BigInteger.ZERO) != 0) {
-
BigInteger mod = n.mod(base);
-
char c = numberSystem[mod.intValue()];
-
s = c s;
-
n = n.divide(base);
-
}
-
return s;
-
}
-
}
common组件RangSliptUtil中添加一个方法
-
public static String[] doAlphabetStringSplit(String left, String right, int expectSliceNumber) {
-
//将最大值最小值都转化为小写字母,供数值运算
-
left = left.toLowerCase();
-
right = right.toLowerCase();
-
int biglength = left.length() > right.length() ? left.length() : right.length();
-
if (left.length() > right.length()) {
-
String tailZeroPatrern = "%-" biglength "s";
-
right = String.format(tailZeroPatrern, right).replace(" ","0");
-
}
-
BigInteger[] tempResult = doBigIntegerSplit(G36Util.string2BigInteger(left), G36Util.string2BigInteger(right), expectSliceNumber);
-
String[] result = new String[tempResult.length];
-
//最小值不变,假设原始left排序有大写,排序大于转为小写的,改变left比最小值下限还小不影响结果
-
result[0] = left;
-
//最大值转为大写字母,提高最大值的上限,不影响结果
-
result[tempResult.length - 1] = right.toUpperCase();
-
//中间数值用小写转化的结果,只是对数据切分,不影响结果
-
for (int i = 1, len = tempResult.length - 1; i < len; i ) {
-
if (G36Util.bigInteger2String(tempResult[i]).length() < biglength) {
-
String headZeroPattern = "%" biglength "s";
-
result[i] =String.format(headZeroPattern, G36Util.bigInteger2String(tempResult[i])).replace(" ","0");
-
}else {
-
result[i] = G36Util.bigInteger2String(tempResult[i]);
-
}
-
}
-
return result;
-
}
plugin-rdbms-util组件中
com.alibaba.datax.plugin.rdbms.util.RdbmsRangeSplitWrap中调用
doAsciiStringSplit,改成调用doAlphabetStringSplit
至此改造完成。
- 打包测试下吧
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhiacaee
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22