00:00
来,那现在我们,呃,来吧,同学们,我们来把这个函数啊,咱们一起写一下,因为大家是第一次写对吧?啊来我们一起写一下,那点击这个finish。来点击这次window。嗯,这个关掉就行啊,那我们要想写这个have的UD啊,TF函数啊,那我们首先需要引入一个have的依赖对吧?那接着咱们要引的话,其实主要就引那个谁就行了,Have eec就够了啊,咱们找到那个需要的依赖啊。我。往下翻,往下翻,这就是我们所需的这个have的依赖啊,CTRLC粘过来放到我们这个代码当中,CTRLV啊,那这边咱们刷新一下啊,好,这个依赖呢,需要这个下载一下,咱们等一会儿啊。嗯,因为我这个本地仓库,我把之前那个给他删了,我换了一个空白的没有仓库啊,那这个需要可能就下一下啊,咱们稍微等一下。嗯。嗯。把这个事给忘了。
01:00
嗯。稍微等会儿吧。嗯。OK,那这个应该差不多。快下完了还没出来啊,这个得等他那个plugin出现之后,那这个才算下完了啊。咱们稍微等一下依赖呢,应该还没导进来,所以咱们没法写啊。嗯。呃,下完了我再刷新一下。刚才应该是有一个依赖,他没有下载下来啊,应该是有一个没下载下来啊。嗯。这些都没问题。可能是刚才超时了啊,一直下载没,其实没下载完,那个一直下载不下来,超时了嘛,嗯,这回又得下了,就是等一下吧,那就啊应该也快啊这一个依赖。
02:08
嗯。OK,那这时候呢,我们开始去写我们这个UDTF函数的代码,来,咱们右键啊,右键你有一个加class,在这起个名字吧,咱们叫做com.at硅谷。啊,然后点呃金帽吧,啊然后后边呢,来一个呃,Have啊,然后点UD,咱们叫UTF对吧,那我们呃这个类名叫什么类名呢?类名就跟咱们函数名保持一致就行了,咱们叫什么?是不是explode explorede啊explode然后是不是Jason,然后ay是不是咱们那个函数的名字就是这个呀,那这个类名咱也叫这个啊键名是诶不能这么写啊,怎么还写成下划线了呢?咱们应该是,哎这个图风命名就行,Explo的接森瑞是不是就可以了,然后咱们回收啊好,那这个搞定,那搞定之后呢,我们接下来按照我们官网上的要求,我们需要首先做的第一件事就是先去extend继承啊,这个generate UD TF,这个呃,抽象类对吧?来咱们继承一下,呃,S extend啊GE啊,Ne generate。
03:19
RC,然后U,呃,DTFUTF,然后我们会说啊,OK,那这里边有几个方法需要实现啊,咱们不用,呃,让它自动提示了,咱们直接把官网上的这个代码咱们粘过来啊,粘过来啊复制,然后复制过来之后呢,我们放在这儿CRL,那复制过来之后,咱们需要把这里边没用的一些东西给它干掉啊,你像这个是不是他自己定义的变量啊,咱们不用,那这个close方法咱用不到,直接干掉,那这个移上的方法咱们需要用的啊,里边的逻辑咱们先留着,那这个也是他自己的处理逻辑,咱们不要啊,删掉就行了,好,咱们留下这些内容,那把这个呢,我们把class引一下啊,把它引一下。走。那这个呢,引一下啊,这儿还有一个。
04:04
这个呃,Out enter啊,走,那list out enter啊,OK,还剩最后一个啊,Out enter,还有一个。行,这回这个比较清楚了啊,然后这时候呢,咱们就已经,嗯是不是把这个这个整个的代码的结构咱们已经拿过来了呀,对吧,咱们在这儿呢,要实现的方法有两个,一个是隐Internet,一个是process,它咱们就不用管了,然后大家可以看到Internet方法,这是不是明显它是过时了,对吧?那其实过时影不影响咱们使用啊,其实能用啊,因为它只要底层有这个呃,它这个相应的这个呃方法的依赖有这个声明咱是不是就能就能用啊对吧?但是这个过时的方法咱们尽量不用啊,为什么呀,因为你要用了它之后,假如说我们这个呃集群当中,咱们hi武升级了啊,咱们have武升级的,比如说现在咱们3.1.2对吧,那最新的还我已经到四了,对不对,那假如说我们升级到四,那升到四之后,你说你这个函数,假如说过时的API在四里边已经去掉了,那你这个函数还能用吗。
05:05
是不是就用不了了呀,对不对,他是不是有这种也这是不是就是所谓的兼容性问题啊,对不对,那所以这种过时的方法咱们尽量不用,那不用的话,咱们就去找一下它那个不过时的方法是谁对吧?那怎么找呢?咱们去他这个在这里边去找就行,或者说你在这呢,看你这有没有提示CTRLQ。CTRLQ,它这个注释做的不好啊,他是不是没有告诉咱们那个不过时的是哪个方法呀,没告诉没告诉咱自己去找呗,找到他这个负类啊,你就往下翻啊,往下翻,哎二有一个three KT的过时,这就是咱们刚才引用的那个过时的方法,那你紧着往下翻呢,往下翻哎,不用往下这呢啊,它上面这个方法。是不是就是那个不过时的以initialize方法呀,哎就是这样的,那它俩有啥区别,我们看一下啊,有啥区别,首先先看返回值类型是不是一样的,那这个输入类型呢。哎,好像有点不太一样了,这个好像是一个什么object inspector数组,那上面呢,是一个ru object inspector是不是那有区别,那所以说咱们这呢,用用上面那个,那也就是说我们只需要将代码当中的这个参数类型是给它变一下就行,诶那这个方法它就不过时了,那那咱们用的就是这个啊。
06:19
然后呢,这时候我给大家解释一下啊,我们回忆一下隐匿时代的方法,它的作用是什么?第一个作用是进行参数类型的交价,第二个是限定输出的类型,对不对,那这个怎么是怎么去实现这些功能啊来我们先来给大家分析一下。既然我这个隐代的方法,我要去校验输入啊,它的这个参数的类型以及个数对不对,那你是不是必须得拿到它那个输入类,输入的那个参数的类型及个数啊,对不对,那怎么拿到啊。啊,那官网上是这么描述的,他说什么呀,他说have啊,会调用形带的方法,然后呢,去通知咱们这个参数的类型对不对,它调用的时候它怎么通知啊,所谓的通知在这指的是什么呀。
07:08
所谓的通知其实就是怎么做,Have是不是会调用这个函数,调用函数它是不是得给你传参?不对,它是不是就是将have,咱们那个函数的输入参数的个数以及类型,是不是通过这个参数给你传到这个方法里边来了呀。对不对,这就是他这个所谓的通知,那也就是说我们实际上从这个里边就能够获取到咱们这个函数的输入的类型以及个数。嗯,是这样的啊,然后你看返回值是什么,返回值类型好像跟输入的类型是一样的吧,对不对,那输入类型也是一个什么叫做ru objector in此or也是这东西,那那所以说我们要做的是应该是什么呀?Have是不是把咱们这个函数的输入类型以及个数封装到了一个这样的东西里边,然后传给咱们了,那咱们要做的是什么?
08:02
是不是将我们这个输出的啊,这个类型以及个数是不是交给给它封装成一个这样的一个对象,然后返回给have啊,首先是这样的一个逻辑是这样的啊,然后这时候呢,我们就来看一看这个东西,它到底是个什么玩意儿啊,什么叫做ru object inspector,那我们现在呢,先看object inspector。这是不是就是所谓的对象检查器对不对,这个在我们官网上有明确的说明,是不是有这个东西啊,这就是它这是一个类啊,它这个对象检查器它有什么作用啊,也是在这儿呢,它是不是就相当里边封装了我们have里边的数据类型啊,对不对,那也就是说我一个string会有一个string对象检查器啊,Int会有int对应大器,那你快观察一下它这。传进来的是一个什么对象检查器啊。是一个什么in,是一个strip不是吧,是一个ruru,是不是我们还有当中一个复杂数据类型叫做结构体啊,对不对,是一个结构体对象检查器,那哎,也就是说它将我们这个函数的输入类型以及输入的个数给你封装到了一个那个结构体当中。
09:10
哎,为什么要封装到一个结构体里边呢?或者说它封装成结构体之前,你看它封装到一个什么里边了。之前那个过时的话,是一个对象减压器的一个数组啊,对不,就这个数组咱们好理解,为什么?因为你这个一个函数,你的参数是不是有可能有多个,对不对,那我有多个,每一个参数是不是都有一个自己的对应RT,那所以说是不是给你传来一个数组,这个应该好理解对吧?啊,那为什么现在它不用数组来变成结构体了。啊,那结构体是什么样的呀,大家都知道have当中的结构体呢,其实相当于啊大如大家如果学过C语言的话,那肯定知道我们C语言当中有一个数据结构叫做ru的,对不对?那ru其实就是有点类似于我们Java当中那个class对不对?你class里边是不是能够声明咱们这个字段啊,也能声明每个字段的自己的类型,对不对,那ru结构体是不是就这样一个东西啊,对不对,也就是说一个ru的结构体当中可以有多个字段,每个字段都有自己的字段名和自己的类型。
10:11
哎,那这个正好是不是可以对应于我们的多个参数啊。你看你这个函数需要传多个参数,那每个参数是不是都有自己的参数的类型啊对,那你是不是就可以把这多个参数当做一个结构体,哎,给它封装一下,那是不是这个结构体对象解压器里边就已经拥有了我所有参数的类型。对不对。啊,注意啊,这个不是在给他传数据,只是在给以尼代的方法传你这个多个参数的类型,是不是只是在传类型啊,啊,那所以说把类型哎,多个参数给你封装到一个结构体里边也是说得过去的啊,这个没毛病啊,这个结构体对象元器咱们应该能理解了啊,就是类里边呢,封装了我所有参数的类型啊,搞清楚好,那现在咱们再说这个输出。哎,那我输出它为什么也要封装成一个结构体对象检查器呢?
11:06
也就是我的输出类型也要封装到一个结构体里边啊,这是为啥?因为大家都知道UDTF函数啊,它是不是会把一个呃一行数据给你大成多行啊,对吧,那大成多行之后,是不是可以有一个列,也可以有多个列呀。这个呢,咱们体会一下啊,比如说一个explo的函数,我给他一个数组,那它炸出来是不是就一个列,那我给它一个map,它炸来是不是就两列呀,对不对?所以说你炸出来的话呢,可以有多个列,那每个列是不是也可以有不同的类型。对不对,那所以说它这边将我们输出的多个列,它的类型呢,也封装到了一个结构体里边。啊,能理解吧,呃,结构里边的每个字段就对应于我们的每个列。啊,那输出这边输入这边呢,那结构体当中的每个字段就对应一我的一个函数啊不不不不,一个函数一个输入一个参数一个参数啊啊重新说一下就是还这个输入这边呢,相当于结构体当中的每个字段就对应于我的每一个输入的参数啊,是这样的啊,那输出这边每一个字段对应一个每个列啊就是这个意思啊好,那这块呢,我们大家把这俩东西得先搞清楚啊行,那搞清楚之后呢,我们就开始去实现咱们这个函数的逻辑了啊。
12:22
哎,这个函数呢,前面一再强调有俩功能,一个功能呢是校验输入的参数,对不对,那怎么校验呢?你要想校验是不是得先拿到咱们这个参数的个数以及类型才能校验呀,对不对,怎么拿,是不是通过这个玩意去拿啊,通过它去拿啊,那通过拿他怎么拿呀,这个东西怎么用啊,那不知道怎么用,那你就把它拿过来点一下呗,看这里边有啥,诶首先你点完之后呢,第一个方法就是啥。获取ru是不是获取所有的结构体的field field是什么?是不是就是这个结构体当中的一个一个的字段呀,对吧?啊会这个字段的什么东西,字段的reference就是字段的引用对不对?那OK,我们现在是不是就得先获取到每个字段的引用啊,因为每个字段是不是指代的就是我的每一个参数啊。
13:14
的一个字段对应一个参数啊,所以获取咱们所谓的所谓引用,那我们看一看它的返回值是什么类型,CTRLV,你会发现它的返回值类型是什么呀,是一个例子的集合。哎,那既然是一个例子的集合啊,那你说这我们可以利用这个集合来去做什么样的校验。你想一想啊,它反过去一个集合,很显然一个集合是不是应该是一个结构体当中的一个。一个集合里边的每个元素应该是什么?是不是应该是这个,呃,结构体当中的每个字段呀,对不对啊,那集合当中有多少个字段。啊,那就说明什么,说明我们传进来的参数就有多少个呗,对不对,那所以说我们可以根据这个集合的哎长度啊,或者集合的大小去判断我们这个参数的个数是否合法,对不对,比如说我要求我这个函数只能传一个参,你传俩就不行,对不对啊,那所以说我们可以根据它来去做一个校验,那OK,那接下来咱们就往下走啊,哎,那所以说咱们这儿可以怎么写这个代码啊。
14:16
那就做if判断呗,来if啊,If什么呢?If all field reference点什么东西是不是size啊,啊,如果这个size。咱们要求转几个参数。没就传一个我们设计过了对吧,如果不等于一,不等于一是不是就不合法啊,不合法我就得怎么做,那不合法我还有必要去解析你这个输入输入进来的东西吗?你传都没按照我的要求传,那我肯定就不给你解析了,所以直接怎么做,直接抛异常啊,抛什么异常这块有是不是有什么udf,就是自定义函数的这个参数异常啊,那我们就抛一个这样的异常,哎,我们直接在throw啊,一个new ctrl v啊,然后这里边来括号啊,这里面咱写什么东西啊,什么东西。
15:02
就提示一下就行了呗,对吧,那我这是什么函数,我是j explode eslode explode,哎,杰森瑞啊杰森,哎瑞啊这个函数呢啊,我只能接收几个参数呢?哎,只能哎接收啊接收啊一个。一个参数。哎,这不就完事了吗?对吧,这就是做了一个校验了啊OK啊行,那做完这个参数个数的校验之后,那咱们还得校验啥呀,是不是还得校验这个参数的类型啊对不对,校验类型,那类型咱们怎么获取类型呢?啊怎么获取类型。啊,咱们都知道have当中类型,它给它封装到什么里边呢?是不是封装到一个对象检查器里边了呀,对不对,封装对象检查器里边了,那所以说我们现在应该怎么办呀,是不是应该拿到我们这个结构体里边每一个字段的对象检查器,是不是才能拿到每个字段的类型啊。对不对,那所以咱们看能不能拿到啊,OK,那怎么拿呢。
16:04
现在我们已经明确了,这个集合它的长度是不是只能是一,因为我们只穿一个参数,那所以说我现在需要拿到第一个元素,对吧?拿到第一个元素我们怎么做是不是凹。Field reference,然后咱们点什么,是不是get呀,Get谁get几。零看零看零是不是就拿到第一个字段了,那我看它返回值是啊CTRL的V,那你返回值就是一个结构体当中的一个字段,这个字段我们是我们想要的嘛,我们得要结构体是不是才能拿到类型啊,那个不是结构体,就是你得拿那个检查器啊,检查器啊,检查器,检查检查器才能拿到类型,那检查器怎么拿呢?那咱们再点一下啊,点一下,那点一下之后呢,你会发现这里边有一个get field object inpe,是不是获取字段的对象检查器对不对,咱们拿过来,拿来之后呢,我们就得到这个所谓的检查器了啊得到检查器了,那得到检查器之后呢,那怎么获取它的类型呢?这里边有一个方法叫做点get t name,哎,这就是获取它的这个。
17:06
类型名称啊,这样的一个方法,那CTRL的V,你会得到它这个类型的名称,这个类型的名称。OK,那这个类型的名称,你说它返回的值应该是什么呢?返回的是不是就是你这个have当中的那个类型啊,对不对,咱们have当中类型都有什么类型,基础类型和复杂类型,基础类型就是string in等等等等,复杂类型的什么ru的,然后a map是不是这些东西啊,对不对?哎,那咱们这返回的应该是什么才对呀?应该什么才对,我们设计的时候,咱们要求了,我们这儿,呃,要求这个函数呢,它得返回的是。呃,不是返回啊,是输入啊,输入咱们叫输入啊是什么是数组字符串。对不对,所以是字符串,那也就这应该是死string才对,那所以咱是不是就可以做一个胶样子,If if什么呢?If type name啊,当然不能这么写啊,咱们这样写啊,来比如说点啊string,点是不是equals啊equals啊来把这个放进来。
18:08
CTRL放在这里,Ctrl away。Type of。对吧,一内如果1S,它那一三是不是就是正常的,如果不等于它,不等于它,我是不是应该是抛一常才对,对吧?CTRLC啊,这个抛异常啊,当然这里边呢,我们说这个函数只能接受一个死菌。类型的参数对吧,哎类型的哎这个参数哎是不是就完事了啊,就是这样一个逻辑,但是大家要注意了,你说咱们这个死菌啊,你这么直接就这么写,有没有什么风险。肯定是有风险的啊,你现在相当于是是对字符串进行这个比较啊,对不对,那假如说我这个type name,我返回的,诶不是小写的词缀,我可能是大写的词缀,我也有可能首字母大写对不对,那你说你这个校验是不是就不通过了呀,对不对?那所以说我们必须得明确啊,明确什么,明确have的这个方法,它所返回的这个字符串,它到底是什么,具体是什么格式,是大写,是小写还是首字母大写,这个东西咱是不是得搞清楚啊,或者说呢,甚至返回的都不是一个完整的词,可能就返回了一个str,对不对,那这些东西咱是必须得搞清楚才行。
19:17
啊,那咱们怎么去搞清楚呢?那这时候我们就得看一下啊,我们这个对象检查器,它在构造对象检查器对象的时候是往里边放的,这个typeb内是什么样的,那它返回的是不是就是什么样的了呀,对不对,看看这个怎么构造的啊,这个呢,我们是不需要new的,我们还有当中给我们提供好了构造对象检查器的工厂类啊,比如这个。Primitive object inspector factory啊,Primitive是什么意思啊,是不是就是那个基础的意思啊,这就是基础数据类型的对象杂器,就是包括string,包括int,那咱们现在查的是不是就是string啊,那所以说我们应该用这个工厂类去找它这个构造方法啊,那点进去点去,那点进来之后有这么多的东西啊,那这时我们搜一下,比如就搜谁,就搜咱们这个死针啊,你看能不能搜到啊,搜搜搜。
20:10
哎,走,哎,你看这个位置。啊,看这啊,这个它是不是在构造一个对应压器对不对,然后呢,你看这里边啊,咱们大致看一下这个逻辑就行,你看这是什么,是不是put什么type info factory,然后get prim type info,然后呢,传了一个参数是不是type name啊。传进来的type name是啥?是不是就是小写的string,那它返回的type name是不是也是小写的string啊,对不对,所以得搞清楚啊,你看其他的类型是不是都有自己的对象检查器啊,布尔的tiny in small in in big float double等等等等都是小写的,所以说咱们这呢,已经验证了,我们其实返回就是小写的,那咱这是不是这么写就没有任何问题了呀,啊就跟跟他保持一致就行啊好,那也就是说咱们通过这几行代码呢,就完成了我们这个函数当中的这个参数类型的校验。
21:02
啊,完成了参数类型的校验,第一个是校验的个数,第二个呢,校验的是类型啊类型啊,那当然呢,我们这因为这个函数只有一个参数啊,假设我这个函数有多个参数呢?假设有三个参数。那个数是不是就正常加验就行,那这个类型呢,你得怎么做。你是不是就得变历了呀,对不对,你是不是变历,咱们这三个参数,每个参数不都得校验一下,那个类型能理解吧?啊实际上刚才咱们只有一个就不用变历的啊,这个咱们搞清楚好,那这块完事完了之后呢,那接下来我们往下看啊。再往下呢,我们需要实现这个以泥赖方法的第二一个功能,它的第二个功能呢,就是什么,第二功能就是什么。啊,第二功能是啥。哎,第二个功能就是是不是把咱们这个函数的输出结果类型封装到一个这样的对象检查器里边啊,啊,一个结构体的对象检检查器里边,那这时候咱们是不是就得想办法去构造一个这样的对象检查器,对不对,那怎么构造呢?哎,前面讲了对象压压器我们不用自己用,也不能自已用,哎,Have给我们提供好了对象检压器的构造的工厂类了啊,那我们的类型分为两类,基础数据类型和复杂数据类型啊,那它的这个呃,构造工厂呢,其实也分了两种啊,那我这种基础数据类型的对象传压器,那我使用谁,我就使用刚才咱们看到的这个是不是这个叫做primitive啊,Object inspector factory primeive,就是基础的意思嘛,基础数据类型,那你刚才也看到了int string是不是都在这里边构造的呀,对不对,那我们现在要得到的是一个什么。
22:46
是一个复杂的数据类型吧,那复杂数据类型,那你用这个能得到吗?肯定得不到,那我们用谁呢?用下面这个。哎,Object inspector factory对象检器工厂,然后这里边咱们要获取的是一个什么样呢?是一个结构体对象检查器,对吧?一个结构体,那既然是一个结构体,那我们看看调用的什么方法,你往下翻啊,这是不是有一个get standardru object inspector是不是获取一个标准的结构体对象检察器啊,来调一个这样的方法就行了啊,那调这个方法我需要给它传什么参呢?你可以看CTRLP看一下。
23:27
这个方法呢,我需要传俩参数,你看啊,哪俩参数,一个参数是一个集合,这个集合是什么?是ru field names。啊,那后边一个集合是什么?是一个对象检查器的一个机型吧,一个一个集合吧,对不对,叫做ru field object inspectors,诶那你说这个东西咱们怎么理解呀。怎么理解?啊,首先咱们得明确对象闸器的作用是什么,是不是封装数据类型,对吧,结构体的数据类型,你自己去定义它的类型,你说你需要给他传什么信息。
24:03
啊,去定义一个结构体的类型,你需要传什么信息?第一个信息就是你的列名是什么?那第二信息是什么?是每个列的类型吧,对不对?所以说你在构造这个对应检压器的时候,是不是也是需要这么传的,第一个集合,把你这个结构体当中所有的列名以一个集合的形式传进来,那第二个结合呢?把什么呀,把每个列的类型所对应的对象检查器数给它传进来呀。哎,是不上是这样一个一个逻辑,所以说你就传这俩集合就完事了。啊OK,那这就是咱们这个构造这种对象减压器的这个方法,就这么搞啊好,那也就咱们要得到一个它,那是不是就得准备两个量的集合是吧,那你看上面是不是就有这样的俩集合呀。那一个集合呢,是子质类型集合,一个是对象解答器集合,好那接下来咱们往下走啊,那首先我们看第一个,那咱们这返回的应该是几列呀,咱们是几列呀,咱们是不是输出一列,这一列是什么类型,是字符串类型,这个是不是字符串类型啊,那既然是字符串类型的话,那咱们这明白了,那首先这个名字咱们可以随便起这个列名呢,大家说这个名应该就是什么呀。
25:14
明,将来就是什么。将来就是什么,其实将来就是我们写circle的时候啊,咱们这儿呢,是不是会炸出来一列或者是多列,对不对,就是你炸出来的那个列的列名的默认值,你看咱们这艾之后是不是会给它起一个别名啊,对吧,这个别名不写行不行。可以,这个别名是可以不写的,不写那就是谁,也就是你在代码当中给他加的列名。能理解吧,啊,就是这个意思啊,那当然咱们这儿了,可以给他随便写一个,比如说我叫做item,因为我大的是数组,我返回的每一个字段都是一个元素,那就叫item啊,OK啊,是这样的啊,那完之后呢,接下来看下边,下边我们需要往第二个集合当中去加上一个Java类型的对象压压器,对吧,不是加va是死string类型的,是死string类型的对象压器,对不对?那所以说那咱们这怎么办?是不是需要把这个改一下,它是in的类型的对不对,那我们改成。
26:07
是不是死讯类型就行。哎,那是不是通过这个工厂类获取一个Java类型,呃,这个死string类型的对象压压器,哎,是不是搞定了,哎,那就完事了啊,那这样一来,我们相当于就完成了以尼赖的方法,它的这个这个编写。啊,这个稍微的呃,有点这个陌生,对啊来说可能啊,咱们也没有必要啊,呃,去非得把这个所有的这个have的源码去通读一遍,你这个东西才能会写,没必要,你看咱们是不是也不知道have底层源码是什么,咱们也没看,然后我就直接通过它官网上的一个案例,是不是就能把这个代码也能写出来呀,其实好多的时候咱们到工作之后呢,都是这样的啊,可能我接触一个新东西,我可能并不熟悉,哎,但是它网上呢,是有它相关的这个教程的,那咱们参照它的教程,我们实现自己的功能啊就可以了啊,因为我们没有时间也没有精力去把所有框架的所有源码都看完嘛,对不对啊OK,那这就是我们在这儿呢,所实现的这个以一设的方法啊,全部的内容啊,来把这个录一下。
我来说两句