hive详解(函数)

版权声明:转载或者应用请注明出处 https://blog.csdn.net/qq_35180983/article/details/82974314

hive函数分为内置函数和自定义函数。

内置函数:

show functions;     查看函数
desc function;      查看用法

排名函数:(3种)
row_number():没有并列,相同名次按顺序排(同分不同名)
rank():有并列,相同名次空位
dense_rank():有并列,相同名次不空位

班级成绩排名前三的:

create table stu_score(
classId string,
userName string,
score int 
)
row format delimited 
fields terminated by ' '
;

load data local inpath '/usr/local/hivedata/score.dat' into table stu_score;

1、按班级分组,按照学生成绩倒序排列

row_number:
select *,
row_number() over(distribute by classId sort by score desc) rm,
rank() over(distribute by classId sort by score desc) rk,
dense_rank() over(distribute by classId sort by score desc) drk
from stu_score
;

取前三名:

select * from 
(
select *,
row_number() over(distribute by classId sort by score desc) rm,
rank() over(distribute by classId sort by score desc) rk,
dense_rank() over(distribute by classId sort by score desc) drk
from stu_score
) tmp
where tmp.rm < 4
;

select * from 
(
select *,
row_number() over(partition by classId order by score desc) rm,
rank() over(partition by classId order by score desc) rk,
dense_rank() over(partition by classId order by score desc) drk
from stu_score
) tmp
where tmp.rm < 4
;

over:开窗函数
patition只能用order by,不能用sort by

自定义函数:

为什么要有自定义函数:
hive的内部函数无法满足所有的业务需求,hive提供很多模块的自定义功能,比如:serde、自定义函数、输入输出格式等。
UDF:用户自定义函数,user defined function.一对一的输入输出(常用)
UDAF:用户自定义聚合函数。user defined aggregation function.多对一的输入输出。
UDTF:用户自定义表生成函数。user defined table-generate function.一对多的输入输出

编写UDF的方式:
1、继承UDF,重写evaluate(),允许重载。
2、继承genericUDF,重写initlizer()\getdisplay()\evaluate()

使用:
第一种用法:(只对当前session有效)
1.将编写好的UDF的jar包上传到服务器,并添加带hive的class path中
add jar /root/xxx.jar

add jar /root/gp1813Demo-1.0-SNAPSHOT.jar;

2.创建一个自定义的临时函数名

create temporary function myUDF as 'com.zk.xxxx';

3.测试
dual

create table dual (id string);
insert into dual values(' ');

select myUDF('abc') from dual;

4.确定没有调用该函数时可以注销函数(小心)

drop temporary function myudf;

第一种:(创建永久函数)
1、将编写好的 UDF的jar包上传到服务器,并将jar包上传到hdfs上,并添加到hive的class path中

hdfs dfs -put /root/gp1813Demo-1.0-SNAPSHOT.jar /hiveUDF/
add jar /hiveUDF/gp1813Demo-1.0-SNAPSHOT.jar;

2、创建一个自定义的函数名:

create function myUpperCase as 'com.qfedu.bigdata.hiveUDF.firstUDF';

第二种用法:(相当于临时函数)
1、将编写好的UDF的jar包上传到服务器
2、编写脚本
vi ./hive-init

add jar /root/xxx.jar
create temporary function myUDF as 'com.qf.xxxx';

3、启动hive的时候带上初始化脚本文件

hive -i ./hive.init

第三种用法:(临时函数)
1、将编写好的UDF的jar包上传到服务器
2、在hive的安装目录的conf目录下创建一个文件,文件名为.hiverc,
vi $HIVE_HOME/conf/.hiverc

add jar /root/xxx.jar
ls -al
create temporary function myUDF as 'com.qf.xxxx';

3、直接启动:hive

第四种:
编译源码(费劲)
1)将写好的Java文件拷贝到~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/udf/

cd  ~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/udf/
ls -lhgt |head

2)修改
~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java,增加import和RegisterUDF

