当前位置: 首页 > news >正文

Golang 处理parquet文件实战教程

Parquet是Apache基金会支持的项目,是面向列存储二进制文件格式。支持不同类型的压缩方式,广泛用于数据科学和大数据环境,如Hadoop生态。

本文主要介绍Go如何生成和处理parquet文件。

创建结构体

首先创建struct,用于表示要处理的数据:

type user struct {ID        string    `parquet:"name=id, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`FirstName string    `parquet:"name=firstname, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`LastName  string    `parquet:"name=lastname, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Email     string    `parquet:"name=email, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Phone     string    `parquet:"name=phone, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Blog      string    `parquet:"name=blog, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Username  string    `parquet:"name=username, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Score     float64   `parquet:"name=score, type=DOUBLE"`CreatedAt time.Time //wont be saved in the parquet file
}

这里要提醒的是tag,用于说明struct中每个字段在生成parquet过程中如何被处理。

parquet-go包可以处理parquet数据,更多的tag可以参考其官网。

生成parquet文件

下面现给出生成parquet文件的代码,然后分别进行说明:

package mainimport ("fmt""log""time""github.com/bxcodec/faker/v3""github.com/xitongsys/parquet-go-source/local""github.com/xitongsys/parquet-go/parquet""github.com/xitongsys/parquet-go/reader""github.com/xitongsys/parquet-go/writer"
)type user struct {ID        string    `parquet:"name=id, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`FirstName string    `parquet:"name=firstname, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`LastName  string    `parquet:"name=lastname, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Email     string    `parquet:"name=email, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Phone     string    `parquet:"name=phone, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Blog      string    `parquet:"name=blog, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Username  string    `parquet:"name=username, type=BYTE_ARRAY, encoding=PLAIN_DICTIONARY"`Score     float64   `parquet:"name=score, type=DOUBLE"`CreatedAt time.Time //wont be saved in the parquet file
}const recordNumber = 10000func main() {var data []*user//create fake datafor i := 0; i < recordNumber; i++ {u := &user{ID:        faker.UUIDDigit(),FirstName: faker.FirstName(),LastName:  faker.LastName(),Email:     faker.Email(),Phone:     faker.Phonenumber(),Blog:      faker.URL(),Username:  faker.Username(),Score:     float64(i),CreatedAt: time.Now(),}data = append(data, u)}err := generateParquet(data)if err != nil {log.Fatal(err)}}func generateParquet(data []*user) error {log.Println("generating parquet file")fw, err := local.NewLocalFileWriter("output.parquet")if err != nil {return err}//parameters: writer, type of struct, sizepw, err := writer.NewParquetWriter(fw, new(user), int64(len(data)))if err != nil {return err}//compression typepw.CompressionType = parquet.CompressionCodec_GZIPdefer fw.Close()for _, d := range data {if err = pw.Write(d); err != nil {return err}}if err = pw.WriteStop(); err != nil {return err}return nil
}

定义结构体上面已经说明,但需要提醒的是类型与文档保持一致:

Primitive TypeGo Type
BOOLEANbool
INT32int32
INT64int64
INT96(deprecated)string
FLOATfloat32
DOUBLEfloat64
BYTE_ARRAYstring
FIXED_LEN_BYTE_ARRAYstring

接着就是使用faker包生成模拟数据。然后调用err := generateParquet(data)方法。该方法大概逻辑为:

  • 首先准备输出文件,然后基于本地输出文件构造pw,用于写parquet数据:
  fw, err := local.NewLocalFileWriter("output.parquet")if err != nil {return err}//parameters: writer, type of struct, sizepw, err := writer.NewParquetWriter(fw, new(user), int64(len(data)))if err != nil {return err}//compression typepw.CompressionType = parquet.CompressionCodec_GZIPdefer fw.Close()

然后设置压缩类型,并通过defer操作确保关闭文件。下面开始写数据:

  for _, d := range data {if err = pw.Write(d); err != nil {return err}}if err = pw.WriteStop(); err != nil {return err}return nil

循环写数据,最后调用pw.WriteStop()停止写。 成功写文件后,下面介绍如何读取parquet文件。

读取parquet文件

首先介绍如何一次性读取文件,主要用于读取较小的文件:

func readParquet() ([]*user, error) {fr, err := local.NewLocalFileReader("output.parquet")if err != nil {return nil, err}pr, err := reader.NewParquetReader(fr, new(user), recordNumber)if err != nil {return nil, err}u := make([]*user, recordNumber)if err = pr.Read(&u); err != nil {return nil, err}pr.ReadStop()fr.Close()return u, nil
}

大概流程如下:首先定义本地文件,然后构造pr用于读取parquet文件:

  fr, err := local.NewLocalFileReader("output.parquet")if err != nil {return nil, err}pr, err := reader.NewParquetReader(fr, new(user), recordNumber)if err != nil {return nil, err}

然后定义目标内容容器u,一次性读取数据:

  u := make([]*user, recordNumber)if err = pr.Read(&u); err != nil {return nil, err}pr.ReadStop()fr.Close()

但一次性大量记录加载至内存可能有问题。这是官方文档提示:

If the parquet file is very big (even the size of parquet file is small, the uncompressed size may be very large), please don’t read all rows at one time, which may induce the OOM. You can read a small portion of the data at a time like a stream-oriented file.

大意是不要一次读取文件至内存,可能造成OOM。实际应用中应该分页读取,下面通过代码进行说明:


func readPartialParquet(pageSize, page int) ([]*user, error) {fr, err := local.NewLocalFileReader("output.parquet")if err != nil {return nil, err}defer func() {_ = fr.Close()}()pr, err := reader.NewParquetReader(fr, new(user), int64(pageSize))if err != nil {return nil, err}defer pr.ReadStop()//num := pr.GetNumRows()pr.SkipRows(int64(pageSize * page))u := make([]*user, pageSize)if err = pr.Read(&u); err != nil {return nil, err}return u, nil
}

与上面函数差异不大,首先函数包括两个参数,用于指定页大小和页数,关键代码是跳过一定记录:

  pr.SkipRows(int64(pageSize * page))

根据这个方法可以获得总行数,pr.GetNumRows(),然后结合页大小计算总页数,最后循环可以实现分页查询。

计算列平均值

既然使用了Parquet列存储格式,下面演示下如何计算Score列的平均值。

func calcScoreAVG() (float64, error) {fr, err := local.NewLocalFileReader("output.parquet")if err != nil {return 0.0, err}pr, err := reader.NewParquetColumnReader(fr, recordNumber)if err != nil {return 0.0, err}num := int(pr.GetNumRows())data, _, _, err := pr.ReadColumnByPath("parquet_go_root\u0001score", num)if err != nil {return 0.0, err}var result float64for _, i := range data {result += i.(float64)}return (result / float64(num)), nil
}

首先打开文件,然后调用pr.GetNumRows()方法获取总行数。然后基于路径指定列,其中parquet_go_root为根路径,因为前面使用字节数组,这里分割符变为\u0001,完整路径为:parquet_go_root\u0001score

相关文章:

Golang 处理parquet文件实战教程

Parquet是Apache基金会支持的项目&#xff0c;是面向列存储二进制文件格式。支持不同类型的压缩方式&#xff0c;广泛用于数据科学和大数据环境&#xff0c;如Hadoop生态。 本文主要介绍Go如何生成和处理parquet文件。 创建结构体 首先创建struct&#xff0c;用于表示要处理…...

腾讯TIM实现即时通信 v3+ts实践

目录 初始化sdk 功能描述 初始化 准备 SDKAppID 调用初始化接口 监听事件 发送消息 创建消息 创建文本消息 登录登出 功能描述 登录 登出 销毁 登录设置 获取会话列表 功能描述 获取会话列表 获取全量的会话列表 历史消息 功能描述 拉取消息列表 分页拉取…...

华为OD机试 - 回文字符串(Java JS Python)

题目描述 如果一个字符串正读和反渎都一样(大小写敏感),则称它为一个「回文串」,例如: leVel是一个「回文串」,因为它的正读和反读都是leVel;同理a也是「回文串」art不是一个「回文串」,因为它的反读tra与正读不同Level不是一个「回文串」,因为它的反读leveL与正读不…...

APP测试的7大注意点。

1. 运行 1&#xff09; App安装完成后的试运行&#xff0c;可正常打开软件。 2&#xff09; App打开测试&#xff0c;是否有加载状态进度提示。 3&#xff09; App⻚面间的切换是否流畅&#xff0c;逻辑是否正确。 4&#xff09; 注册 同表单编辑⻚面 用户名密码⻓度 …...

设计模式-第4章(装饰模式)

装饰模式装饰模型装饰模式示例商场收银程序&#xff08;简单工厂策略装饰模式实现&#xff09;装饰模式总结装饰模型 装饰模式&#xff08;Decorator&#xff09;&#xff0c;动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为…...

【算法设计-分治】快速幂与龟速乘

文章目录1. 快速幂2. 龟速乘3. 快速幂取模4. 龟速乘取模5. 快速幂取模优化1. 快速幂 算法原理&#xff1a; 计算 311&#xff1a; 311 (35)2 x 335 (32)2 x 332 3 x 3仅需计算 3 次&#xff0c;而非 11 次 计算 310&#xff1a; 310 (35)235 (32)2 x 332 3 x 3仅需计算…...

基于新一代kaldi项目的语音识别应用实例

本文是由郭理勇在第二届SH语音技术研讨会和第七届Kaldi技术交流会上对新一代kaldi项目在学术及“部署”两个方面报告的内容上的整理。如果有误&#xff0c;欢迎指正。 文字整理丨李泱泽 编辑丨语音小管家 喜报&#xff1a;新一代Kaldi团队三篇论文均被语音顶会ICASSP-2023接…...

【GO】31.grpc 客户端负载均衡源码分析

这篇文章是记录自己查看客户端grpc负载均衡源码的过程&#xff0c;并没有太详细的讲解&#xff0c;参考价值不大&#xff0c;可以直接跳过&#xff0c;主要给自己看的。一.主要接口&#xff1a;Balancer Resolver1.Balancer定义Resolver定义具体位置为1.grpc源码对解析器(resol…...

PTA L1-058 6翻了(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; “666”是一种网络用语&#xff0c;大概是表示某人很厉害、我们很佩服的意思。最近又衍生出另一个数字“9”&#xff0c;意思是“6翻了”&#xff0…...

【Origin科研绘图】如何快速绘制一个折线图 ||【前端特效】爱心篇 之 幸好有你 || 泰坦尼克号——乘客生存与否 预测 || PyCharm使用介绍

🎯作者主页:追光者♂ 🌸个人简介:在读计算机专业硕士研究生、CSDN-人工智能领域新星创作者🏆、2022年CSDN博客之星人工智能领域TOP4🌟、阿里云社区专家博主🏅 【无限进步,一起追光!】 🍎欢迎点赞👍 收藏⭐ 留言📝 🌿本篇,首先是:基于科研绘图工具O…...

一文解读电压放大器(电压放大器原理)

关于电压放大器的科普知识&#xff0c;之前讲过很多&#xff0c;今天为大家汇总一篇文章来详细的讲解电压放大器&#xff0c;希望大家对于电压放大器能有更清晰的认识。电压放大器是什么&#xff1a;电压放大器是一种常用的电子器件&#xff0c;它的主要作用是把输入信号的振幅…...

线上监控诊断神器arthas

目录 什么是arthas 常用命令列表 1、dashboard仪表盘 2、heapdump dumpJAVA堆栈快照 3、jvm 4、thread 5、memory 官方文档 安装使用 1、云安装arthas 2、获取需要监控进程ID 3、运行arthas 4、进入仪表盘 5、其他命令使用查看官方文档 什么是arthas arthas是阿…...

@Import注解的原理

此注解是springboot自动注入的关键注解&#xff0c;所以拿出来单独分析一下。 启动类的run方法跟进去最终找到refresh方法&#xff1b; 这里直接看这个org.springframework.context.support.AbstractApplicationContext#refresh方法即可&#xff0c;它下面有一个方法 invoke…...

平台总线开发(id和设备树匹配)

目录 一、ID匹配之框架代码 二、ID匹配之led驱动​​​​​​​ 三、设备树匹配 四、设备树匹配之led驱动 五、一个编写驱动用的宏 一、ID匹配之框架代码 id匹配&#xff08;可想象成八字匹配&#xff09;&#xff1a;一个驱动可以对应多个设备 ------优先级次低 注意事项…...

TS泛型,原来就这?

一、泛型是什么&#xff1f;有什么作用&#xff1f; 当我们定义一个变量不确定类型的时候有两种解决方式&#xff1a; 使用any 使用any定义时存在的问题&#xff1a;虽然知道传入值的类型但是无法获取函数返回值的类型&#xff1b;另外也失去了ts类型保护的优势 使用泛型 泛型…...

关于算法学习和刷题的建议

大家好&#xff0c;我是方圆。最近花时间学了学算法&#xff0c;应该算是我接触Java以来第一次真正的学习它&#xff0c;这篇帖子我会说一些我对算法学习的理解&#xff0c;当然这仅仅是浅浅的入算法的门&#xff0c;如果想深挖或者是有基础的人想提升自己&#xff0c;我觉得这…...

2023年“网络安全”赛项浙江省金华市选拔赛 任务书

2023年“网络安全”赛项浙江省金华市选拔赛 任务书 任务书 一、竞赛时间 共计3小时。 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段单兵模式系统渗透测试 任务一 Windows操作系统渗透测试 任务二 Linux操作系统渗透测试 任务三 网页渗透 任务四 Linux系统…...

http协议简介

http 1.简介 超文本传输协议&#xff08;HTTP&#xff0c;HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处…...

CSDN 第三十一期竞赛题解

第二次参加 总分77.5&#xff0c;主要是在最后一题数据有误&#xff0c;花费了巨量时间… 参加的另一次比赛最后一道题目也出现了一点问题&#xff0c;有点遗憾。 题解 T1&#xff1a;最优利润值 你在读的经营课程上&#xff0c;老师布置了一道作业。在一家公司的日常运营中&…...

EM_ASM系列宏定义(emscripten)

2.5 EM_ASM系列宏很多编译器支持在C/C代码直接嵌入汇编代码&#xff0c;Emscripten采用类似的方式&#xff0c;提供了一组以“EM_ASM”为前缀的宏&#xff0c;用于以内联的方式在C/C代码中直接嵌入JavaScript代码。2.5.1 EM_ASMEM_ASM使用很简单&#xff0c;只需要将欲执行的Ja…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...