我知道它是2023年,但是您可以摆脱处理文件。在事件,API和插座的世界中,文件仍然存在作为移动数据的媒介。这是一个非常普遍的。近年来,我发现自己正在处理Apache Parquet格式文件。更具体地说,我经常最终与他们打交道AWS S3。如果您在复制时是所有AWS DMS产品的消费者,您会发现Parquet Format是处理您的数据的好方法,因为它旨在有效地存储和检索。与Golang一起解析镶木木文件的选项太多了,但是我找到了一个我真正喜欢的库,下面的文章将描述如何充分利用它。
一如既往,这是指向Github Repository的链接,如果您想跳过
什么是Apache Parquet
Apache Parquet是一种开源,面向列的数据文件格式,旨在有效的数据存储和检索。它提供有效的数据压缩和编码方案,具有增强的性能,以批量处理复杂的数据。 Parquet有多种语言,包括Java,C ++,Python等
下载镶木石文件
对于使用S3,我真的很喜欢Golang库,称为s3manager
。这是SDK documentation。我喜欢它的是,在正常S3库的顶部是更高级别的抽象。例如,要从水桶下载文件,您只需执行此类操作
downloader := s3manager.NewDownloader(sess)
_, err = downloader.DownloadWithContext(ctx, file,
&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
下载器将将文件放入您在文件参数中的下载WithContext方法中指定的路径中。它只是一个字符串。
用golang解析文件
用golang解析Apache Parquet文件似乎将超级家庭与其他界面的Unmarshalling(例如Dyanamodb和Json)进行分析。对于与DDB的相似之处,您可以在引用的article
中查看如何执行此操作。解析功能看起来像这样
func ParseFile(fileName string) ([]ParquetUser, error) {
fr, err := floor.NewFileReader(fileName)
var fileContent []ParquetUser
if err != nil {
return nil, err
}
for fr.Next() {
rec := &ParquetUser{}
if err := fr.Scan(rec); err != nil {
// continue along is it's just a malformed row
if errors.Is(err, ErrIllegalRow) {
continue
}
return nil, err
}
fileContent = append(fileContent, *rec)
}
return fileContent, nil
}
首先,请注意,我从Parquet-go库打开了一个FileReader。
从那里,我创建了一个切片,用于保持未划分的输出。
然后我们循环和扫描。对于每个扫描调用,都调用了实现Parquet-Go接口的Unmarshall方法。这种方法看起来像这样
func (r *ParquetUser) UnmarshalParquet(obj interfaces.UnmarshalObject) error {
id, err := obj.GetField("id").Int32()
if err != nil {
return errors.New(fmt.Sprintf("error unmarshalling row on field (id)"))
}
firstName, err := obj.GetField("firstName").ByteArray()
if err != nil {
return errors.New(fmt.Sprintf("error unmarshalling row on field (firstName)"))
}
lastName, err := obj.GetField("lastName").ByteArray()
if err != nil {
return errors.New(fmt.Sprintf("error unmarshalling row on field (lastName)"))
}
role, err := obj.GetField("role").ByteArray()
if err != nil {
return errors.New(fmt.Sprintf("error unmarshalling row on field (role)"))
}
// note this is a time.Time but comes across as an Int64
lastUpdated, err := obj.GetField("lastUpdated").Int64()
if err != nil {
return errors.New(fmt.Sprintf("error unmarshalling row on field (lastUpdated)"))
}
parsed := time.UnixMicro(lastUpdated)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Error("error parsing time")
return errors.New(fmt.Sprintf("(lastUpdated) is not in the right format"))
}
r.Id = int(id)
r.FirstName = string(firstName)
r.LastName = string(lastName)
r.Role = string(role)
r.LastUpdated = parsed
return nil
}
实际上并没有太多在获取字段之外的地方,然后将它们放入结构字段。要指出的一件主要的事情是,一个陷入困境的是,最后一个的字段是time.Time
。镶木库将时间视为Int64
。请注意此行将从图书馆转换为time.Time
parsed := time.UnixMicro(lastUpdated)
运行程序
从那里开始,这只是将所有内容放在一起的问题。这里是main
func main() {
file, err := DownloadFile(context.TODO(), sess, bucket, key)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Error("error downloading the file")
}
contents, err := ParseFile(file)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Error("error parsing the file")
}
err = DeleteFile(file)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Error("error deleting the file")
}
for _, c := range contents {
log.WithFields(log.Fields{
"record": c,
}).Debug("printing the record")
}
}
简而言之
- 下载文件
- 解析文件
- 删除文件
- 循环和打印输出
有用的提示
- 如今,我更多地使用了Vscode,我有点像Goland那样断奶。因此,您将在
.vscode
目录中找到一个launch.json
文件。在那里您可以设置运行程序所需的环境变量 - 查看镶木木文件确实是我发现的痛苦。我喜欢的工具很少。在线观众会阻碍我的工作流程。但是我发现这个Vscode插件很棒。 Here is the link to the marketplace
包起来
希望您发现这很有帮助。就像我一开始提到的那样,文件作为数据介质而消失。当您处理较大的数据集时,Apache的镶木材料是一个很好的选择,这是您可以选择以DMS为输出的选项之一。
我继续只喜欢Golang的简单性和表现以及发展经验。 Parquet-go库有几个怪癖,但总的来说,我的5星级评级。