import com.meilishuo.hive.udf.UDFIp2Long;   //添加import
registerUDF("ip2long", UDFIp2Long.class, false); //添加register

3)在~/install/hive-0.8.1/src下运行ant -Dhadoop.version=1.0.1 package

cd ~/install/hive-0.8.1/src
ant -Dhadoop.version=1.0.1 package

4)替换exec的jar包,新生成的包在/hive-0.8.1/src/build/ql目录下,替换链接

cp hive-exec-0.8.1.jar /hadoop/hive/lib/hive-exec-0.8.1.jar.0628
rm hive-exec-0.8.1.jar
ln -s hive-exec-0.8.1.jar.0628 hive-exec-0.8.1.jar

5)重启进行测试

案例

案例1:生日转换成年龄
输入:string birthday 1986-07-10
输出:int age 32

import com.google.common.base.Strings;
import org.apache.hadoop.hive.ql.exec.UDF;

import java.util.Calendar;

/**
 案例1:生日转换成年龄
 输入:string birthday 1986-07-10
 输出:int age    32
 * 1、截取字符串
 * 2、分别获取年月日
 * 3、获得当前时间
 * 4、age=当前年-生日年
 * 5、判断月份,当前月份小于生日月份,则age-1
 * 6、判断日期,当前日期小于生日日期,则age-1
 */
public class BirthdayToAge extends UDF {
  public int evaluate(String birthday){
    //判断输入参数
    if(Strings.isNullOrEmpty(birthday)){
      return -1;
    }
    //拆分字符串
    String[] birthdays = birthday.split("-");

    //获取生日的年月日
    int birthYear = Integer.parseInt(birthdays[0]);
    int birthMonth = Integer.parseInt(birthdays[1]);
    int birthDays = Integer.parseInt(birthdays[2]);

    //获取当前时间
    Calendar calendar = Calendar.getInstance();
    //获取当前年月日
    int nowYear = calendar.get(Calendar.YEAR);
    int nowMonth = calendar.get(Calendar.MONTH)+1;
    int nowDay = calendar.get(Calendar.DAY_OF_MONTH);

    //计算年龄
    int age = nowYear - birthYear;
    if (birthMonth>nowMonth){
      age -=1;
    }else if (birthMonth==nowMonth&&birthDays>nowDay){
      age-=1;
    }
    return age;
  }

  public static void main(String[] args) {
    System.out.println(new BirthdayToAge().evaluate("1986-07-26"));
  }
}

案例2:根据key值找出value值
如:sex=1&hight=180&weight=130&sal=28000
select func1(“sex=1&hight=180&weight=130&sal=28000”,“weight”) from dual;
130

json格式:
{sex:1,hight:180,weight:130,sal:28000}

import com.google.common.base.Strings;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * 根据key值找出value值
 * 如:sex=1&hight=180&weight=130&sal=28000
 * select func1("sex=1&hight=180&weight=130&sal=28000","weight") from dual;
 * 130
 */
public class KeyToValue extends UDF {
  public String evaluate(String str,String key) throws JSONException {
    //判断传入参数
    if(Strings.isNullOrEmpty(str)){
      return null;
    }

    //将str转换为json格式
    String s1 = str.replace("&",",");
    String s2 = s1.replace("=",":");
    String s3 = "{"+s2+"}";

    //解析json格式
    JSONObject jsonObject = new JSONObject(s3);

    return jsonObject.get(key).toString();
  }

  public static void main(String[] args) throws JSONException {
    System.out.println(new KeyToValue().evaluate("sex=1&hight=180&weight=130&sal=28000","weight"));
  }
}

案例3:正则表达式解析日志:
解析前:
220.181.108.151 - - [31/Jan/2012:00:02:32 +0800] “GET /home.php?mod=space&uid=158&do=album&view=me&from=space HTTP/1.1” 200 8784 “-” “Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)”

解析后:
220.181.108.151 20120131 120232 GET /home.php?mod=space&uid=158&do=album&view=me&from=space HTTP 200 Mozilla

这里使用正则表达式:
在这里插入图片描述

