-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[C#] Add decompression support for Record Batches #32240
Comments
Rishabh Rana / @rishabh-rana: Are we allowed to add a dependency to Arrow for an lz4 compression/ decompression library as part of this change? If not can you suggest another way forward? |
Eric Erhardt / @eerhardt: |
Rishabh Rana / @rishabh-rana: example: interface Decoder {
public void Lz4Decode(Stream input, Stream output);
public void ZstdDecode(Stream input, Stream output);
}
// usage
public class LZ4Decoder: Decoder {
public void Lz4Decode(Stream input, Stream output) {
LZ4Stream.Decode(input).CopyTo(output);
}
public void Lz4Decode(Stream input, Stream output) {
throw new NotImplementedException();
}
}
ArrowStreamReader(stream, new LZ4Decoder()); Does this sound good to you? Apologies for confirming again but this would impact quite a bit of code, So I wanted to make sure that I follow the best practices. Thanks! |
Rishabh Rana / @rishabh-rana: |
Weston Pace / @westonpace:
This opens the door for a future where someone could write a compression provider that supported both LZ4 and gzip (I think that gzip is part of System.IO.Compression and so should be very easy to support). |
Weston Pace / @westonpace: For example, you could use Type.GetType to check if System.IO.Compression.GZipStream exists and, if it does, add a GZipDecoder automatically. However, this would require reflection to create the GZipStream. Maybe someone can think of a more clever solution. |
Adam Reeve / @adamreeve: var lz4DecoderType = Type.GetType("Apache.Arrow.Compression.Lz4.Lz4Decoder, Apache.Arrow.Compression.Lz4", false);
if (lz4DecoderType != null)
{
if (Activator.CreateInstance(lz4DecoderType) is IDecoder decoder)
{
// use decoder
}
else
{
throw new Exception("Failed to cast Lz4Decoder to IDecoder");
}
} Having to maintain these extra wrapper packages would be a bit more work from an operational point of view though. It does seem like just adding new dependencies directly to the Arrow package would be a lot more straightforward, and given there are only two compression formats currently used is this really a problem? On a more minor point, would Decompressor be a more precise term to use rather than Decoder? At least in the Parquet world, which I'm a bit more familiar with, encodings are a separate concept to compression formats. |
Rishabh Rana / @rishabh-rana: Personally, I am more inclined towards the approach that Eric and Weston have proposed. To avoid any unnecessary dependencies on Arrow. I will try to put the code together for the issue soon for a more fruitful discussion on the PR itself. Thanks! |
Adam Reeve / @adamreeve: It isn't in a state suitable for a pull request and just adds ZstdNet as a dependency of Apache.Arrow, which required bumping the target framework to netstandard2.0, but it might still be useful to you as a starting point, depending on how far you've already got with this. |
Apache Arrow JIRA Bot: |
Adam Reeve / @adamreeve: |
I went ahead and tidied up my code and used the reflection approach suggested by @westonpace to implement a default compression provider. I've created a PR for this at #33603 I'm still not sure the reflection approach is the best way to go, it's pretty verbose and not very discoverable by users. I've included some comments in that PR about alternative approaches but maybe it's better to discuss them here rather than on the PR, so I'll copy them below:
PS. |
This sounds like a good approach to me. I think having a standard package that just picks some common compression libs is going to be sufficient for 80% of use cases. |
Cool okay, @lidavidm mentioned on the PR that the Java library works that way too so I'll take a look at the API used there to see if I can make the dotnet API consistent with the way the Java API works, and pare the PR back to remove the reflection based implementation for now. It might make sense to add the new package in a separate PR. |
That seems reasonable to me. |
# Which issue does this PR close? Closes #32240 / https://issues.apache.org/jira/browse/ARROW-16921 # What changes are included in this PR? This PR implements decompression support for Arrow IPC format files and streams in the dotnet/C# library. The main concern raised in the above Jira issue was that we don't want to add new NuGet package dependencies to support decompression formats that won't be needed by most users, so a default `CompressionProvider` implementation has been added that uses reflection to use the `ZstdNet` package for ZSTD decompression and `K4os.Compression.LZ4.Streams` and `CommunityToolkit.HighPerformance` for LZ4 Frame support if they are available. The `netstandard1.3` target has decompression support disabled due to some reflection functionality being missing, and neither `ZstdNet` or `K4os.Compression.LZ4.Streams` support `netstandard1.3`. The `ArrowFileReader` and `ArrowStreamReader` constructors accept an `ICompressionProvider` parameter to allow users to provide their own compression provider if they want to use different dependencies. ### Alternatives to consider An alternative approach that could be considered instead of reflection is to use these extra dependencies as build time dependencies but not make them dependencies of the NuGet package. I tested this out in adamreeve@4544afd and it seems to work reasonably well too but required bumping the version of `System.Runtime.CompilerServices.Unsafe` under the `netstandard2.0` and `netcoreapp3.1` targets. This reduces all the reflection boilerplate but seems pretty hacky as now Apache.Arrow.dll depends on these extra dlls and we rely on the dotnet runtime behaviour of not trying to load them until they're used. So I think the reflection approach is better. Another alternative would be to move decompression support into a separate NuGet package (eg. `Apache.Arrow.Compression`) that depends on `Apache.Arrow` and has an implementation of `ICompressionProvider` that users can pass in to the `ArrowFileReader` constructor, or maybe has a way to register itself with the `Apache.Arrow` package so it only needs to be configured once. That would seem cleaner to me but I'm not sure how much work it would be to set up a whole new package. # Are these changes tested? Yes, new unit tests have been added. Test files have been created with a Python script that is included in the PR due to only decompression support being added and not compression support. # Are there any user-facing changes? Yes, this implements a new feature but in a backwards compatible way. * Closes: #32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Will Jones <[email protected]>
…che#33603) # Which issue does this PR close? Closes apache#32240 / https://issues.apache.org/jira/browse/ARROW-16921 # What changes are included in this PR? This PR implements decompression support for Arrow IPC format files and streams in the dotnet/C# library. The main concern raised in the above Jira issue was that we don't want to add new NuGet package dependencies to support decompression formats that won't be needed by most users, so a default `CompressionProvider` implementation has been added that uses reflection to use the `ZstdNet` package for ZSTD decompression and `K4os.Compression.LZ4.Streams` and `CommunityToolkit.HighPerformance` for LZ4 Frame support if they are available. The `netstandard1.3` target has decompression support disabled due to some reflection functionality being missing, and neither `ZstdNet` or `K4os.Compression.LZ4.Streams` support `netstandard1.3`. The `ArrowFileReader` and `ArrowStreamReader` constructors accept an `ICompressionProvider` parameter to allow users to provide their own compression provider if they want to use different dependencies. ### Alternatives to consider An alternative approach that could be considered instead of reflection is to use these extra dependencies as build time dependencies but not make them dependencies of the NuGet package. I tested this out in adamreeve@4544afd and it seems to work reasonably well too but required bumping the version of `System.Runtime.CompilerServices.Unsafe` under the `netstandard2.0` and `netcoreapp3.1` targets. This reduces all the reflection boilerplate but seems pretty hacky as now Apache.Arrow.dll depends on these extra dlls and we rely on the dotnet runtime behaviour of not trying to load them until they're used. So I think the reflection approach is better. Another alternative would be to move decompression support into a separate NuGet package (eg. `Apache.Arrow.Compression`) that depends on `Apache.Arrow` and has an implementation of `ICompressionProvider` that users can pass in to the `ArrowFileReader` constructor, or maybe has a way to register itself with the `Apache.Arrow` package so it only needs to be configured once. That would seem cleaner to me but I'm not sure how much work it would be to set up a whole new package. # Are these changes tested? Yes, new unit tests have been added. Test files have been created with a Python script that is included in the PR due to only decompression support being added and not compression support. # Are there any user-facing changes? Yes, this implements a new feature but in a backwards compatible way. * Closes: apache#32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Will Jones <[email protected]>
…ReadOnlyMemory (#34108) This is a small follow-up to #33603 to support reading a compressed IPC stream from a `ReadOnlyMemory<byte>`, as I missed that this has a separate reader implementation. * Closes: #32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Weston Pace <[email protected]>
…che#33603) # Which issue does this PR close? Closes apache#32240 / https://issues.apache.org/jira/browse/ARROW-16921 # What changes are included in this PR? This PR implements decompression support for Arrow IPC format files and streams in the dotnet/C# library. The main concern raised in the above Jira issue was that we don't want to add new NuGet package dependencies to support decompression formats that won't be needed by most users, so a default `CompressionProvider` implementation has been added that uses reflection to use the `ZstdNet` package for ZSTD decompression and `K4os.Compression.LZ4.Streams` and `CommunityToolkit.HighPerformance` for LZ4 Frame support if they are available. The `netstandard1.3` target has decompression support disabled due to some reflection functionality being missing, and neither `ZstdNet` or `K4os.Compression.LZ4.Streams` support `netstandard1.3`. The `ArrowFileReader` and `ArrowStreamReader` constructors accept an `ICompressionProvider` parameter to allow users to provide their own compression provider if they want to use different dependencies. ### Alternatives to consider An alternative approach that could be considered instead of reflection is to use these extra dependencies as build time dependencies but not make them dependencies of the NuGet package. I tested this out in adamreeve@4544afd and it seems to work reasonably well too but required bumping the version of `System.Runtime.CompilerServices.Unsafe` under the `netstandard2.0` and `netcoreapp3.1` targets. This reduces all the reflection boilerplate but seems pretty hacky as now Apache.Arrow.dll depends on these extra dlls and we rely on the dotnet runtime behaviour of not trying to load them until they're used. So I think the reflection approach is better. Another alternative would be to move decompression support into a separate NuGet package (eg. `Apache.Arrow.Compression`) that depends on `Apache.Arrow` and has an implementation of `ICompressionProvider` that users can pass in to the `ArrowFileReader` constructor, or maybe has a way to register itself with the `Apache.Arrow` package so it only needs to be configured once. That would seem cleaner to me but I'm not sure how much work it would be to set up a whole new package. # Are these changes tested? Yes, new unit tests have been added. Test files have been created with a Python script that is included in the PR due to only decompression support being added and not compression support. # Are there any user-facing changes? Yes, this implements a new feature but in a backwards compatible way. * Closes: apache#32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Will Jones <[email protected]>
… from ReadOnlyMemory (apache#34108) This is a small follow-up to apache#33603 to support reading a compressed IPC stream from a `ReadOnlyMemory<byte>`, as I missed that this has a separate reader implementation. * Closes: apache#32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Weston Pace <[email protected]>
… from ReadOnlyMemory (apache#34108) This is a small follow-up to apache#33603 to support reading a compressed IPC stream from a `ReadOnlyMemory<byte>`, as I missed that this has a separate reader implementation. * Closes: apache#32240 Authored-by: Adam Reeve <[email protected]> Signed-off-by: Weston Pace <[email protected]>
…IPC decompression (#33893) ### Rationale for this change This further addresses #32240 and is a follow up to PR #33603 to provide an implementation of the `ICompressionCodecFactory` interface in a new `Apache.Arrow.Compression` package. Making this a separate package means users who don't need IPC decompression support don't need to pull in extra dependencies. ### What changes are included in this PR? Adds a new `Apache.Arrow.Compression` package and moves the existing compression codec implementations used for testing into this package. ### Are these changes tested? There are unit tests verifying the decompression support, but this also affects the release scripts and I'm not sure how to fully test these. ### Are there any user-facing changes? Yes, this adds a new package users can install for IPC decompression support, so documentation has been updated. * Closes: #32240 Lead-authored-by: Adam Reeve <[email protected]> Co-authored-by: Eric Erhardt <[email protected]> Signed-off-by: Eric Erhardt <[email protected]>
C# Implementation does not support reading batches written in other implementations of Arrow when the compression is specified in IPC Write options.
e.g. Reading this batch from pyarrow in C# will fail:
pyarrow.ipc.RecordStreamBatchWriter(sink, schema, options=pyarrow,ipcWriteOptions(compression="lz4"))
This is to support decompression (lz4 & zstd) in the C# implementation.
Reporter: Rishabh Rana / @rishabh-rana
Related issues:
Note: This issue was originally created as ARROW-16921. Please see the migration documentation for further details.
The text was updated successfully, but these errors were encountered: