apache / apache/arrow

[R] Troubles with using augmented columns

Open
#33,464 2 comments 0 reactions 0 assignees View on GitHub
Component: C++ Component: R Priority: Critical Priority: Medium Type: bug
Dominant language
C++
Stars
17.1k
Forks
4.3k
Avg merge
3d 18h
Merged PRs (30d)
91

Description

We can project to add augmented fields like `__filename`, but there are a few catches. Given:

```Java

library(arrow, warn.conflicts = FALSE)
library(dplyr, warn.conflicts = FALSE)

ds <- InMemoryDataset$create(mtcars) %>%
mutate(f = add_filename())

show_query(ds)
#> ExecPlan with 3 nodes:
#> 2:SinkNode{}
#> 1:ProjectNode{projection=[mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb, "f": __filename]}
#> 0:SourceNode{}

collect(ds)
#> mpg cyl disp hp drat wt qsec vs am gear carb f
#> 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 in-memory
#> 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 in-memory
#> 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 in-memory
...
```

Issue #1: you can't filter on that column because (my theory, based on the evidence) the ScanNode takes a projection and filter, but the filter is not evaluated with the augmented schema, so it doesn't find `__filename`. This seems fixable in C++.

```Java

ds %>%
filter(f == "in-memory") %>%
collect()
#> Error in `collect()`:
#> ! Invalid: No match for FieldRef.Name(__filename) in mpg: double
#> cyl: double
#> disp: double
#> hp: double
#> drat: double
#> wt: double
#> qsec: double
#> vs: double
#> am: double
#> gear: double
#> carb: double
#> ℹ `add_filename()` or use of the `__filename` augmented field can only be used with with Dataset objects, and can only be added before doing an aggregation or a join.

#> Backtrace:
#> ▆
#> 1. ├─ds %>% filter(f == "in-memory") %>% collect()
#> 2. ├─dplyr::collect(.)
#> 3. └─arrow:::collect.arrow_dplyr_query(.)
#> 4. └─base::tryCatch(...)
#> 5. └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 6. └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 7. └─value[[3L]](cond)
#> 8. └─arrow:::augment_io_error_msg(e, call, schema = x$.data$schema)
#> 9. └─arrow:::handle_augmented_field_misuse(msg, call)
#> 10. └─rlang::abort(msg, call = call)
```

Proof that it is in the ScanNode: If we `collapse()` the query after projecting to include filename but before the filter, the filter doesn't get included in the ScanNode, it's only applied after, as a FilterNode. This works:

```Java

ds %>%
collapse() %>%
filter(f == "in-memory") %>%
collect()
#> mpg cyl disp hp drat wt qsec vs am gear carb f
#> 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 in-memory
#> 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 in-memory
#> 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 in-memory
...
```

A related failure mode: you have to first project to include the augmented column, you can't just include it in a filter:

```Java

InMemoryDataset$create(mtcars) %>%
filter(add_filename() == "in-memory") %>%
collect()
#> Error in `collect()`:
#> ! Invalid: No match for FieldRef.Name(__filename) in mpg: double
#> cyl: double
#> disp: double
#> hp: double
#> drat: double
#> wt: double
#> qsec: double
#> vs: double
#> am: double
#> gear: double
#> carb: double
#> ℹ `add_filename()` or use of the `__filename` augmented field can only be used with with Dataset objects, and can only be added before doing an aggregation or a join.

#> Backtrace:
#> ▆
#> 1. ├─... %>% collect()
#> 2. ├─dplyr::collect(.)
#> 3. └─arrow:::collect.arrow_dplyr_query(.)
#> 4. └─base::tryCatch(...)
#> 5. └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 6. └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 7. └─value[[3L]](cond)
#> 8. └─arrow:::augment_io_error_msg(e, call, schema = x$.data$schema)
#> 9. └─arrow:::handle_augmented_field_misuse(msg, call)
#> 10. └─rlang::abort(msg, call = call)
```

Issue #2, following on that: you can only add the augmented fields at the start of the query, something that goes in the ScanNode. This seems like something we would have to catch in R and error at the time add_filename() is called. That could probably be covered in ARROW-17356.

```Java

InMemoryDataset$create(mtcars) %>%
collapse() %>%
collapse() %>%
filter(add_filename() == "in-memory") %>%
collect()
#> Error in `collect()`:
#> ! Invalid: No match for FieldRef.Name(__filename) in mpg: double
#> cyl: double
#> disp: double
#> hp: double
#> drat: double
#> wt: double
#> qsec: double
#> vs: double
#> am: double
#> gear: double
#> carb: double
#> ℹ `add_filename()` or use of the `__filename` augmented field can only be used with with Dataset objects, and can only be added before doing an aggregation or a join.

#> Backtrace:
#> ▆
#> 1. ├─... %>% collect()
#> 2. ├─dplyr::collect(.)
#> 3. └─arrow:::collect.arrow_dplyr_query(.)
#> 4. └─base::tryCatch(...)
#> 5. └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 6. └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 7. └─value[[3L]](cond)
#> 8. └─arrow:::augment_io_error_msg(e, call, schema = x$.data$schema)
#> 9. └─arrow:::handle_augmented_field_misuse(msg, call)
#> 10. └─rlang::abort(msg, call = call)
```

**Reporter**: [Neal Richardson](https://issues.apache.org/jira/browse/ARROW-18286) / @nealrichardson

**Note**: *This issue was originally created as [ARROW-18286](https://issues.apache.org/jira/browse/ARROW-18286). Please see the [migration documentation](https://github.com/apache/arrow/issues/14542) for further details.*

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the R examples with add_filename(), collapse(), filter(), and collect(), then inspect how the query is planned around the ScanNode and FilterNode. Compare projection and filter schema handling for augmented fields, including the placement restriction after collapse(). Done means the reported filtering cases work or fail with a clear, intentional error, with regression coverage added where the project’s existing tests belong.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, r
Domain
data
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.