
Parquet is a columnar storage format that's highly efficient and scalable, making it a great choice for big data processing.
To get started with Parquet in Golang, you'll first need to install the go-parquet library, which can be done using the command `go get github.com/segmentio/parquet-go`.
Parquet is designed to handle large datasets with ease, thanks to its ability to store data in a compressed and columnar format.
The go-parquet library is a Go implementation of the Parquet format, and it provides a simple and efficient way to read and write Parquet files in Golang.
See what others are reading: Golang Go
Installation
To install the parquet golang package, you'll need Go 1.22 or later. This is a requirement for using the package.
You can download the library via a standard Go module. This is a straightforward process.
The package can be installed with a single command. Just take a dependency on the package and install it.
Two cli utilities are provided for convenience.
If this caught your attention, see: Create a Package in Golang
Usage
The parquet file format is optimized for faster scan operations on subsets of the data set, making it a great choice for big data applications.
A parquet file is a collection of rows sharing the same schema, which allows for efficient storage and retrieval of data.
The parquet.WriteFile[T] function is a simple way to create parquet files on the file system, and it's perfect for small to medium-sized data sets.
To use parquet.WriteFile[T], you'll need to pass in a slice of Go values representing the rows to write to the file.
This function is great for simple use cases, but for more complex scenarios, you may need to look into other functions in the library.
Parquet files are arranged in columns, which makes it easy to scan subsets of the data set and retrieve only the information you need.
By using parquet files, you can significantly speed up your data processing and analysis workflows.
Recommended read: Golang Use Cases
Reading and Writing
Reading and writing parquet files in Go is a breeze with the right tools. The parquet-go package offers a ParquetFile interface that can read and write parquet files on various platforms.
To write parquet files, you can use two main mechanisms: writing columns of typed arrays or using the generic buffer model. Writing columns of typed arrays is more efficient and requires less boxing, but the generic buffer model can be more expressive depending on the situation.
To avoid writing a malformed parquet file, make sure to write the same number of rows to each column. This can be done by using the specialized write methods that accept arrays of Go primitive types.
Take a look at this: Golang Os Write File
Reading Arrays
Reading Arrays is a fundamental concept in programming that allows us to access and manipulate collections of data.
Arrays are similar to lists, but they are more flexible and efficient, especially when working with large datasets.
To read an array, we need to specify the index of the value we want to access. The index is like a label that tells the computer which value we want to retrieve.

For example, if we have an array called "fruits" with the values "apple", "banana", and "cherry", we can access the first value by specifying the index 0.
Arrays are zero-indexed, which means the first value is at index 0, not 1. This can take some getting used to, but it's an important concept to grasp when working with arrays.
Writing Arrays
Writing arrays can be a bit tricky, but don't worry, I've got you covered. The package offers two main mechanisms to write columns of values directly instead of reconstructing rows from the column values.
You can use parquet.GenericBuffer[T] to maintain in-memory buffers of column values. This implementation of the parquet.RowGroup interface is a great tool to have in your toolbox.
If you're working with in-memory arrays of typed values, you can type assert the columns to a specialized version of the write methods accepting arrays of Go primitive types. This is more efficient than boxing the input into an intermediary array of parquet.Value.
On a similar theme: How to Create In-memory Cache in Golang

To ensure that the resulting parquet file is not malformed, make sure that the same number of rows are written to each column. This is a crucial step to get right.
The generic abstraction can be a more expressive model, but it may not always be the right choice depending on the situation.
Parsing File
You can read a Parquet file using the parquet.ReadFile function, which returns a slice of Go values representing the rows read from the file.
The schema of the rows can be explicitly declared when the reader is constructed, which is useful for ensuring the program receives rows matching a specific format.
This is especially useful when dealing with files from remote storage sources that you can't trust to have used an expected schema.
To configure the schema, you pass a parquet.Schema instance as an argument when constructing a reader.
The conversion rules implemented by the package are applied to ensure that rows read by the application match the desired format.
Recommended read: Golang Read Image File

If you need more control over the file, you can use the lower-level parquet.File type, which exposes APIs to iterate over the various parts of a Parquet file.
This can be useful for leveraging the columnar layout of Parquet files.
To read or write a Parquet file, you need a ParquetFile interface implemented.
This interface is supported on different platforms, including local, HDFS, S3, GCS, and memory.
You can use the parquet-go library to open a FileReader and create a slice to hold the output of what's being unmarshalled.
Then you loop and scan, calling the unmarshall method that implements the parquet-go interface for each row.
See what others are reading: Golang Use .env File
File Management
When working with parquet files in Go, you can leverage the columnar layout to your advantage using the parquet.File type. This type exposes APIs to iterate over the various parts of a parquet file.
Inspecting parquet files can be done using the parquet.File type, which is particularly useful for Go applications.
The parquet.File type is designed to provide lower-level APIs, allowing you to tap into the columnar layout of parquet files.
If this caught your attention, see: Go vs Golang
Inspecting Files

