1、前言
在hive的开发交互中,有时需要获取hive表数据在hdfs中的location位置、或者获取hive的文件存储格式、使用的压缩算法,甚至是表中的字段类型、字段注释、字段约束、表中是否有数据、数据大小、文件数等信息。这些信息hive没有提供统一的入口,即使直连hive元数据存储的mysql数据库,也很难一次性拿到这些数据。
但是hive提供的desc命令则可以一次性获取所有的这些信息,例如:
desc formatted tableName
(注:我这里用的是2.3.9版本,加不了约束,所以详细信息里面看不到约束)
不过,虽然desc可以一次性获取所有的这些信息,但是这些信息并不是封装好的,需要通过resultSet一行行读取。以前为了获取hive表存储地址,我解析过一次,但那个不够通用。所以这次准备封装一个通用的解析,避免自己重复造轮子。
2、解析代码
public static Map<String, Object> getTableInfo(ResultSet resultSet) throws Exception {
Map<String, Object> result = new HashMap<>();
// 定义多个集合用于存储hive不同模块的元数据
Map<String, String> detailTableInfo = new HashMap<>();
Map<String, String> tableParams = new HashMap<>();
Map<String, String> storageInfo = new HashMap<>();
Map<String, String> storageDescParams = new HashMap<>();
Map<String, Map<String, String>> constraints = new HashMap<>();
List<Map<String, String>> columns = new ArrayList<>();
List<Map<String, String>> partitions = new ArrayList<>();
Map<String, String> moduleMap = getDescTableModule();
// 解析resultSet获得原始的分块数据
String infoModule = "";
while (resultSet.next()) {
String title = resultSet.getString(1).trim();
if (("".equals(title) && resultSet.getString(2) == null) || "# Constraints".equals(title)) continue;
if (moduleMap.containsKey(title)) {
if ("partition_info".equals(infoModule) && "col_name".equals(moduleMap.get(title))) continue;
;
infoModule = moduleMap.get(title);
continue;
}
String key = null;
String value = null;
switch (infoModule) {
case "col_name":
Map<String, String> map = new HashMap<>();
int colNum = resultSet.getMetaData().getColumnCount();
for (int col = 0; col < colNum; col++) {
String columnName = resultSet.getMetaData().getColumnName(col + 1);
String columnValue = resultSet.getString(columnName);
map.put(columnName, columnValue);
}
columns.add(map);
break;
case "table_info":
key = resultSet.getString(1).trim().replace(":", "");
value = resultSet.getString(2).trim();
detailTableInfo.put(key, value);
break;
case "table_param":
key = resultSet.getString(2).trim().replace(":", "");
value = resultSet.getString(3).trim();
tableParams.put(key, value);
break;
case "storage_info":
key = resultSet.getString(1).trim().replace(":", "");
value = resultSet.getString(2).trim();
storageInfo.put(key, value);
break;
case "storage_desc":
key = resultSet.getString(2).trim().replace(":", "");
value = resultSet.getString(3).trim();
storageDescParams.put(key, value);
break;
case "not_null_constraint":
Map<String, String> notNullMap = constraints.getOrDefault("notnull", new HashMap<>());
if ("Table:".equals(title.trim())) resultSet.next();
String notNullConstraintName = resultSet.getString(2).trim();
resultSet.next();
key = resultSet.getString(2).trim();
notNullMap.put(key, notNullConstraintName);
constraints.put("notnull", notNullMap);
break;
case "default_constraint":
Map<String, String> defaultMap = constraints.getOrDefault("default", new HashMap<>());
if ("Table:".equals(title.trim())) resultSet.next();
String defaultConstraintName = resultSet.getString(2).trim();
resultSet.next();
key = resultSet.getString(1).trim().split(":")[1];
value = resultSet.getString(2).trim();
int valueIndex = value.indexOf(":");
value = value.substring(valueIndex + 1);
defaultMap.put(key + "_constraintName", defaultConstraintName);
constraints.put("default", defaultMap);
break;
case "partition_info":
Map<String, String> partitionMap = new HashMap<>();
int partitionColNum = resultSet.getMetaData().getColumnCount();
for (int col = 0; col < partitionColNum; col++) {
String columnName = resultSet.getMetaData().getColumnName(col + 1);
String columnValue = resultSet.getString(columnName);
partitionMap.put(columnName, columnValue);
}
partitions.add(partitionMap);
break;
default:
System.out.print("unknown module,please update method to support it : " + infoModule);
}
}
result.put("columns",columns);
result.put("detailTableInfo",detailTableInfo);
result.put("tableParams",tableParams);
result.put("storageInfo",storageInfo);
result.put("storageDescParams",storageDescParams);
result.put("constraints",constraints);
result.put("partitions",partitions);
return result;
}
private static Map<String, String> getDescTableModule() {
Map<String, String> descTableModule = new HashMap<>();
descTableModule.put("# col_name", "col_name");
descTableModule.put("# Detailed Table Information", "table_info");
descTableModule.put("Table Parameters:", "table_param");
descTableModule.put("# Storage Information", "storage_info");
descTableModule.put("Storage Desc Params:", "storage_desc");
descTableModule.put("# Not Null Constraints", "not_null_constraint");
descTableModule.put("# Default Constraints", "default_constraint");
descTableModule.put("# Partition Information", "partition_info");
return descTableModule;
}
上面的代码基本上覆盖了所有常用的数据模块,如果有代码中没解析到的模块,则依据代码逻辑添加对应的模块名称和case模块即可。代码很简单,主要就是解析时要细心。
3、测试
下面是我新建的一个简单测试demo,有兴趣的可以简单看下:
1)引入依赖
<!-- hive-jdbc -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>2.3.9</version>
</dependency>
2)编辑代码
public static void main(String[] args) {
try {
String driverName = "org.apache.hive.jdbc.HiveDriver";
Class.forName(driverName);
Connection conn = DriverManager.getConnection("jdbc:hive2://192.168.71.135:10000/test_db");
String sql = "desc formatted test_table";
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet resultSet = ps.executeQuery();
Map<String,Object> result = getTableInfo(resultSet);
System.out.println(result.size());
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
3)结果显示
可以看到除了约束之外,其它的数据都正常的存入到了对应的集合中。(我测试用的2.3.9版本的约束创建有问题,但是在3.1.0版本中创建约束是正常的)。
4、总结
上面是我根据自己的需求使用进行的代码编辑,其基本包含了全部的表信息。但是也有可能有没考虑周到的地方,比如我一开始没考虑到多个同种约束的问题,在使用中遇到问题了又来重新更新了文章中的代码。所以如果使用中有些地方解析不对,可能需要您根据自己的实际场景再进行改写。
版权归原作者 Interest1_wyt 所有, 如有侵权,请联系我们删除。