实际的企业使用场景里,可能需要把不同项目里的数据、函数、计算资源等一起使用。那如何实现这种跨项目的使用呢,本文用实际例子来说明下。
准备
- 项目空间:grant_from,需要授权的数据、函数、资源都在这个项目里
- 项目空间:grant_to,被授权的用户需要在这个项目里执行计算。
- 用户:aliyun$xxxx@aliyun.com,grant_from项目的project owner,后续的授权操作是这个账号执行的。
- 用户:ram$xxxx@aliyun.com:chuanxue2,通过在大数据开发套件里授权了grant_to项目的开发角色,现在在使用grant_to项目进行计算的时候,需要用到grant_from项目里的数据、函数和资源。
- 表:dual,在grant_from和grant_to里都有的一张表,里面就一条数据,用于测试UDF用的。
- 表:grant_from.wc_in,grant_from项目里的一张表。需要授权给ram$xxxx@aliyun.com:chuanxue2,让他在grant_to里做计算的时候也能用到。
- 函数:getPersonName,在grant_from里的待授权函数
- 资源resource_file.txt、和其他一些jar包是在grant_from里的资源文件。
表
授权
需要添加用户并做表对账号的授权。授权后被授权账号可以跨项目引用。
-- 以下操作是在grant_from里由aliyun$xxxx@aliyun.com执行的
-- add user只需要添加一次就够了。以前添加过了就可以跳过
odps@ grant_from>add user RAM$xxxx@aliyun.com:chuanxue2;
-- 如果只是SQL查询,只要给Select权限就够了。不过使用MapReduce作为输入表的话,还需要Describe 权限。这里一并授权了。
odps@ grant_from>grant Select,Describe on table wc_in to user RAM$xxxx@aliyun.com:chuanxue2;
需要提一句,可以在大数据开发套件的数据管理里更方便地做数据授权,可以参考这里。
使用
可以在SQL里,使用ProjectName.TableName使用这张表,比如
---以下操作是由RAM$xxxx@aliyun.com:chuanxue2在grant_to里操作
odps@ grant_to>select * from grant_from.wc_in;
而在MapReduce/Graph里,就以MapReduce为例,可以把代码写成
InputUtils.addTable(TableInfo.builder().projectName("grant_from").tableName("wc_in").build(), job);
OutputUtils.addTable(TableInfo.builder().tableName("wc_out").build(), job);
其他的一切使用方法都和使用本项目内的表的用法一样,这里不再赘言。
函数
授权
比如grant_from里有个解析json字符串的内容的一个UDF,现在希望让RAM$xxxx@aliyun.com:chuanxue2在grant_to里也能用起来。
先看看这个UDF,aliyun$xxxx@aliyun.com在grant_from里是怎么用的:
odps@ grant_from>select getPersonName('{"id":100,"name":"chuanxue","age":11}') from dual;
+-----+
| _c0 |
+-----+
| chuanxue |
+-----+
授权之前,需要确定这个函数都涉及了什么资源文件
odps@ grant_from>desc function getPersonName;
Name getPersonName
Owner ALIYUN$xxxx@aliyun.com
Created Time 2017-05-26 13:31:33
Class odps.test.GetPersonName
Resources grant_from/resources/getPersonName.jar,grant_from/resources/gson-2.2.4.jar
所以授权的步骤包括:
--add user还是如前面提到,只需要添加一次,如果已经添加过可以不添加
odps@ grant_from>add user RAM$xxxx@aliyun.com:chuanxue2;
-- 授权函数
odps@ grant_from>grant read on function getPersonName to user RAM$xxxx@aliyun.com:chuanxue2;
OK
odps@ grant_from>grant read on resource getPersonName.jar to user RAM$xxxx@aliyun.com:chuanxue2;
OK
odps@ grant_from>grant read on resource gson-2.2.4.jar to user RAM$xxxx@aliyun.com:chuanxue2;
OK
使用
被授权后, RAM$xxxx@aliyun.com:chuanxue2就可以在grant_to这个项目里使用到被授权的函数了。通过ProjectName:FunctionName可以很方便的引用这个函数。
-- 这个操作由被授权的子账号在grant_to里执行
odps@ grant_to>select grant_from:getPersonName('{"id":100,"name":"chuanxue","age":11}') from dual;
+-----+
| _c0 |
+-----+
| chuanxue |
+-----+
资源
命令行引用
需要资源的授权的场景比较少。不过比如说刚才的那个函数,也可以只把资源授权给对方,让对方自己创建一个函数。
资源文件的授权和前面函数的授权方式一样,不再重复,创建函数的方法和调用可以参考:
-- 在grant_to里创建一个函数getPersonName2,使用的资源都是来自之前被授权的grant_from里的getPersonName.jar和gson-2.2.4.jar
odps@ grant_to>create function getPersonName2 as odps.test.GetPersonName using grant_from/resources/getPersonName.jar,grant_from/re
sources/gson-2.2.4.jar;
-- 创建好了后的调用就正常调用了。dual表也是grant_to里的dual表。
odps@ grant_to>select getPersonName2('{"id":100,"name":"chuanxue","age":11}') from dual;
而在mapreduce里引用其他项目的jar包,也是一样。先在grant_from里做授权
-- cx_word_count2.jar其实就是cx_word_count.jar改了文件名,然后传到grant_from作跨项目引用的。
odps@ grant_from>add jar C:\Users\chuanxue\Desktop\cx_word_count2.jar -f;
OK: Resource 'cx_word_count2.jar' have been updated.
odps@ grant_from>grant read on resource cx_word_count2.jar to user RAM$xxxx@aliyun.com:chuanxue2;
OK
授权结束后,RAM$xxxx@aliyun.com:chuanxue2就可以在grant_to里使用这个jar包
odps@ grant_to>jar -resources grant_from/resources/cx_word_count2.jar -classpath C:\Users\chuanxue\Desktop\cx_word_count2.jar odps.test.WordCount;
Java代码里读取资源
还有一种场景,就是如何在代码里跨项目读资源文件。一般本项目里的资源文件的读取方法是(参考这里)
byte[] buffer = new byte[1024];
int bytesRead = 0;
String filename = context.getJobConf().get("import.filename");
bufferedInput = context.readResourceFileAsStream(filename);
while ((bytesRead = bufferedInput.read(buffer)) != -1) {
String chunk = new String(buffer, 0, bytesRead);
importdata.append(chunk);
}
在命令行里的调用方式是:
odps@ grant_to>jar -resources grant_from/resources/cx_word_count3.jar,grant_from/resources/resource_file.txt -classpath C:\Users\chuanxue\Desktop\cx_word_count3.jar odps.test.WordCount;
在代码里,还是用
String filename = "resource_file.txt";
bufferedInput = context.readResourceFileAsStream(filename);
也就是说,是在jar命令里告知任务使用的资源是来自其他项目的,到了MapReduce的Java代码里,所有的用法照旧,不需要特别指定资源的项目。