使用go语言开发hive导出工具
前言
新版 hive 提供了 beeline 工具,可以执行SQL并导出数据,不过操作还是有点复杂的,团队里有些同学不会Linux的基本操作,所以我花了亿点点时间写了个交互式的命令行工具方便使用。
效果
命令行工具,就是这么朴实无华。

探索过程
一开始是打算用 bash 脚本,结果发现根本不会写,beeline 导出数据只能使用输出重定向,shell 脚本里面的重定向老是有问题,一直报错。我直接放弃了。
接着又打算换成 Python 来写,这个倒是很顺利,但主机终端似乎是旧版本的Ubuntu,自带的Python居然是2.7,Python2的语法写得我实在是烦,于是我打算用能编译成二进制的语言在本地写,然后上传到终端上去运行。
这时候想到了 C# ,.Net8 对 AOT 提供了很好的支持,可以当成 C++ 使用,不过我用下来还是有一些小坑,比如 AOT 模式只能在 Linux 下才能编译 Linux 版本的可执行文件,不能像 Go 那样在 Windows 下交叉编译 Linux 版的可执行文件,然后当我费尽周折编译好上传上去执行的时候又报错说 glibc 库找不到。
/lib64/libm.so.6: version `GLIBC_2.29' not found
我查了一下似乎是跟系统版本有关,最终还是放弃了,转向使用 go 开发。
环境配置
我的电脑里已经有 go 的环境,不过为了文章的完整性,还是记录(水)一下
在 Windows 上推荐使用 scoop 来管理软件
只要一行命令就可以安装 go
scoop install go
因为众所周知的原因,国内网络的特殊性,需要配置一下 go proxy
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
搞定,接下来安装个 goland 或者 vscode 就可以开始愉快的写代码了。
使用 beeline
使用 beeline 导出 hive 的查询结果,命令如下
beeline -u jdbc:hive2://host:port -n username -p password --incremental=true --verbose=false --fastConnect=true --silent=true --outputformat=csv2 -f ./temp.sql > result.csv
需要先把要执行的SQL保存在一个文件里,然后通过 -f 参数指定,查询结果会出现在标准输出,这时候重定向到文件里,就完成了查询结果导出。
分析一下
说起来很简单,这个命令行工具就是提示用户输入 SQL 语句,然后保存到一个临时文件里,再执行上述的 beeline 命令,将标准输出保存到一个文件里,就完成了一个导出的流程。
ASCII Logo
在实现正经功能之前,先来个花里胡哨的。
很多命令行工具启动的时候都会显示一个炫酷的 ASCII Logo ,我也要整一个
很多在线工具都提供了生成 ASCII 艺术字的功能,我使用的是这个: https://tools.kalvinbg.cn/txt/ascii
输入文字之后生成 ASCII 字符画,复制下来。我这里用的是 StarBlog ,就当是给我的博客宣传了~
然后需要使用不转义的字符串来保存,大部分语言都有这个功能,go 当然也不例外。
go 使用的是两个反引号,像这样
var str = `hello`
但是很快我发现了问题,ASCII字符画里面也有反引号字符,直接复制进去结果就是报错,除非手动做转义,太麻烦了。
最后我只能先把 ASCII字符画用 base64 编码,然后在程序里解码后打印出来。
记得先 import 这个 encoding/base64 库
const asciiTitle string = "base64"
var titleDec, _ = base64.StdEncoding.DecodeString(asciiTitle)
fmt.Printf("%s\n", titleDec)
这样就搞定了~
这点还是得吐槽一下,我第一次使用是 C# 来写这个工具,C# 使用 @"ASCII字符画" 就用得好好的,不用转来转去。
读取输入
本来是很简单的功能,但不知道为啥实际用起来还是有一些坑的
一开始我用得是fmt.Scanln() 来读取
但有个问题,这个方法是遇到回车(换行)就读取结束,而很多 SQL 语句里都有包含换行,这就麻烦了。要不就只能要求输入的 SQL 语句不能含有换行,要不就只能换一种方式读取输入。
最终当然是换一种方式了,使用 bufio 库来读取流
reader := bufio.NewReader(os.Stdin)
fmt.Println("请输入要执行的SQL语句,以分号结束,之后按回车确认。")
line, err := reader.ReadBytes(';')
line = bytes.TrimRight(line, "\r\n")
sql := string(line)
以分号结束就可以允许 SQL 里包含换行符。
读取环境变量
使用 beeline 命令是需要指定用户名和密码的,这部分不能写在代码里,我打算使用读取环境变量来实现。
但每次设置环境变量再运行太麻烦了,所以掏出了 dotenv 大法,go 的生态不算丰富,但大部分功能都能找到对应的库,这个 dotenv 我用的是 github.com/joho/godotenv 这个库
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file", err.Error())
}
之后在程序的同级目录下创建 .env 文件,将环境变量保存在这个文件里就完事了
CONN_STR=jdbc:hive2://host:port
USERNAME=user
PASSWORD=pwd
OUTPUT_FORMAT=csv2
创建临时目录和文件
网上很多文章都是用 ioutil.TempFile() 这类已经弃用的方法,事实上现在应该用 os 库提供的方法
首先创建临时目录
dir, err := os.MkdirTemp("", "hive-out-")
if err != nil {
fmt.Printf("创建临时目录错误!%v\n", err)
log.Fatal(err)
}
创建临时文件并写入
tempFile, err := os.CreateTemp(dir, "hive.*.sql")
if err != nil {
fmt.Printf("创建临时文件错误!错误:%v\n", err)
log.Fatal(err)
}
defer tempFile.Close()
defer os.Remove(tempFile.Name())
defer os.RemoveAll(dir)
data := []byte(sql)
if _, err := tempFile.Write(data); err != nil {
fmt.Println("写入文件失败!", err.Error())
log.Fatal(err)
}
log.Printf("创建临时文件 %s\n\n", tempFile.Name())
生成 UUID
go 的标准库竟然没有提供 UUID 功能,这也许就是 go 的哲学 Simplicity 吧
这块我使用的是 github.com/google/uuid 这个库,Google 出品应该没毛病。
u1, err := uuid.NewUUID()
if err != nil {
log.Printf("创建UUID失败: %v\n", err)
log.Fatal(err)
}
log.Printf("Session ID: %v\n\n", u1)
不过最后这个 UUID 没有用上。
一开始我是打算用来作为输出的文件名,不过后面觉得还是用日期时间更合适。
日期时间格式化
老生常谈的问题,我直接用 fmt.Sprintf 方法,简单粗暴
t := time.Now()
timeStr := fmt.Sprintf("%04d-%02d-%02d_%02d-%02d-%02d-%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond())
outputPath := fmt.Sprintf("%s.csv", timeStr)
执行命令+输出重定向
Linux 的输出有两种
- stdout
- stderr
对于 hive 的导出结果,我们只需要把 stdout 保存到文件里就行。
go 里面设计得很简单,直接创建个文件,将命令行的 stdout 重定向到文件就行。
outputFile, err := os.Create(outputPath)
if err != nil {
log.Fatalf("创建文件失败: %v\n", err)
}
执行命令并重定向输出
log.Printf("正在执行SQL,请稍等...\n\n")
cmd := exec.Command(
"beeline",
"-u", os.Getenv("CONN_STR"),
"-n", os.Getenv("USERNAME"),
"-p", os.Getenv("PASSWORD"),
"--incremental=true",
"--verbose=true",
"--fastConnect=true",
"--silent=true",
"--outputformat="+os.Getenv("OUTPUT_FORMAT"),
"-f", tempFile.Name(),
)
cmd.Stderr = os.Stderr
cmd.Stdout = outputFile
err = cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
defer outputFile.Close()
log.Printf("导出数据到:%s\n\n", outputPath)
log.Println("搞定!")
stderr 不需要保存到文件里,所以重定向到 stderr 输出就行。
搞定~
小结
好久没写 Go 了,设计得确实很简单,属于是优缺点都很明显的语言。
最直接的就是良好的发布部署体验,.Net8 的 AOT 吹到天上去了但是实测发布 AOT 的体验还是比较一般,而且还挑 Linux 的版本,这也是我选择使用 go 来开发这个工具的直接原因。
缺点里面我感知最强的就是 go 的错误处理机制,err != nil 这个写得好烦啊!虽然可以用 data, _ := xxx() 直接强行隐藏报错,但还是不如 try 来得舒服。
就这样吧,一个很简单的小工具,因为我对 go 不是很熟悉所以花了些时间探索。
参考资料
- https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter01/01.4.html
- https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter06/06.1.html
- https://juejin.cn/post/7000925379145760782
- https://www.cnblogs.com/mayanan/p/15342214.html
- https://www.cnblogs.com/wongbingming/p/13984538.html
- https://colobu.com/2020/12/27/go-with-os-exec
使用go语言开发hive导出工具的更多相关文章
- 功能齐全、效率一流的免费开源数据库导入导出工具(c#开发,支持SQL server、SQLite、ACCESS三种数据库),每月借此处理数据5G以上
软件名:DataPie 功能:支持SQL server.SQLite.ACCESS数据库的导入.导出.存储过程调用,支持EXCEL2007.EXCEL2003.ACCESS2007. CSV文件导入数 ...
- LInux系统的C语言开发工具笔记
常用的C语言开发工具有很多,每个开发工具所支持的库函数和对标准的实现都有差异.对于初学者,选择一款使用广泛.上手容易的开发工具才是王道.在Windows 上很多从事C和C++开发的人员都选择VS作为开 ...
- Android For JNI(一)——JNI的概念以及C语言开发工具dev-c++,编写你的第一个C语言程序,使用C启动JAVA程序
Android For JNI(一)--JNI的概念以及C语言开发工具dev-c++,编写你的第一个C语言程序 当你的Android之旅一步步的深入的时候,你其实会发现,很多东西都必须去和framew ...
- ubuntu - 14.04,安装、配置GO语言开发工具Eclipse!!
在配置Eclipse之前,我们必须保证下面这些都已经安装,并且正常工作了: 一,Go语言:参考文章 http://blog.csdn.net/sunylat/article/details/49859 ...
- Unix下C语言开发工具
在Unix下进行C语言开发有一套工具,主要有: 编译器:cc,gcc,clang SSH登录工具:putty,xshell就不说了,尼玛还有后门 make工具:跟Maven一样是项目构建工具,这个使用 ...
- 求推荐go语言开发工具及go语言应该以哪种目录结构组织代码?
go语言的开发工具推荐? go语言开发普通程序及开发web程序的时候,应该以哪种目录结构组织代码? 求推荐go语言开发工具及go语言应该以哪种目录结构组织代码? >> golang这个答案 ...
- Go 语言开发工具
Go 语言开发工具 LiteIDE LiteIDE是一款开源.跨平台的轻量级Go语言集成开发环境(IDE). 支持的操作系统 Windows x86 (32-bit or 64-bit) Linux ...
- go语言开发工具sublime text3 + gosublime配置
开始go语言开发时,网上google了下go的开发工具,大都推荐 sublime text3+gosublime.但是实际操作中gosublime不能直接安装,需要自己手动安装.将自己的安装过程整理一 ...
- 开发了一个安卓小软件“CSV联系人导入导出工具”,欢迎测试
开发了一个安卓小软件"CSV联系人导入导出工具",欢迎测试.本软件可以帮你快速备份和恢复联系人,不用担心号码遗失,软件操作简单,使用方便. 下载地址: 百度网盘:https://p ...
- C#开发的高性能EXCEL导入、导出工具DataPie(支持MSSQL、ORACLE、ACCESS,附源码下载地址)[转]
转自:http://www.cnblogs.com/yfl8910/archive/2012/05/19/2509194.html 作为财务数据核算人员,面对大量的业务与财务数据,借助于传统的EXCE ...
随机推荐
- CF1580C Train Maintenance题解
我们以 \(\sqrt m\) 为分界点来进行平衡. 设当前在进行第 \(k\) 次操作,询问 \(i\). 对于 \(x_i + y_i \leq \sqrt m\),可以在 \(last_{x_i ...
- 即构SDK12月迭代:新增多项质量回调,互动白板、云录制SDK同步更新
即构SDK12月迭代来啦,本月LiveRoom/AudioRoom SDK新增了端到端延迟质量回调.房间会话ID信息,便于在音视频通话.直播场景中进行时延.通话质量的评测.同时还优化了硬件设备权限变更 ...
- ZEGO即构科技荣获36氪【WISE2020中国新经济之王最具影响力企业】
12月8-10日,36氪重磅新经济峰会WISE2020新经济之王大会将在北京举办.近日,2020新经济之王--中国最具影响力企业榜单陆续发布,全球云通讯服务商即构科技,凭借在企业服务领域硬核出色的技术 ...
- ISP图像处理——紫边Purple Fringing检测
之前写过文章记紫边的形成原因,以下小结改善方法 图像紫边存在数码相机.监控摄像头等数字成像图像,使用设备在逆光.大光圈条件下拍摄图像的高反差区域容易出现紫边,解决图像自编问题有助设备得到完美图像. 紫 ...
- 单行编辑控件不能有多行文本 matlab
单行编辑控件不能有多行文本 matlab 解决方法:双击进入控件,把max参数改2以及以上
- DolphinScheduler3.1.7集成SAP HANA
源码地址:GitHub - apache/dolphinscheduler at 3.1.7-release 个人fork gitee地址:DolphinScheduler:Gitee) 后端代码更改 ...
- zabbix 可计算监控项使用 last() 与 avg() 的区别
使用zabbix的可计算监控项时遇到的问题 在agent异常退出的情况下,使用last()的监控项依然在产出数据! 分析解决 last()函数会跳过空值,取最后一个有效值计算.遍查文档,只有用avg( ...
- 2021-7-12 VUE的生命周期
挂载: beforeCreate created beforeMount mounted:el挂载到实例上时运行 更新: beforeUpdate updated 销毁: beforeDestory ...
- Powe AutoMate:列表操作
大纲 记录对列表的操作 创建列表 向列表中添加元素 添加多个 合并列表 运行结果 反转列表 反转前 反转后 删除列表中的重复项 结果: 减去列表 结果:
- Django跨域问题解决方案: django-cors-headers安装与配置
django-cors-headers安装与配置 官方文档:https://pypi.org/project/django-cors-headers/ 安装 pip install django-co ...