生产中Hive的元数据存储在MySQL中,构建数据字典我们可以通过查询元数据表,导出查询结果后生成自己想要的文档。
下面我会一步一步介绍如何生成markdown格式的数据字典文档。
定义SQL
首先废话不多说,贴出我们需要的在MySQL中使用的SQL。
SELECT
a. NAME as SCHEMA_NAME,-- 数据库名称
t.TBL_NAME as TABLE_NAME,-- 表名
b.PARAM_VALUE as TABLE_COMMENT,-- 表注释
e.INTEGER_IDX as COLUMN_ID,-- 字段序号
e.COLUMN_NAME ,-- 字段名
e.TYPE_NAME as COLUMN_DATA_TYPE,-- 字段类型
f.PART_KEYS as PART_COLUMN,-- 分区字段
e.COMMENT-- 字段注释
FROM
TBLS t
JOIN DBS a ON t.DB_ID = a.DB_ID
LEFT JOIN (select TBL_ID,PARAM_VALUE FROM TABLE_PARAMS where PARAM_KEY='comment') b ON t.TBL_ID = b.TBL_ID
LEFT JOIN SDS c ON t.SD_ID = c.SD_ID
LEFT JOIN CDS d ON c.CD_ID = d.CD_ID
LEFT JOIN COLUMNS_V2 e ON d.CD_ID = e.CD_ID
LEFT JOIN (SELECT TBL_ID,GROUP_CONCAT(PKEY_NAME) AS PART_KEYS FROM PARTITION_KEYS GROUP BY TBL_ID) f on t.TBL_ID = f.TBL_ID
// where a. NAME = 'hive库名' 此处选择你需要的库
order by 1,2,4
TBLS
表存储Hive表信息DBS
表存储Hive库信息TABLE_PARAMS
表存储Hive表的一些参数信息COLUMNS_V2
表存储Hive表的字段信息PARTITION_KEYS
表存储表的分区字段
至于这些表为什么这么关联,大家可以使用Navicat的逆向数据库到模型
功能查看。
运行以上SQL可以得到以下结果:
导出结果为JSON
Navicat有个很方便的功能,可以把查询结果导出为JSON。
点击下一步设置好JSON文件路径,再下一步指定编码。
最后点击开始,导出结果JSON。
通过Java代码读取JSON并生成md
打开JSON文件,JSON的格式为:
{
"RECORDS":[
{
"SCHEMA_NAME":"hive_db",
"TABLE_NAME":"hive_table",
"TABLE_COMMENT":"",
"COLUMN_ID":0,
"COLUMN_NAME":"userid",
"COLUMN_DATA_TYPE":"string",
"PART_COLUMN":"log_date",
"COMMENT":null
},//内部一个大括号中的内容是Hive表的一列
...,
...
]
}
我们需要定义两个对象来接收这个JSON文件数据
public class Record {
private List<Column> records;
public Record() {
}
public Record(List<Column> records) {
this.records = records;
}
public List<Column> getRecords() {
return records;
}
public void setRecords(List<Column> records) {
this.records = records;
}
}
public class Column {
private String schemaName;//库名
private String tableName;//表名
private String tableComment;//表注释
private String columnId;//表的列序号
private String columnName;//表的列名
private String columnDataType;//表的列的数据类型
private String PartColumn;//表的分区字段
private String comment;//表的列注释
@Override
public String toString() {//toString可根据喜好自定义输出字段
return
"|" + columnId +
"|" + columnName +
"|" + columnDataType +
"|" + PartColumn +
"|" + (comment == null?"":comment) +
"|";
}
public String toStringWithNoPart() {
return
"|" + columnId +
"|" + columnName +
"|" + columnDataType +
"|" + (comment == null?"":comment) +
"|";
}
public String getTableComment() {
return tableComment;
}
public void setTableComment(String tableComment) {
this.tableComment = tableComment;
}
public String getSchemaName() {
return schemaName;
}
public void setSchemaName(String schemaName) {
this.schemaName = schemaName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnId() {
return columnId;
}
public void setColumnId(String columnId) {
this.columnId = columnId;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getColumnDataType() {
return columnDataType;
}
public void setColumnDataType(String columnDataType) {
this.columnDataType = columnDataType;
}
public String getPartColumn() {
return PartColumn;
}
public void setPartColumn(String partColumn) {
PartColumn = partColumn;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Column() {
}
public Column(String schemaName, String tableName, String columnId, String columnName, String columnDataType, String partColumn, String comment) {
this.schemaName = schemaName;
this.tableName = tableName;
this.columnId = columnId;
this.columnName = columnName;
this.columnDataType = columnDataType;
PartColumn = partColumn;
this.comment = comment;
}
}
最后就是main方法将JSON文件内容转成Record对象,然后输出其中的Column。注意以下的markdown格式是Typora的语法,不同的markdown工具可能语法有一些差别。
public static void main(String[] args) {
//FileReader来自Hutool工具包,可以在pom中导入,读取navicat生成的json文件
FileReader fileReader = new FileReader("C:\\Users\\ut\\Desktop\\directory.json");
String jsonStr = fileReader.readString();
//JSONObject来自FastJson库,可以在pom中导入
Record record = JSONObject.parseObject(jsonStr, Record.class);
List<Column> columns = record.getRecords();
for (Column column : columns) {//根据不同的样式输出列信息
if("0".equals(column.getColumnId())){//根据列序号是否为0判断循环是否到一个新的表的列
System.out.println("\n| 数据库名称 | 表名 | 字段序号 | 字段名 | 字段类型 | 分区字段 | 备注 |\n" +
"| ---- | ---- | ---- | ---- | ---- | ---- |");
}
System.out.println(column.toString());
}
try {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:\\Users\\Desktop\\directory.md")));//在指定目录输出
for (Column column : columns) {
if("0".equals(column.getColumnId())){
writer.write("## "+column.getSchemaName()+"."+column.getTableName()+"\n");
if(column.getTableComment() != null){
writer.write("**"+column.getTableComment()+"**");
}
if(column.getPartColumn() == null){
writer.write("\n| 字段序号 | 字段名 | 字段类型 | 备注 |\n" +
"| ---- | ---- | ---- | ---- |\n");
}else{
writer.write("\n| 字段序号 | 字段名 | 字段类型 | 分区字段 | 备注 |\n" +
"| ---- | ---- | ---- | ---- | ---- |\n");
}
}
if(column.getPartColumn() == null){
writer.write(column.toStringWithNoPart());
writer.newLine();
}else{
writer.write(column.toString());
writer.newLine();
}
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
运行main方法后,打开生成的markdown文件,渲染后如下:
以上操作就可以生成一个简易的数据字典。