一、实验概述
大数据计算服务(MaxCompute,原名 ODPS)是一种快速、完全托管的 GB/TB/PB 级数据仓库解决方案。MaxCompute 向用户提供了完善的数据导入方案以及多种经典的分布式计算模型,能够更快速的解决用户海量数据计算问题,有效降低企业成本,并保障数据安全。
本实验结合实际数据和案例,深入浅出的演示了如何使用MaxCompute的内置数据传输功能,详细介绍tunnel数据传输命令及通过tunnel JAVA SDK 定制开发数据传输服务功能。
二、实验目标
本实验通过控制台Data IDE和客户端两种方式进行实验,掌握不同的数据传输操作命令,以及相关注意事项。
完成此实验后,可以掌握的能力有:
1. tunnel 数据传输命令的基本操作;
2. tunnel JAVA SDK 定制开发数据传输服务;
三、学习建议
1. 掌握MaxCompute的内置的数据传输功能以及相关命令的基础操作;
2. 提前安装 ODPS客户端(下载客户端软件)
第 1 章:实验准备
1.1 申请MaxCompute资源
在弹出的左侧栏中,点击 创建资源 按钮,开始创建实验资源。
资源创建过程需要1-3分钟。完成实验资源的创建后,用户可以通过 实验资源 查看实验中所需的资源信息,例如:阿里云账号等。
1.2 准备测试账号
该实验需要和其他同学配合完成,请找到一个可以和你互相配合的同学,下文中会提到A用户、B用户,其中A用户即为你本人使用的阿里云的账号,B用户为和你配合的同学的阿里云账号;
实验中两个账户均使用的是阿里云主账号(或者具有项目admin权限的用户),可在两台电脑中登录,亦或使用同一台电脑里两个不同的浏览器打开,或一个使用浏览器打开,另一个使用odpscmd客户端;
为方便区别相关的账号操作,下述实验过程中A账号的操作记录均采用的命令行的方式进行操作截图,账号B的操作记录均使用页面浏览器的操作截图;
实验中的配置文件、文件路径、账号、项目名称、授权表等,均需根据具体的项目进行修改。
1.3 资源环境准备
1)请点击页面左侧的实验资源,在左侧栏中,查看本次实验资源信息。如图案例:
2)点击“实验资源”,查看所需具体资源,如图案例:
3)在弹出的左侧栏中,点击 创建资源 按钮,开始创建实验资源。
注意:由于实验环境一旦开始创建则进入计时阶段,建议学员先基本了解实验具体的步骤、目的,真正开始做实验时再进行创建
4)创建资源,如图案例:(创建资源需要几分钟时间,请耐心等候……)资源创建成功,如图案例:(注意资源中的项目名称、子用户名称、子用户密码、AK ID、AK Secret信息)
1.4 进入实验环境
1、登录控制台
1)点击“前往控制台”
注意:此实验界面为使用者提供了进入实验的用户名称,如 u-bcofvgpr 以及登录密码,请先记录下来,密码需要鼠标点击直接拷贝下来,以及使用其他工具的 AK ID 以及 AK Secret 秘钥对 ,项目名称等信息。将AK ID 和 AK Secret配置在安装的客户端的配置文件中。
2)输入用户名
3)点击下一步,输入密码:(刚才实验环境创建时所提供)
4)进入控制台界面
5) 点击 “大数据(数加)”进入大数据开发控制台
6) 点击”大数据开发套件”进入工作区界面
7)点击“进入工作区”,进入工作环境(首次进入显示每个菜单的帮助信息)
8) 点击“跳过”或逐个菜单看看,最终显示
9)点击“新建脚本”设置实验临时文件
10)设置文件名称、类型(选择ODPS SQL)、描述信息(建议非必须)、文件保存目录信息,点击“提交”进入SQL操作环境
2、配置客户端
1)如果为提前安装客户端,请参考下面网址进行安装:
(https://help.aliyun.com/document_detail/27971.html?spm=5176.doc27834.6.730.xbOX5m)
3)解压安装
4)配置客户端文件,在XXX(个人目录)\odpscmd_public\conf\,打开文件 odps_config.ini,修改配置信息;即将上述实验资源中提供的AK ID 以及 AK Secret 和项目名称分别填写在上述配置文件中,其他信息不变,如图:
5) 检查测试即通过命令行,进入\ODPS_DEMO\odpscmd_public\bin\,执行 odpscmd,进入交互界面,确认安装是否配置成功。案例如图:
执行后进入如下界面:(测试案例项目为bigdata_train)
6) 通过创建一个数据表测试:
------输入语句创建表dual
create table dual (X string);
------数据表中插入一条记录并检查
insert into table dual select count(*) from dual;
------检查插入结果
1.5 安装配置最新odpscmd 客户端
步骤1:客户端介质下载 (参考地址)
https://help.aliyun.com/document_detail/27971.html?spm=5176.doc27833.2.1.b6nngs 步骤2:解压odpscmd_public.zip 到本目录,如:解压至本地目录 E:\ ODPS_DEMO \odpscmd_public
步骤3:查看本次实验课用到的介质,可以看到如下的文件夹:
步骤4:在conf文件夹中有odps_config.ini文件。编辑此文件,填写相关信息:
project_name=<自己的项目名称>
access_id=<自己的项目生成的访问ID , www.aliyun.com网站上申请到的access_id>
access_key=<自己的项目生成的访问ID的密钥信息,即 www.aliyun.com网站上申请access_key>
end_point=http://service.odps.aliyun.com/api (tunnel JAVA SDK 需要)
tunnel_endpoint=http://dt.odps.aliyun.com (tunnel JAVA SDK 需要)
log_view_host=http://logview.odps.aliyun.com (默认)
https_check=true (默认)
注意: [在申请资源部分可获取实验所需的项目名称、所需的access_id(AK ID) 、access_key(AK Secre)等信息 ] 如下图开通资源后所示:步骤5:修改好配置文件后运行bin目录下的odpscmd(在Linux系统下是./bin/odpscmd,Windows下运行./bin/odpscmd.bat),现在可以运行 MaxCompute 命令,如:
注意:项目可以随时根据情况切换,上图表示环境设置成功.
将 E:\ODPS_DEMO\odpscmd_public\bin 加入环境变量 PATH,方便通过命令行调用 odpscmd
1.5 下载配套实验材料
(1) 下载本实验所用到的介质包:
下载附件,将ODPS_DEMO.zip解压至本地目录 E:\ODPS_DEMO,解压密码为:aca21104
(2) 查看本次实验课用到的介质:
dir E:\ODPS_DEMO\Resources\02-DataTransfer (注意里面包含建表脚本文件和实验数据文件)
至少应该包含以下文件:
(3) 检查系统是否安装了Java运行环境(1.6及以上版本):
(4) 检查是否安装了eclipse,建议使用 luna-sr2 版本;
说明:目前高版本的Eclipse Neon有可能会导致插件加载失败,请使用Eclipse Luna版本。(下载地址:http://www.eclipse.org/downloads/packages/release/luna/sr2)
(5) 使用实验账号,登录阿里云官网,检查账号下的可用资源:
应至少包括 大数据计算 服务;
如无项目,请新建一个项目用于本次实验,本实验中使用项目名称为 IDE;
检查可用 AccessKeyID 和 AccessKeySecret,并记录一对用于后续实验;
第 2 章:tunnel 数据传输命令基本操作
2.1 tunnel upload 目标为单表
注意本节实验首先保证表t_tunnel 必须已经创建完成,如果没有,请参考如下语句创建:
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
(1) 使用 upload 子命令,上传文件 people.csv 到表 t_tunnel 中:
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\people.csv t_tunnel;
(2) 检查上传结果:
(3) 再上传一遍,验证一下tunnel 上传数据的方式是 append 还是 overwrite:
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\people.csv t_tunnel;
read t_tunnel;
上述结果表明tunnel upload操作为append操作不是overwrite操作
2.2 tunnel upload 目标为分区表
本节实验首先保证表t_tunnel_p存在,若不存在,请参考下面语句处理(或直接重新创建表t_tunnel_p):
drop table if exists t_tunnel_p;
create table t_tunnel_p (id int, name string) partitioned by (gender string);
(1) 创建表 t_tunnel_p 的分区 gender='male’中:
alter table t_tunnel_p add if not exists partition (gender='male');
(2) 使用 upload 子命令,上传文件 men.csv 以及 women.csv 到表 t_tunnel_p 的已存在的分区 gender='male’中
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\women.csv t_tunnel_p/gender='male';
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\men.csv t_tunnel_p/gender='male';
(3) 检查表 t_tunnel_p 中的内容,体会一下分区内容和标称值的逻辑关系:
向同一个分区装载不同文件时,两个文件的内容append到一起了
2.3 tunnel upload 源文件为目录
本节实验首先保证表t_tunnel存在,否则参照下面操作新建表t_tunnel ;
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
(1) 将目录E:\ODPS_DEMO\resources\02-DataTransfer\famous_people\ 下的所有文件都上传到 t_tunnel 中去:
truncate table t_tunnel;
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\famous_people\ t_tunnel;
(2) 检查上传结果:
2.4 tunnel upload 容忍错误记录
注意表t_tunnel已经存在,否则,可单独创建:
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
(1) 将文件E:\ODPS_DEMO\resources\02-DataTransfer\people_bad.csv上传至t_tunnel:
truncate table t_tunnel;
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\people_bad.csv t_tunnel;
read t_tunnel;
默认情况下,不允许有错误数据,如果有则抛出错误,数据装载失败
(2) 指定容忍错误的参数 -dbr 为 true:
truncate table t_tunnel;
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\people_bad.csv t_tunnel -dbr true;
read t_tunnel;
指定容易错误的参数 -dbr 为ture 后,错误的数据不会被装载,正确的数据会被装载,如上图,记录ID为10的记录为错误数据没有被装载上
2.5 tunnel upload 扫描文件
t_tunnel建表参考:
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
欲将文件E:\ODPS_DEMO\resources\02-DataTransfer\crawd.csv上传至t_tunnel,可以在上传前先做个预扫描
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\crawd.csv t_tunnel --scan=only;
2.6 tunnel upload 行、列分隔符
本节实验首先保证表t_tunnel存在,若不存在,请参考下面语句处理(或直接重新创建表t_tunnel):
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
将文件E:\ODPS_DEMO\resources\02-DataTransfer\people_delimeter.csv文件上传到 t_tunnel 中去:
truncate table t_tunnel;
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\people_delimiter.csv t_tunnel -fd || -rd &;
read t_tunnel;
指定数据文件的列分隔符 –fd || , 行分隔符 –rd &
2.7 tunnel upload多线程
本节实验首先保证表t_tunnel存在,若不存在,请参考下面语句处理(或直接重新创建表t_tunnel):
drop table if exists t_tunnel;
create table t_tunnel (id int, name string);
使用多个线程将文件E:\ODPS_DEMO\resources\02-DataTransfer\crawd.csv文件上传到 t_tunnel 中去:
truncate table t_tunnel;
tunnel upload E:\ODPS_DEMO\resources\02-DataTransfer\crawd.csv t_tunnel -threads 8;
read t_tunnel;
count t_tunnel;
当数据文件较大地,可以通过-threads N 指定N个线程同时进行装载,加快速度
2.8 tunnel download 非分区表
将表 t_tunnel 下载到本地文件 t_tunnel.csv
tunnel download t_tunnel t_tunnel.csv;
数据下载当前路径下,可以指定导出文件的具体路径,指定path\t_tunnel.csv 即可 path 根据自己的机器情况指定
2.9 tunnel download 分区表
将表 t_tunnel_p 下载到本地文件 t_tunnel_p.csv
tunnel download t_tunnel_p/gender='male' t_tunnel_p.csv;
第 3 章:tunnel JAVA SDK 定制开发数
3.1 安装配置eclipse开发环境
首先,解压下载的eclipse-java-luna-SR2-win32-x86_64.zip到E:\ODPS_DEMO,然后执行以下操作:
(1) 将E:\ODPS_DEMO\InstallMedia\odps-eclipse-plugin-bundle-0.16.0.jar 拷贝至目录E:\ODPS_DEMO\eclipse\plugins
(2) 执行E:\ODPS_DEMO\eclipse\eclipse.exe,打开 eclipse,点击 New -> Other
(3) 配置 odps
(4) 指定 JavaProject Name:
3.2 单线程上传文件
此部分建表语句参考:
drop table if exists t_tunnel_sdk;
create table t_tunnel_sdk (
)
partitioned by (gender string);
本实验可参考脚本:E:\ODPS_DEMO\resources\02-DataTransfer\UploadSample.java
(1) 新增 Java 类:
(2) 类名为UploadSample,包名为 DTSample
(3) 设计该类实现功能为将单个文件上传至ODPS的表中,需要的输入参数为:
-f <file_name>
-t <table_name>
-c <config_file>
[-p ]
[-fd <field_delimiter>]
编写方法 printUsage,提示调用语法:
private static void printUsage(String msg) {
System.out.println(
"Usage: UploadSample -f file \\\n"
+ " -t table\\\n"
+ " -c config_file \\\n"
+ " [-p partition] \\\n"
+ " [-fd field_delimiter] \\\n"
);
if (msg != null) {
System.out.println(msg);
}
}
编写获取、解析输入参数的方法 :
private static String accessId;
private static String accessKey;
private static String OdpsEndpoint;
private static String TunnelEndpoint;
private static String project;
private static String table;
private static String partition;
private static String fieldDelimeter;
private static String file;
private static void printUsage(String msg) {
System.out.println(
"Usage: UploadSample -f file \\\n"
+ " -t table\\\n"
+ " -c config_file \\\n"
+ " [-p partition] \\\n"
+ " [-fd field_delimiter] \\\n"
);
if (msg != null) {
System.out.println(msg);
}
}
private static void parseArgument(String[] args) {
for (int i = 0; i < args.length; i++) {
if ("-f".equals(args[i])) {
if (++i == args.length) {
throw new IllegalArgumentException("source file not specified in -f");
}
file = args[i];
}
else if ("-t".equals(args[i])) {
if (++i == args.length) {
throw new IllegalArgumentException("ODPS table not specified in -t");
}
table = args[i];
}
else if ("-c".equals(args[i])) {
if (++i == args.length) {
throw new IllegalArgumentException(
"ODPS configuration file not specified in -c");
}
try {
InputStream is = new FileInputStream(args[i]);
Properties props = new Properties();
props.load(is);
accessId = props.getProperty("access_id");
accessKey = props.getProperty("access_key");
project = props.getProperty("project_name");
OdpsEndpoint = props.getProperty("end_point");
TunnelEndpoint = props.getProperty("tunnel_endpoint");
} catch (IOException e) {
throw new IllegalArgumentException(
"Error reading ODPS config file '" + args[i] + "'.");
}
}
else if ("-p".equals(args[i])){
if (++i == args.length) {
throw new IllegalArgumentException(
"odps table partition not specified in -p");
}
partition = args[i];
}
else if ("-fd".equals(args[i])){
if (++i == args.length) {
throw new IllegalArgumentException(
"odps table partition not specified in -p");
}
fieldDelimeter = args[i];
}
}
if(file == null) {
throw new IllegalArgumentException(
"Missing argument -f file");
}
if (table == null) {
throw new IllegalArgumentException(
"Missing argument -t table");
}
if (accessId == null || accessKey == null ||
project == null || OdpsEndpoint == null || TunnelEndpoint == null) {
throw new IllegalArgumentException(
"ODPS conf not set, please check -c odps.conf");
}
}
(4) 编写方法,从文件中读出记录,同时将这些记录格式化
读出记录,逐列处理
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import com.aliyun.odps.Column;
import com.aliyun.odps.OdpsType;
import com.aliyun.odps.TableSchema;
import com.aliyun.odps.data.ArrayRecord;
import com.aliyun.odps.data.Record;
class RecordConverter {
private TableSchema schema;
private String nullTag;
private SimpleDateFormat dateFormater;
private DecimalFormat doubleFormat;
private String DEFAULT_DATE_FORMAT_PATTERN = "yyyyMMddHHmmss";
public RecordConverter(TableSchema schema, String nullTag, String dateFormat,
String tz) {
this.schema = schema;
this.nullTag = nullTag;
if (dateFormat == null) {
this.dateFormater = new SimpleDateFormat(DEFAULT_DATE_FORMAT_PATTERN);
} else {
dateFormater = new SimpleDateFormat(dateFormat);
}
dateFormater.setLenient(false);
dateFormater.setTimeZone(TimeZone.getTimeZone(tz == null ? "GMT" : tz));
doubleFormat = new DecimalFormat();
doubleFormat.setMinimumFractionDigits(0);
doubleFormat.setMaximumFractionDigits(20);
}
/**
* record to String array
* */
public String[] format(Record r) {
int cols = schema.getColumns().size();
String[] line = new String[cols];
String colValue = null;
for (int i = 0; i < cols; i++) {
Column column = schema.getColumn(i);
OdpsType t = column.getType();
switch (t) {
case BIGINT: {
Long v = r.getBigint(i);
colValue = v == null ? null : v.toString();
break;
}
case DOUBLE: {
Double v = r.getDouble(i);
if (v == null) {
colValue = null;
} else {
colValue = doubleFormat.format(v).replaceAll(",", "");
}
break;
}
case DATETIME: {
Date v = r.getDatetime(i);
if (v == null) {
colValue = null;
} else {
colValue = dateFormater.format(v);
}
break;
}
case BOOLEAN: {
Boolean v = r.getBoolean(i);
colValue = v == null ? null : v.toString();
break;
}
case STRING: {
String v = r.getString(i);
colValue = (v == null ? null : v.toString());
break;
}
default:
throw new RuntimeException("Unknown column type: " + t);
}
if (colValue == null) {
line[i] = nullTag;
} else {
line[i] = colValue;
}
}
return line;
}
/**
* String array to record
* @throws ParseException
* */
public Record parse(String[] line){
if (line == null) {
return null;
}
int columnCnt = schema.getColumns().size();
Column[] cols = new Column[columnCnt];
for (int i = 0; i < columnCnt; ++i) {
Column c = new Column(schema.getColumn(i).getName(),
schema.getColumn(i).getType());
cols[i] = c;
}
ArrayRecord r = new ArrayRecord(cols);
int i = 0;
for (String v : line) {
if (v.equals(nullTag)) {
i++;
continue;
}
if (i >= columnCnt) {
break;
}
OdpsType type = schema.getColumn(i).getType();
switch (type) {
case BIGINT:
r.setBigint(i, Long.valueOf(v));
break;
case DOUBLE:
r.setDouble(i, Double.valueOf(v));
break;
case DATETIME:
try {
r.setDatetime(i, dateFormater.parse(v));
} catch (ParseException e) {
throw new RuntimeException(e.getMessage());
}
break;
case BOOLEAN:
v = v.trim().toLowerCase();
if (v.equals("true") || v.equals("false")) {
r.setBoolean(i, v.equals("true") ? true : false);
} else if (v.equals("0") || v.equals("1")) {
r.setBoolean(i, v.equals("1") ? true : false);
} else {
throw new RuntimeException(
"Invalid boolean type, expect: true|false|0|1");
}
break;
case STRING:
r.setString(i, v);
break;
default:
throw new RuntimeException("Unknown column type");
}
i++;
}
return r;
}
}
(5) 编写主方法,读取文件,上传到odps表中去:
public static void main(String args[]) {
try {
parseArgument(args);
} catch (IllegalArgumentException e) {
printUsage(e.getMessage());
System.exit(2);
}
Account account = new AliyunAccount(accessId, accessKey);
Odps odps = new Odps(account);
odps.setDefaultProject(project);
odps.setEndpoint(OdpsEndpoint);
BufferedReader br = null;
try {
TableTunnel tunnel = new TableTunnel(odps);
tunnel.setEndpoint(TunnelEndpoint);
TableTunnel.UploadSession uploadSession = null;
if(partition != null) {
PartitionSpec spec = new PartitionSpec(partition);
System.out.println(spec.toString());
uploadSession=tunnel.createUploadSession(project, table,spec);
System.out.println("Session Status is : " + uploadSession.getStatus().toString());
}
else
{
uploadSession= tunnel.createUploadSession(project, table);
//System.out.println("Session Status is : " + uploadSession.getStatus().toString());
}
Long blockid = (long) 0;
RecordWriter recordWriter = uploadSession.openRecordWriter(blockid, true);
Record record = uploadSession.newRecord();
TableSchema schema = uploadSession.getSchema();
RecordConverter converter = new RecordConverter(schema, "NULL", null, null);
br = new BufferedReader(new FileReader(file));
Pattern pattern = Pattern.compile(fieldDelimeter);
String line = null;
while ((line = br.readLine()) != null) {
String[] items=pattern.split(line,0);
record = converter.parse(items);
recordWriter.write(record);
}
recordWriter.close();
Long[] blocks = {blockid};
uploadSession.commit(blocks);
System.out.println("Upload succeed!");
} catch (TunnelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
(6) 在 ODPS 中建表:
odpscmd -f E:\ODPS_DEMO\resources\02-DataTransfer\crt_tbl.sql
(7) 在 eclipse 中设置测试运行参数:
将下列参数填入program parameter:-f E:\ODPS_DEMO\resources\02-DataTransfer\uploadDataSet.csv -t t_tunnel_sdk -p ‘gender=“Male”’ -fd , -c E:\ODPS_DEMO\odpscmd_public\conf\odps_config.ini
通过console查看输出信息:
去ODPS project里检查上传结果:read t_tunnel_sdk;
3.3 单线程下载文件
本实验可参考脚本:E:\ODPS_DEMO\resources\02-DataTransfer\DownloadSample.java
(1) 在已有的名称为 DataTransfer 的 Java project中的 DTSample 包下新增 Java 类:
(2) 编写方法 printUsage,提示调用该程序的输入参数;
(3) 编写方法 parseArgument,获取并解析输入参数;
(4) 编写类RecordConverter用来格式化数据,生成 Record 记录;
(5) 编写方法 main 方法,实现单线程数据下载:
//根据输入参数中的配置文件,配置阿里云账号
Account account = new AliyunAccount(accessId, accessKey);
Odps odps = new Odps(account);
odps.setDefaultProject(project);
odps.setEndpoint(OdpsEndpoint);
//基于上述云账号,创建服务入口类
TableTunnel tunnel = new TableTunnel(odps);
tunnel.setEndpoint(TunnelEndpoint);
//创建从上述odps服务通道中下载数据的会话,分为分区的表和非分区表两种:
TableTunnel.DownloadSession session;
if(partition != null) {
PartitionSpec spec = new PartitionSpec(partition);
session= tunnel.createDownloadSession(project, table, spec);
}else{
session= tunnel.createDownloadSession(project, table);
}
//从odps表中读出记录,格式化后,写入到本地文件:
RecordReader reader = session.openRecordReader(0L, session.getRecordCount(),
true);
TableSchema schema = session.getSchema();
Record record;
RecordConverter converter = new RecordConverter(schema, "NULL", null, null);
String[] items = new String[schema.getColumns().size()];
while ((record = reader.read()) != null) {
items = converter.format(record);
for(int i=0; i<items.length; ++i) {
if(i>0) out.write(fieldDelimeter.getBytes());
out.write(items[i].getBytes());
}
out.write(lineDelimiter.getBytes());
}
reader.close();
out.close();
(6) 在 eclipse 中设置测试运行参数:
将下列参数填入 program parameter
-f E:\ODPS_DEMO\resources\02-DataTransfer\downloadMaleDataSet.csv -fd , -c E:\ODPS_DEMO\odpscmd_public\conf\odps_config.ini -t t_tunnel_sdk -p ‘gender=“Male”’
去查看下载文件E:\ODPS_DEMO\resources\02-DataTransfer\downloadMaleDataSet.csv,并和ODPS表 t_tunnel_sdk 中的数据对比。
第 4 章:实验总结
4.1 实验总结
MaxCompute提供的数据传输功能,tunnel命令集方便我们上传本地数据到单表、分区表,并支持上传时自定义设计列分隔符、行分隔符、及数据容错等能力,数据量较大,还可以指定线程数据来加速数据的上传,实验详细介绍了日常工作中常用的功能。
另外,MaxCompute还提供了tunnel JAVA SDK 方便我们进行程序开发时使用数据传输功能