[开源]小程序:DW元数据表血缘关系的实现

小程序:DW元数据表血缘关系的实现 - lixiaotaoplus的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/lixiaotaoplus/article/details/52840237

随着数据仓库(DW)接入的表和建立的模型增多,元数据管理就变得越来越重要。元数据表血缘关系,俗称“表与表之间的关系”。良好的元数据管理,可以清晰和明确看出每张表和模型之前的关系。
在没有工具之前,只能依靠手工维护,一旦脚本发生变化,手工维护遗漏或不及时的话,就会造成关系不准确。通过工具,当表数量上百、上千张的时候,通过分析表与表“血缘关系”,就能清楚知道每张表之间的关系,及时定位和溯源问题。
笔者在XXX项目实践中,通过Java和Hive,最终产出一张表与表之间的关系表。现在把思路和代码分享给大家,与大家一起交流。当然,程序也有会很多改进和完善的地方,如有不妥,欢迎指正,谢谢。
本文也提供了解析sql的思路和方法。
实现思路:
获取输入路径;
读取文本文件内容(其中需要把从路径中读取所有文件);
规则解析
“来源表”解析:主要通过表命名规范进行解析
“目标表”解析:主要通过insert into table和insert overwrite table语句解析
将解析文件,输出txt文件;
将文件上传到hdfs文件,加载到HIVE;
HIVE“行转列”处理;
生成“文件目录filepath、来源表source_table、目标表target_table ”三个字段.
主要代码:
<一>、获取输入路径主要代码:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
ArrayList<File> files=getListFiles(D:\\HQL\xx); //获取解析文件路径
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public static ArrayList<File> getListFiles(Object obj) {
File directory = null;
if (obj instanceof File) {
directory = (File) obj;
} else {
directory = new File(obj.toString());
}
ArrayList<File> files = new ArrayList<File>();
if (directory.isFile()) {
files.add(directory);
return files;
} else if (directory.isDirectory()) {
File[] fileArr = directory.listFiles();
for (int i = 0; i < fileArr.length; i++) {
File fileOne = fileArr[i];
files.addAll(getListFiles(fileOne));
}
}
return files;
<二>、读取文本文件内容主要代码
[java] view plain copy 在CODE上查看代码片派生到我的代码片
String filePath =files.get(i).toString(); //获取的单个文件路径
[java] view plain copy 在CODE上查看代码片派生到我的代码片
//读取文本文件内容
public static String readFile(String filePath) throws IOException {
StringBuffer sb = new StringBuffer();
readToBuffer(sb, filePath);
return sb.toString();
}
//将文本文件中的内容读入到buffer中
lic static void readToBuffer(StringBuffer buffer, String filePath) throws IOException {
InputStream is = new FileInputStream(filePath);
String line; // 用来保存每行读取的内容
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
line = reader.readLine(); // 读取第一行
while (line != null) { // 如果 line 为空说明读完了
buffer.append(line); // 将读到的内容添加到 buffer 中
buffer.append("\n"); // 添加换行符
line = reader.readLine(); // 读取下一行
}
reader.close();
is.close();
}
<三>、解析“来源表”主要代码
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public static String hqltoSourceTable(String hql){
//获取hql内容
Map<String,String> map = new HashMap<String,String>();
String pattern = "(<span style="line-height: 23.8px; font-family: 微软雅黑, 宋体, arial;">ods.|dwd.|......</span><span style="line-height: 23.8px; font-family: 微软雅黑, 宋体, arial;">)\w+" ;//此处可以添加表命名规则</span>
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(hql.toLowerCase().replaceAll(" \s+"," "));//转小写,将“空白字符”转空格
while(m.find()) {
map.put(m.group(0), m.group(0));
}
return map.keySet().toString().replaceAll("[\[\] +]", "");
}
<四>、解析“目标表”主要代码
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public static String hqltoTargetTable(String hql){
//获取hql内容
Map<String,String> map = new HashMap<String,String>();

//表:
String pattern = "(insert into table|insert overwrite table)\s+((\w+)\.(\w+)|(\w+))" ;

Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(hql.toLowerCase().replaceAll(" \s+"," "));//转小写,将“空白字符”转空格
while(m.find()) {
map.put(m.group(0).replaceAll("insert into table|insert overwrite table|ods.|dwd.|.....", ""), m.group(0));//此处需要添加库名规则,将库名过滤掉
}
return map.keySet().toString().replaceAll("[\[\] \s+]", "");

五、将解析文件,输出txt文件
[java] view plain copy 在CODE上查看代码片派生到我的代码片
StringBuffer bf =new StringBuffer();
ileUtil fileUtil = new FileUtil();
fileUtil.writerFile(path,"hqlToTable.txt",bf.toString());
System.out.println("succeed! The file path is "+ path + "/hqlToTable.txt");

[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.xx.xx.hql;
import java.io.*;

public class FileUtil {
public String readerFile(String path) throws IOException {
File file = new File(path);
if (!file.exists() || file.isDirectory())
throw new FileNotFoundException();

    byte[] tempbytes = new byte[5120];  
    int length=0;  
    StringBuffer sb = new StringBuffer();  
    @SuppressWarnings("resource")  
    FileInputStream fin = new FileInputStream(path);  

    // 读入多个字节到字节数组中,byteread为一次读入的字节数  
    while ((length=fin.read(tempbytes)) != -1) {  
        sb.append(new String(tempbytes,0,length));  
    }  

    return sb.toString();  
}  

public boolean writerFile(String path, String fileName, String fileContent) throws IOException {  
    try {  
        File file = new File(path);  
        if (!file.isDirectory()) {  
            file.deleteOnExit();  
            file.mkdirs();  
        }  
        String filePath = file + "/" + fileName;  
        file = new File(filePath);  
        if (file.exists() || file.isFile()) {  
            file.delete();  
        }  
        BufferedWriter out  
                = new BufferedWriter(new FileWriter(filePath));  
        out.write(fileContent);  
        out.flush();  
        out.close();  
        return true;  
    } catch (IOException e) {  
        e.printStackTrace();  
        return false;  
    }  
}  

}
六、HIVE“行转列”处理主要代码
[sql] view plain copy 在CODE上查看代码片派生到我的代码片
load data inpath '/tmp/hqlToTable.txt' into table tmp_app_xxxxx_table_rel_a;

insert overwrite table app_xxxxx_table_rel_a partition(dt='${hivevar:today}')
select
source_table
,target_table
,filepath
,from_unixtime(unix_timestamp())
from
(
SELECT distinct
filepath
,trim(new_source_table) as source_table
,trim(new_target_table) as target_table
FROM (
SELECT filepath
,source_table
,target_table
FROM tmp_app_xxxxx_table_rel_a --将解析后的文件数据加载到此表里
WHERE target_table IS NOT NULL
AND target_table <> ''
AND (
filepath NOT LIKE '%create%'
OR filepath NOT LIKE '%bak%'
OR filepath NOT LIKE '%test%'
OR filepath NOT LIKE '%bkt%'
)
) t LATERAL VIEW explode(split(source_table, ',')) adTable AS new_source_table
LATERAL VIEW explode(split(target_table, ',')) adTable AS new_target_table
) t
where trim(source_table) <> trim(target_table)
;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容