JavaWeb结合Hive(一)
实现功能:点击预览数据能获得表内的前十条数据,点击结构信息能获得表结构信息,并且都是在当前页面展示
datasource.js
$(function() {
$(".showTables").click(function() {
var databaseName = "test";
$.ajax({
url : "DataSourceServlet",
type : "post",
data : {
databaseName : databaseName
},
dataType : "json",
success : function(data) {
var content = $(".tableList");
for (index in data) {
var tableName = data[index];
content.append("" + tableName + "");
}
}
})
})
// 对于动态添加的元素绑定事件 - on方式实现需要在jQuery的1.7版本以后,live,bind
// $(父级选择器).on(事件名称,需要绑定事件的元素-即动态添加进来的元素,方法体-触发事件后执行的内容)
// 如果动态添加的元素没有父级元素可以使用document或者body
// 此时$(this)依然代表触发事件的元素
$(document).on("click",".info",function(){
// 通过data("xxx")方法可以获得当前元素通过data-xxx属性定义的值
var tableName = $(this).data("name");
// 通过触发事件元素与需要获取信息的元素之间的层级关系进行查找
// siblings能够获取到同级元素的集合,也可以直接传入选择器作为参数,如siblings(".className"),会返回同级中匹配的元素
//alert($(this).siblings().eq(0).html());
$.ajax({
url : "TableInfoServlet",
type : "post",
data : {
tableName : tableName
},
dataType : "json",
success:function(data){
var content = $(".tableInfo");
// 保证指定区域只显示当前表信息,添加信息前先清空
content.html("");
for(index in data){
content.append("" + data[index] + "")
}
}
})
})
$(document).on("click",".data",function(){
var tableName = $(this).data("name");
$.ajax({
url : "TableDataServlet",
type : "post",
data : {
tableName : tableName
},
dataType : "json",
success:function(data){
var content = $(".tableData");
// 保证指定区域只显示当前表信息,添加信息前先清空
content.html("");
for(index in data){
content.append("" + data[index] + "")
}
}
})
})
})
TableInfoServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sand.util.HiveUtil;
import net.sf.json.JSONArray;
/**
* Servlet implementation class TableInfoServlet
*/
@WebServlet("/TableInfoServlet")
public class TableInfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TableInfoServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String tableName = request.getParameter("tableName");
HiveUtil hiveUtil = new HiveUtil();
hiveUtil.changeDatabase("test");
// 当需要获取表信息时,如果只传入表名称会在当前数据库中搜索该表,需要先切换数据库
// 如果传入库名.表名 -> 在指定的数据库下进行搜索
List list = hiveUtil.getTableInfo(tableName);
out.print(JSONArray.fromObject(list).toString());
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
TableDataServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sand.util.HiveUtil;
import net.sf.json.JSONArray;
/**
* Servlet implementation class TableDataServlet
*/
@WebServlet("/TableDataServlet")
public class TableDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TableDataServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String tableName = request.getParameter("tableName");
HiveUtil hiveUtil = new HiveUtil();
hiveUtil.changeDatabase("test");
// 当需要获取表信息时,如果只传入表名称会在当前数据库中搜索该表,需要先切换数据库
// 如果传入库名.表名 -> 在指定的数据库下进行搜索
List list = hiveUtil.getTableData(tableName);
out.print(JSONArray.fromObject(list).toString());
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
运行效果
load.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
<script type="text/javascript" src="js/jquery-1.7.1.min.js">script>
<script type="text/javascript" src="js/load.js">script>
head>
<body>
<form action="LoadDataServlet" method="post"
enctype="multipart/form-data">
<span>数据表名称:span><input type="text" name="tableName" /><br />
<label><input type="checkbox" name="auto" value="auto" />从首行中读取字段信息label><br />
<label><input type="checkbox" name="overwrite" value="overwrite" />是否覆盖导入label><br />
<span>列分隔符:span><input type="text" name="format" /><br />
<input type="button" value="添加" class="add" />
<div class="columnInfo">div>
<input type="file" name="data" /> <input type="submit" value="上传" />
form>
<div class="column" style="display: none">
<span class="columnNameLabel">列名:span><input type="text" name="columnName" /> <span>数据类型:span>
<select name="columnType">
<option value="int">intoption>
<option value="string">Stringoption>
select> <span class="delete">-span>
div>
body>
html>
load.js
$(function(){
$(".add").click(function(){
var column = $(".column").html();
$(".columnInfo").append("" + column + "
");
})
$(document).on("click",".delete",function(){
$(this).parent().remove();
})
$("input[name='auto']").click(function(){
if($(this).attr("checked") == "checked"){
$(".columnNameLabel").hide();
$("input[name='columnName']").hide();
}else{
$(".columnNameLabel").show();
$("input[name='columnName']").show();
}
})
$("input[type='checkbox']").removeAttr("checked");
})
LoadDataServlet.java
此Servlet功能仅实现了拼接字符串,真正执行的代码待完善
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
* Servlet implementation class LoadDataServlet
*/
@WebServlet("/LoadDataServlet")
@MultipartConfig
public class LoadDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoadDataServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置编码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/plain; charset=UTF-8");
// 接收参数
String tableName = request.getParameter("tableName");
boolean isAuto = request.getParameter("auto") == null ? false : true;
boolean isOverwrite = request.getParameter("overwrite") == null ? false : true;
String format = request.getParameter("format");
if (!isAuto) {
String[] columnNames = request.getParameterValues("columnName");
}
String[] columnTypes = request.getParameterValues("columnType");
for (String columnType : columnTypes) {
System.out.println(columnType);
}
// 使用Part对象接收文件
Part part = request.getPart("data");
// 取出文件名(如果需要)
String path = "/tmp";
// 可以使用自定义的名称,也可以使用UUID
String fileName = UUID.randomUUID().toString();
// 从登陆信息中获取当前用户的唯一标识
String userId = "1";
String filePath = path + File.separator + fileName;
// 使用write方法向路径中写入文件
part.write(filePath);
Reader reader = new FileReader(new File(filePath));
BufferedReader bf = new BufferedReader(reader);
String tableInfo = bf.readLine();
String createTable = "create table " + tableName + "(";
for(int i = 0;i < columnTypes.length;i ++) {
createTable += tableInfo.split(format)[i] + " " + columnTypes[i] + ",";
}
createTable = createTable.substring(0,createTable.length() - 1);
createTable += ") row format delimited fields terminated by '" + format + "' tblproperties(\"skip.header.line.count\"=\"1\")";
bf.close();
reader.close();
System.out.println(createTable);
String loadToHive = "load data local inpath '"+ filePath +"' " + (isOverwrite ? "overwrite " : "") +"into table " + tableName;
System.out.println(loadToHive);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
将项目打包成war文件,并且用Xftp上传至CentOS中apache安装目录下的webapps目录下
su root切换至root用户,执行./startup.sh启动apache服务,启动后会自动解压war包并部署项目
启动后就可以通过浏览器访问http://sz01/WebProject/load.jsp
待完善
内部表和外部表区别:内部表即完全交给hive管理表,在创建时会将数据移动到数据仓库所
在的路径,删除时会删除数据源文件。外部表即增加hive管理的数据文件,创建时需要记录
数据所在的路径,不会移动数据源文件,删除时不会删除数据源文件
创建外部表
创建时需要用location关键字指定数据所在的路径
create table {tableName}(
{columnName} {columnType},
{columnName} {columnType},
…
)[row format delimited fields terminated by ‘\t’]
[location ‘{HDFS_path}’];
如果指定的文件夹下已经有数据文件,则只要结构匹配就可以直接使用
导入数据即将数据导放置在创建表时指定的目录下
删除外部表,只会删除结构,文件将会保留
注:在mysql创建的hive库中有两张数据元表,其中SDS用于记录表结构对应的路径信息,TBLS用于记录表的基本信息(所属的数据库,数据表类型)
函数的执行,通过select关键字进行调用;函数之间可以相互嵌套使用,只需要一个select关键字。
根据函数的作用,传入的参数可以是某个固定的值,也可以指表中某个列的字段名称;
传入单个数据时,返回单个的结果,和表产生关联时,返回的是逐条数据调用后返回的结果。
查看可用函数列表
show functions;
查看函数描述信息
desc function {functionName};
四则运算
select 6+3;
select 6-3;
select 6*3;
select 6/3;
取余运算
select 25%3;
按位运算
与:select 6&9; 0110&1001=0000
或:select 6|9; 0110|1001=1111
异或:select 6^9; 0110^1001=1111
取反:select ~4;
如果结果为真,则返回TRUE,否则返回FALSE
逻辑与(AND)、逻辑或(OR)、逻辑非(NOT)
取整函数
向下取整函数
select floor (5.9);
向上取整函数
select ceil/ceiling (6.1);
生成随机数
rand ([{seed}]):返回一个0到1范围内的随机数,传入参数时可生成稳定的随机数
select rand;
自然指数函数
自然指数e的n次方:exp ({n})
对数函数
幂函数
pow/power ({base},{exponent})
平方根函数
sqrt ({value})
立方根函数
cbrt ({value})
进制函数
绝对值函数
abs ({value})
获取日期函数
unix_timestamp()
时间戳转换函数,在进行日期转换时,可以自定义日期格式
UNIX时间戳转日期:from_unixtime ({unixTime}[,{formatString}])
日期转UNIX时间戳:unix_timestamp ({timeString}[,{formatString}])
日期截取函数,使用日期截取函数时,必须针对字符串日期操作
日期计算函数
字符串长度函数
length ({stringValue})
字符串翻转函数
reverse ({stringValue})
字符串连接函数
字符串截取函数
substr/substring ({stringValue},{index}):当index为正数时,截取从index至结尾的字符串,当index为负数时,截取后index个字符,index的值不能超过字符串长度
substr/substring ({stringValue},{index},{length}):截取从index开始,长度为length的字符,index为正数时,索引从左边开始,index为负数时,索引从右边开始
大小写转换函数
去空格函数
正则表达式函数
正则替换函数:regexp_replace ({stringValue},{regexpString},{replaceValue})
正则解析函数:regexp_extract ({stringValue},{regexpString},{index})
URL解析函数(重要)
parse_url ({stringValue},’{extractPart}’)[,’{extractKey}’])
HOST:获取主机名(域名)
PATH:获取访问路径
QUERY:参数解析,需要配合extractKey一起使用
REF:获取锚点信息
PROTOCOL:获取网络协议
FILE:获取路径及参数信息
select parse_url (‘https://www.baidu.com/s?keyword=111‘,’HOST’);
select parse_url (‘https://www.baidu.com/s?keyword=111‘,’QUERY’,’keyword’);
JSON解析函数(重要)
json解析地址
get_json_object({jsonString},’$.{jsonObjectKey}’)
select get_json_object(‘{“name”:”cry”,”age”:20}’,’$.name’);
字符串生成函数
首字符ASCII码函数
ascii ({stringValue})
字符串补足函数
将原字符串用指定的追加字符串补足为指定长度的字符串
字符串分割函数
split ({stringValue},{splitValue})
在Eclipse中新建普通java项目
新建文件夹lib,将hive-exec.1.2.2.jar(jar包在hive安装包的lib目录下)复制到lib中,并且添加至构建路径
由于编写了一个自定义解析JSON对象类,所以需要将json依赖的两个jar包导入到hive安装路径的lib目录中
ezmorph-1.0.6.jar
json-lib-2.2.2-jdk15.jar
获取子字符串类SubString.java,需要继承UDF类,并且需要创建方法evaluate,可以自定义返回值类型和参数列表,但是方法名必须是evaluate
import org.apache.hadoop.hive.ql.exec.UDF;
public class SubString extends UDF{
public String evaluate(String str, int start, int end) {
return str.substring(start, end);
}
}
自定义解析JSON对象类JsonParse.java
import org.apache.hadoop.hive.ql.exec.UDF;
import net.sf.json.JSONObject;
public class JsonParse extends UDF{
public static String evaluate(String jsonStr, String key) {
return JSONObject.fromObject(jsonStr).get(key).toString();
}
}
右键项目选择导出,类型为jar file,只需要打包src目录下的内容即可,命名udf.jar
使用Xftp将udf.jar上传至CentOS
注意:自定义函数加载仅对当前会话有效
启动hive客户端
加载jar包,将当前jar包添加至构建路径(类的搜索加载路径)中
add jar /home/bigdata/udf.jar
创建函数
create temporary function sub as ‘com.cry.udf.SubString’;
create temporary function jsonParse as ‘com.cry.udf.JsonParse’;
可以通过以下命令查看函数是否创建成功
show functions;
根据定义的函数名使用select执行,并传入正确的参数
select sub(‘abcdefg’,0,7);
select sub(‘abcdefg’,1,6);
select jsonParse(‘{\”name\”:\”cry\”,\”age\”:20}’,’name’);
删除函数
drop temporary function {functionName};
配置文件加载
在hive-site.xml中配置指定目录,可以省略导入jar包操作,需要将jar包放在指定目录下
<property>
<name>hive.aux.jars.pathname>
<value>$HIVE_HOME/auxlibvalue>
property>
初始化文件加载
启动hive时指定初始化文件,在文件中添加jar包,创建函数
vi init-hive
add jar /home/bigdata/udf.jar;
create temporary function sub as 'com.cry.udf.SubString';
create temporary function jsonParse as 'com.cry.udf.JsonParse';
JDBC操作Hive时可以在初始化工具类时加上初始化方法,即可自动加载jar包,创建函数
public void init() {
try {
statement.execute("add jar /home/bigdata/udf.jar");
statement.execute("create temporary function sub as 'com.sand.udf.SubString'");
statement.execute("create temporary function jsonParse as 'com.sand.udf.JsonParse'");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
将以上函数添加至构造函数中
public HiveUtil() {
open();
init();
}