我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Golang处理parquet文件实战指南

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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 main

import (
  "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 = 10000

func main() {
  var data []*user
  //create fake data
  for 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, size
  pw, err := writer.NewParquetWriter(fw, new(user), int64(len(data)))
  if err != nil {
    return err
  }
  //compression type
  pw.CompressionType = parquet.CompressionCodec_GZIP
  defer 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, size
  pw, err := writer.NewParquetWriter(fw, new(user), int64(len(data)))
  if err != nil {
    return err
  }

  //compression type
  pw.CompressionType = parquet.CompressionCodec_GZIP
  defer 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 float64
  for _, i := range data {
    result += i.(float64)
  }
  return (result / float64(num)), nil
}

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

总结

到此这篇关于Golang处理parquet文件的文章就介绍到这了,更多相关Golang处理parquet文件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Golang处理parquet文件实战指南

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Golang处理parquet文件实战指南

这篇文章主要给大家介绍了关于Golang处理parquet文件的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用Golang具有一定的参考学习价值,需要的朋友可以参考下
2023-03-07

Golang如何处理parquet文件

这篇文章主要介绍“Golang如何处理parquet文件”,在日常操作中,相信很多人在Golang如何处理parquet文件问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang如何处理parquet文件
2023-07-05

Golang编程指南:高效处理文件修改任务

Golang编程指南:高效处理文件修改任务近年来,Golang作为一种快速、高效、并发性能卓越的编程语言,越来越受到开发者们的青睐。在日常开发中经常会遇到需要处理文件修改任务的情况,本文将通过具体代码示例,介绍如何在Golang中高效地处
Golang编程指南:高效处理文件修改任务
2024-02-28

golang函数错误处理实践指南

错误处理实践指南:内置错误类型: 使用内置类型创建自定义错误。error 接口: 使用%w语法包装错误以提供上下文。检查错误: 使用== nil检查错误是否存在。错误守卫: 简化错误处理过程。自定义类型: 创建自定义类型表示错误,提供更多信
golang函数错误处理实践指南
2024-05-04

Golang错误处理方式实战指南:高效解决问题的秘诀

Golang 错误处理方式实战指南:高效解决问题的秘诀在编程中,错误处理是非常重要的一部分,它能够帮助我们优雅地处理异常情况,提高程序的健壮性和可靠性。然而,在 Golang 中,错误处理有着自己独特的方式和技巧。本文将针对 Golang
Golang错误处理方式实战指南:高效解决问题的秘诀
2024-03-13

JavaScript 事件处理实战指南,一步步带你成为高手

JavaScript 事件处理是网页开发的基础,掌握它可以让我们轻松实现各种交互效果。本文将详细介绍 。
JavaScript 事件处理实战指南,一步步带你成为高手
2024-02-22

Golang编程指南:文件编码修改实践

在 go 中修改文件编码可解决跨平台文本兼容性问题。步骤如下:读取文件:使用 ioutil.readfile() 读取文件内容。修改编码:使用 utf8.decodereader() 修改文件编码,可指定 utf-8 或其他编码。写入文件:
Golang编程指南:文件编码修改实践
2024-04-03

Go语言中文件处理入门指南

go 语言文件处理入门指南本文指南介绍了 go 语言中文件处理的基本概念和技术,包括:文件创建:使用 os.create 函数创建新文件。文件读取:使用 os.open 函数打开文件,并使用 ioutil.readall 读取其内容。实战案
Go语言中文件处理入门指南
2024-04-08

PHP 异常处理实战指南:轻松处理各种异常情况!

PHP 异常处理是一项关键技术,可帮助您轻松处理应用程序中的各种异常情况,确保程序的稳定性和健壮性。本文将介绍 PHP 异常处理的基础知识、异常处理的最佳实践,并通过演示代码让您轻松掌握异常处理技巧。
PHP 异常处理实战指南:轻松处理各种异常情况!
2024-02-24

Golang实践指南之获取目录文件列表

在搭建项目中一般都会有确定项目根目录的绝对路径的需求,下面这篇文章主要给大家介绍了关于Golang实践指南之获取目录文件列表的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-01-07

操作系统文件操作实战指南:解决常见问题

操作系统文件操作是编程中必不可少的技能,但经常会遇到各种问题。本文提供一个实战指南,解决常见问题,让您轻松掌握文件操作。
操作系统文件操作实战指南:解决常见问题
2024-02-29

JavaScript Try...Catch 语句实战指南:轻松捕获并处理错误

: JavaScript Try...Catch 语句是一种强大的错误处理机制,可帮助您轻松捕获并处理错误,从而使您的代码更加健壮可靠。本文将详细介绍 Try...Catch 语句的语法、用法以及一些常见的错误处理场景,帮助您掌握这一重要技术。
JavaScript Try...Catch 语句实战指南:轻松捕获并处理错误
2024-02-08

创建有效的文件监控系统:使用Golang实现指南

构建高效的文件监控系统:Golang实现指南随着信息技术的不断发展,文件管理和数据监控成为了现代软件开发中一个不可或缺的环节。在众多的编程语言中,Golang以其高效、并发性强、易于使用等特点,成为了很多开发者钟爱的选择。本文将分享如何利
创建有效的文件监控系统:使用Golang实现指南
2024-02-24

Python 异常处理实战指南,解决常见错误不再是难事

Python 异常处理是编程中必不可少的一环,它可以帮助我们捕获并处理程序运行期间可能发生的错误,避免程序意外终止。本文将介绍 Python 中的异常处理机制,并通过丰富的示例演示如何处理常见的错误,为读者提供一份实用的 Python 异常处理指南。
Python 异常处理实战指南,解决常见错误不再是难事
2024-02-24

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录