跳至内容

nanoarrow 的目标是使用 nanoarrow C 库Arrow C 数据Arrow C 流 接口提供最小的有用绑定。

安装

您可以从 CRAN 安装 nanoarrow 的发布版本:

install.packages("nanoarrow")

您可以从 GitHub 安装 nanoarrow 的开发版本:

# install.packages("remotes")
remotes::install_github("apache/arrow-nanoarrow/r")

如果您能够加载该包,则可以使用!

示例

Arrow C 数据和 Arrow C 流接口包含三个结构:ArrowSchema 代表数组的数据类型,ArrowArray 代表数组的值,以及 ArrowArrayStream 代表零个或多个具有相同 ArrowSchemaArrowArray。所有这三种结构都可以使用 nanoarrow R 包包装在 R 对象中。

模式

使用 infer_nanoarrow_schema() 获取与给定 R 向量类型相对应的 ArrowSchema 对象;使用 as_nanoarrow_schema() 将来自其他数据类型表示的对象(例如,arrow R 包 DataType,如 arrow::int32())转换为对象;或者使用 na_XXX() 函数来构造它们。

infer_nanoarrow_schema(1:5)
#> <nanoarrow_schema int32>
#>  $ format    : chr "i"
#>  $ name      : chr ""
#>  $ metadata  : list()
#>  $ flags     : int 2
#>  $ children  : list()
#>  $ dictionary: NULL
as_nanoarrow_schema(arrow::schema(col1 = arrow::float64()))
#> <nanoarrow_schema struct>
#>  $ format    : chr "+s"
#>  $ name      : chr ""
#>  $ metadata  : list()
#>  $ flags     : int 0
#>  $ children  :List of 1
#>   ..$ col1:<nanoarrow_schema double>
#>   .. ..$ format    : chr "g"
#>   .. ..$ name      : chr "col1"
#>   .. ..$ metadata  : list()
#>   .. ..$ flags     : int 2
#>   .. ..$ children  : list()
#>   .. ..$ dictionary: NULL
#>  $ dictionary: NULL
na_int64()
#> <nanoarrow_schema int64>
#>  $ format    : chr "l"
#>  $ name      : chr ""
#>  $ metadata  : list()
#>  $ flags     : int 2
#>  $ children  : list()
#>  $ dictionary: NULL

数组

使用 as_nanoarrow_array() 将对象转换为 ArrowArray 对象。

as_nanoarrow_array(1:5)
#> <nanoarrow_array int32[5]>
#>  $ length    : int 5
#>  $ null_count: int 0
#>  $ offset    : int 0
#>  $ buffers   :List of 2
#>   ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>   ..$ :<nanoarrow_buffer data<int32>[5][20 b]> `1 2 3 4 5`
#>  $ dictionary: NULL
#>  $ children  : list()
as_nanoarrow_array(data.frame(col1 = c(1.1, 2.2)))
#> <nanoarrow_array struct[2]>
#>  $ length    : int 2
#>  $ null_count: int 0
#>  $ offset    : int 0
#>  $ buffers   :List of 1
#>   ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>  $ children  :List of 1
#>   ..$ col1:<nanoarrow_array double[2]>
#>   .. ..$ length    : int 2
#>   .. ..$ null_count: int 0
#>   .. ..$ offset    : int 0
#>   .. ..$ buffers   :List of 2
#>   .. .. ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>   .. .. ..$ :<nanoarrow_buffer data<double>[2][16 b]> `1.1 2.2`
#>   .. ..$ dictionary: NULL
#>   .. ..$ children  : list()
#>  $ dictionary: NULL

您可以使用 as.vector()as.data.frame() 获取对象的 R 表示形式。

array <- as_nanoarrow_array(data.frame(col1 = c(1.1, 2.2)))
as.data.frame(array)
#>   col1
#> 1  1.1
#> 2  2.2