Inspecting Files is a crucial part of file management, and sometimes it's useful to dig deeper into the specifics of a file.
The parquet.File type is designed to provide a way to iterate over the various parts of a parquet file, taking advantage of its columnar layout.
Lower-level APIs like parquet.File can be super helpful for Go applications that need to work with parquet files.
By using parquet.File, developers can gain more control over how they interact with parquet files, which can be especially useful for complex data analysis tasks.
Merging Row Groups
Merging Row Groups can be a useful operation to improve query performance by reducing the number of bloom filters stored in parquet files.
The parquet-go/parquet-go package supports creating merged views of row groups, where the view contains all the rows of the merged groups, maintaining the order defined by the sorting columns of the groups.
There are a few key constraints to keep in mind when merging row groups. The sorting columns of all the row groups must be the same, or the merge operation must be explicitly configured a set of sorting columns which are a prefix of the sorting columns of all merged row groups.

The schemas of row groups must all be equal, or the merge operation must be explicitly configured with a schema that all row groups can be converted to, in which case the limitations of schema conversions apply.
Here are the key constraints to consider when merging row groups:
- The sorting columns of all the row groups must be the same, or the merge operation must be explicitly configured a set of sorting columns which are a prefix of the sorting columns of all merged row groups.
- The schemas of row groups must all be equal, or the merge operation must be explicitly configured with a schema that all row groups can be converted to, in which case the limitations of schema conversions apply.
Once a merged view is created, it can be written to a new parquet file or buffer to create a larger row group.
Sorting Row Groups
Sorting row groups is a key feature in parquet file management. It allows you to specify the order of rows in a file by declaring sorting columns when creating a parquet.GenericBuffer[T] instance.
The parquet.GenericWriter[T] type is optimized for minimal memory usage, keeping the order of rows unchanged and flushing pages as soon as they are filled.
To sort rows, you need to buffer all rows before ordering and writing them to a parquet file. This is where parquet.GenericBuffer[T] comes in, acting as a buffer of rows and implementing sort.Interface.
Intriguing read: T Golang

The columns that rows are ordered by are configured when creating parquet.GenericBuffer[T] instances using the parquet.SortingColumns function. This function constructs row group options configuring the buffer.
The type of parquet columns defines how values are compared, and you can find more details in the Parquet Logical Types section.
After being written, buffers can be reused by calling their Reset method. This makes them efficient for use in applications that need to write multiple parquet files.
Additional reading: Golang Function Type
File
Inspecting Parquet Files can be done using the parquet.File type, which provides APIs to iterate over the various parts of a parquet file in Go applications.
This type is intended to leverage the columnar layout of parquet files, making it a useful tool for developers working with these files.
Parquet files can be read and written using the ParquetFile interface, which is implemented by parquet-go.
This interface allows for reading and writing parquet files on different platforms, including local file systems and cloud storage services like HDFS, S3, and GCS.
Here's an interesting read: Check Type of Interface Golang

You can download a parquet file from an S3 bucket using the s3manager library in Go, which provides a higher-level abstraction on top of the normal S3 library.
To download a file, you simply call the DownloadWithContext method and specify the path where you want the file to be saved.
Parsing a parquet file involves opening a FileReader from the parquet-go library and creating a slice to hold the output of the unmarshalling process.
You then loop and scan the file, calling the unmarshall method for each row to extract the data into structs.
Discover more: Aws S3 Golang
Encryption and Decryption
Encryption is a crucial aspect of data storage and retrieval, especially when working with sensitive information. ColumnDecryptionProperties can be constructed for a given column path using the NewColumnDecryptionProperties function.
You can create a new instance of ColumnDecryptionProperties with the same key and column using the Clone function. This is useful when you need to duplicate an existing set of decryption properties.
FileEncryptionProperties describe how to encrypt a parquet file when writing data. This includes the encryption properties for each column in the file.
The EncryptedColumns function returns the mapping of column paths to column encryption properties, giving you a clear view of what's being encrypted. This is especially useful when working with complex data sets.
File level encryption handling can be specified using the WithEncryptionProperties function, allowing you to control how encryption is handled on a file-by-file basis. This can be a powerful tool for managing sensitive data.
The Key function returns the key used for encrypting a column, unless it's being encrypted by the footer key. This is an important consideration when working with encrypted data.
ColumnKey returns the key to be used for decrypting a provided column, making it easier to access encrypted data. This is a crucial step in the decryption process.
Schema and Metadata
In Parquet-go, schema definition is crucial for data processing. There are four methods to define the schema: go struct tags, Json, CSV, and Arrow metadata.
Only items in the schema will be written and others will be ignored. This ensures that the data is processed accurately and efficiently.
To define a schema using Arrow metadata, you'll need to follow some restrictions. For instance, field names in the schema must start with an upper letter, and using the reserved string "PARGO_PREFIX_" as a name prefix is not allowed.
See what others are reading: How to Update a Github Using Golang
Schema
There are four methods to define the schema: go struct tags, Json, CSV, and Arrow metadata. Only items in the schema will be written and others will be ignored.
Go struct tags require public fields that start with an upper letter, which we call InName. Field names in the Parquet file are called ExName, and function common.HeadToUpper converts ExName to InName.
Here are some restrictions on field names in Arrow metadata:
- It's not allowed if two field names are only different at their first letter case, such as "name" and "Name".
- PARGO_PREFIX_ is a reserved string that you should not use as a name prefix.
- Use \x01 as the delimiter of fields to support . in some field name.
The parquet.Convert function is used to build converted views of row groups to translate between schema versions. It's a low-level routine that constructs conversion rules from a source to a target schema.
Statistics Enabled

You can control whether or not to enable column statistics using the WithStats function.
This function specifies a default for whether or not to enable column statistics.
To check if statistics are enabled for a specific column path, you can use the StatisticsEnabledFor function.
If you have a ColumnPath object, you can use the StatisticsEnabledPath function, which is the same as StatisticsEnabledFor.
The MaxStatsSizeFor function returns the maximum stat size for a given column path.
Statistics will be written for a column path if StatisticsEnabledFor returns true.
Compression and Encoding
Compression and Encoding is a crucial aspect of parquet golang that can significantly impact performance and data storage efficiency. The package offers various encoding types, including Plain, Plain/RLE Dictionary, Delta Binary Packed, Delta Byte Array, and Delta Length Byte Array.
For most use cases, it's recommended to use Plain and Dictionary encoding, as they provide a good balance between compression and performance. Some platforms may not support all encoding types, so it's essential to check the supported encodings before choosing one. If you're unsure, you can always start with Plain and Dictionary encoding.
Readers also liked: Golang Copy Array
The default encoding used by parquet-go can be customized using the `WithEncoding` and `WithEncodingPath` functions, which define the encoding for specific columns or the entire dataset. These functions are useful when you need to optimize writes or improve data compression. Here are some common encoding types supported by parquet-go:
Compression
Compression is a crucial aspect of data storage, especially when working with large datasets. The default compression type used for any columns without a specific compression defined is determined by the Compression function of WriterProperties.
This function returns the default compression type, which is a key factor in optimizing data storage and retrieval. The CompressionLevel function, on the other hand, returns the default compression level for any column without a specified compression level.
By understanding and utilizing these functions, developers can fine-tune their data storage and compression strategies to achieve better performance and efficiency. For example, using the Compression function, you can ensure that your data is stored with the optimal compression type for your specific use case.
The choice of compression type and level can significantly impact the speed and efficiency of data storage and retrieval. By selecting the right compression settings, you can reduce the time required to write wide tables or large datasets, especially on multi-core systems.
Consider reading: Golang Azure Blob Storage
Delta Binary Packed
Delta Binary Packed is a type of encoding supported in this package, and it's only available for integer types.
It's a compact way to store data, which can be beneficial for platforms with limited storage space.
The supported integer types for Delta Binary Packed encoding include INT32, INT64, INT_8, INT_16, INT_32, INT_64, UINT_8, UINT_16, UINT_32, and UINT_64.
You can also use it to store time-related data, such as TIME_MILLIS, TIME_MICROS, TIMESTAMP_MILLIS, and TIMESTAMP_MICROS.
If you're not sure what to use, you can always fall back to Plain encoding, which is supported by most platforms.
Encoding
Encoding is a crucial aspect of compression and encoding, and it's essential to understand the different types of encoding supported by parquet-go. The encoding types supported in this package are Plain, Plain/RLE Dictionary, Delta Binary Packed (only integer types), Delta Byte Array (only ByteArray), and Delta Length Byte Array (only ByteArray).
For standard formats, parquet-go will convert LIST and MAP to go slice and go map, respectively. However, for nonstandard formats, it will convert them to corresponding structs. If you're unsure what to use, just stick with Plain and Dictionary encoding.
You might enjoy: Convert a Map to Json Golang
Some platforms may not support all kinds of encodings, so it's always a good idea to check compatibility before choosing an encoding type. The default encoding that will be utilized for any columns without a specified value is determined by the Encoding function.
You can define the encoding that is used when dictionary encoding is disabled or if it grows too large with the WithEncoding function. This function is also available as WithEncodingPath, which takes a ColumnPath directly. Alternatively, you can use the WithEncodingFor function to define the encoding only for a specific column path.
The DictionaryIndexEncoding function returns which encoding will be used for the Dictionary Index values based on the parquet version. V1 uses PlainDict and V2 uses RLEDict. The supported integer types for Delta Binary Packed encoding are INT32, INT64, INT_8, INT_16, INT_32, INT_64, UINT_8, UINT_16, UINT_32, and UINT_64.
Here are the supported integer types for Delta Binary Packed encoding:
- INT32
- INT64
- INT_8
- INT_16
- INT_32
- INT_64
- UINT_8
- UINT_16
- UINT_32
- UINT_64
- TIME_MILLIS
- TIME_MICROS
- TIMESTAMP_MILLIS
- TIMESTAMP_MICROS
Debugging and Tips
Debugging can be a real pain, but parquet-go makes it a bit easier with its built-in debugging capabilities. You can turn it on by setting the PARQUETGODEBUG environment variable.
This variable must be formatted as a comma-separated list of key=value pairs. One of the debug flags you can use is tracebuf=1, which turns on tracing of internal buffers. This is useful for validating that reference counters are set to zero when buffers are reclaimed by the garbage collector.
If a buffer is leaked, the package will log an error message along with the stack trace captured when the buffer was last used. This can help you track down issues and fix them quickly.
If you're working with custom types, you'll be happy to know that parquet-go supports type aliases like MyString string. Just make sure the base type follows the instructions in the table.
Debugging
Debugging is a crucial step in the development process, and having the right tools can make all the difference. The package we're working with has built-in debugging capabilities that can be turned on using the PARQUETGODEBUG environment variable.
To enable debugging, you'll need to format the value as a comma-separated list of key=value pairs. This is similar to GODEBUG, so you may already be familiar with the process.
One of the most useful debug flags is tracebuf=1, which turns on tracing of internal buffers. This helps validate that reference counters are set to zero when buffers are reclaimed by the garbage collector.
If a buffer is leaked, the package will log an error message along with the stack trace captured when the buffer was last used. This can be a huge help in identifying and fixing issues.
Tips
When working with Parquet-go, it's essential to consider type aliases. Specifically, you can use type aliases like MyString string, but make sure the base type follows the table instructions.
Parquet-go supports type aliases, which can be useful for simplifying your code. For example, you can use type alias like MyString string.
To convert types, you can refer to the converter functions in converter.go. These functions can help you with type conversions, making your code more efficient.
Some common type convert functions include those found in converter.go, which can be a valuable resource for debugging and optimizing your code.
Readers also liked: Golang Source
Concurrency

Concurrency is a game-changer when working with large datasets in parquet-go.
The most time-consuming process in writing and reading is Marshal/Unmarshal, which can be improved by using multiple goroutines. This can be achieved by setting the concurrent number parameter np in the Read/Write initial functions.
Writing columns in parallel is a great way to maximize throughput when dealing with large columnar datasets. This is especially useful when each column can be prepared independently and written concurrently, leveraging multiple CPU cores.
You can use Go's goroutines to write to each column's ColumnWriter in parallel, making it ideal for wide tables or large datasets on multi-core systems.
To write columns in parallel, you'll need to use WriteRowValues for each column and close the column after writing. Make sure to ensure that all columns receive the same number of rows, as mismatched row counts will result in malformed files.
You might enjoy: Golang Testing Parallel
Apache
Apache Parquet is a standard data storage format in data lakes, and it's a crucial part of big data processing and engineering.
The Go ecosystem has been lacking an official and performant Parquet library, which has been a weak link in data processing and engineering on big data using Go.
Matt Poole has been working on the Apache Arrow Go Parquet library for about 2 years, and the last major code chunk got merged last week.
The new library is scheduled for the next Arrow release (7.0.0).
Featured Images: pexels.com