import com.google.common.base.Strings;
import org.apache.hadoop.hive.ql.exec.UDF;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 正则表达式解析日志:
 * 解析前:
 * 220.181.108.151 - - [31/Jan/2012:00:02:32 +0800] \"GET /home.php?mod=space&uid=158&do=album&view=me&from=space HTTP/1.1\" 200 8784 \"-\" \"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)\"
 *
 * 解析后:
 * 220.181.108.151	20120131 120232	GET	/home.php?mod=space&uid=158&do=album&view=me&from=space	HTTP	200	Mozilla
 */
public class LogParser extends UDF {
  public String evaluate(String log) throws ParseException {

    //判断输入参数
    if(Strings.isNullOrEmpty(log)){
      return null;
    }

    //定义一个正则表达式
    String regx = "^([0-9.]+\\d+) - - \\[(.* \\+\\d+)\\] .+(GET|POST) (.+) (HTTP)\\S+ (\\d+).+\\\"(\\w+).+$";
    //定义一个模式
    Pattern pattern = Pattern.compile(regx);
    //构造匹配器
    Matcher matcher = pattern.matcher(log);

    StringBuffer sb = new StringBuffer();

    //判断是否匹配上
    if (matcher.find()){
      int count = matcher.groupCount();
      //循环匹配上的字段,获取数据
      for (int i = 1; i <= count; i++){
        //判断组的标号是否为2
          if (i == 2) {
            //定义一个当前的日期格式
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss");
            //解析log中的日期格式
            Date d = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z", Locale.ENGLISH).parse(matcher.group(i));
            String sDate = sdf.format(d);
            sb.append(sDate + "\t");
          } else {
            sb.append(matcher.group(i) + "\t");
          }

      }

    }

    return sb.toString();
  }

  public static void main(String[] args) throws ParseException {
    System.out.println(new LogParser().evaluate("220.181.108.151 - - [31/Jan/2012:00:02:32 +0800] \\\"GET /home.php?mod=space&uid=158&do=album&view=me&from=space HTTP/1.1\\\" 200 8784 \\\"-\\\" \\\"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)\\\""));
  }

}

案例4:Json数据解析UDF开发

有原始json数据如下:
{“movie”:“1193”,“rate”:“5”,“timeStamp”:“978300760”,“uid”:“1”}
{“movie”:“661”,“rate”:“3”,“timeStamp”:“978302109”,“uid”:“1”}
{“movie”:“914”,“rate”:“3”,“timeStamp”:“978301968”,“uid”:“1”}
{“movie”:“3408”,“rate”:“4”,“timeStamp”:“978300275”,“uid”:“1”}
{“movie”:“2355”,“rate”:“5”,“timeStamp”:“978824291”,“uid”:“1”}
{“movie”:“1197”,“rate”:“3”,“timeStamp”:“978302268”,“uid”:“1”}
{“movie”:“1287”,“rate”:“5”,“timeStamp”:“978302039”,“uid”:“1”}

最终我要得到一个结果表:
movie rate timestamp uid
1197 3 978302268 1

步骤:
1、创建一个单字段的表来关联原始json数据

create table if not exists t_json(
json string
)
;

load data local inpath '/usr/local/hivedata/rating.json' into table t_json;

2、编写UDF函数,利用自定义函数将json数据解析成\t分割的字符串数据

create temporary function jsonParser as 'com.qfedu.bigdata.hiveUDF.jsonParser';

3、将解析后的结果插入一张临时表(单字段)

create table if not exists t_jsontmp
as
select jsonParser(json) as json from t_json;

4、使用split函数从临时表中解析出字符串中的各个字段插入到最终结果表

create table if not exists t_movierate
as
select split(json,'\t')[0] as movie,split(json,'\t')[1] as rate,split(json,'\t')[2] as ts,split(json,'\t')[3] as uid from t_jsontmp;

内置json函数:(同样可以达到目的)

select get_json_object(json,'$.movie') from t_json limit 10;

猜你喜欢

转载自blog.csdn.net/qq_35180983/article/details/82974314