即使在 C 级别上,ArrowArray 与 ArrowSchema 是不同的,但在 R 级别上,我们会在可能的情况下附加一个模式。您可以使用 infer_nanoarrow_schema() 访问附加的模式。

infer_nanoarrow_schema(array)
#> <nanoarrow_schema struct>
#>  $ format    : chr "+s"
#>  $ name      : chr ""
#>  $ metadata  : list()
#>  $ flags     : int 0
#>  $ children  :List of 1
#>   ..$ col1:<nanoarrow_schema double>
#>   .. ..$ format    : chr "g"
#>   .. ..$ name      : chr "col1"
#>   .. ..$ metadata  : list()
#>   .. ..$ flags     : int 2
#>   .. ..$ children  : list()
#>   .. ..$ dictionary: NULL
#>  $ dictionary: NULL

数组流

创建 ArrowArrayStream 最简单的方法是从数组或对象列表中创建,这些数组或对象可以使用 as_nanoarrow_array() 转换为数组。

stream <- basic_array_stream(
  list(
    data.frame(col1 = c(1.1, 2.2)),
    data.frame(col1 = c(3.3, 4.4))
  )
)

您可以使用 $get_next() 方法从流中拉取批次。最后一个批次将返回 NULL

stream$get_next()
#> <nanoarrow_array struct[2]>
#>  $ length    : int 2
#>  $ null_count: int 0
#>  $ offset    : int 0
#>  $ buffers   :List of 1
#>   ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>  $ children  :List of 1
#>   ..$ col1:<nanoarrow_array double[2]>
#>   .. ..$ length    : int 2
#>   .. ..$ null_count: int 0
#>   .. ..$ offset    : int 0
#>   .. ..$ buffers   :List of 2
#>   .. .. ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>   .. .. ..$ :<nanoarrow_buffer data<double>[2][16 b]> `1.1 2.2`
#>   .. ..$ dictionary: NULL
#>   .. ..$ children  : list()
#>  $ dictionary: NULL
stream$get_next()
#> <nanoarrow_array struct[2]>
#>  $ length    : int 2
#>  $ null_count: int 0
#>  $ offset    : int 0
#>  $ buffers   :List of 1
#>   ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>  $ children  :List of 1
#>   ..$ col1:<nanoarrow_array double[2]>
#>   .. ..$ length    : int 2
#>   .. ..$ null_count: int 0
#>   .. ..$ offset    : int 0
#>   .. ..$ buffers   :List of 2
#>   .. .. ..$ :<nanoarrow_buffer validity<bool>[0][0 b]> ``
#>   .. .. ..$ :<nanoarrow_buffer data<double>[2][16 b]> `3.3 4.4`
#>   .. ..$ dictionary: NULL
#>   .. ..$ children  : list()
#>  $ dictionary: NULL
stream$get_next()
#> NULL

您可以通过调用 as.data.frame()as.vector() 将所有批次拉取到一个 data.frame() 中。

stream <- basic_array_stream(
  list(
    data.frame(col1 = c(1.1, 2.2)),
    data.frame(col1 = c(3.3, 4.4))
  )
)

as.data.frame(stream)
#>   col1
#> 1  1.1
#> 2  2.2
#> 3  3.3
#> 4  4.4

在使用流后,您应该尽快调用释放方法。这使流的实现能够以比等待垃圾收集器清理对象更可预测的方式释放任何资源(例如打开的文件)。

与 arrow 包的集成

nanoarrow 包为大多数 arrow 包类型实现了 as_nanoarrow_schema()as_nanoarrow_array()as_nanoarrow_array_stream()。类似地,它为 nanoarrow 对象实现了 arrow::as_arrow_array()arrow::as_record_batch()arrow::as_arrow_table()arrow::as_record_batch_reader()arrow::infer_type()arrow::as_data_type()arrow::as_schema(),这样您就可以将等效的 nanoarrow 对象传递给许多 arrow 函数,反之亦然。