有没有办法用 sparklyr 处理嵌套数据?
Is there a way to deal with nested data with sparklyr?
在下面的示例中,我加载了一个 parquet 文件,该文件在 meta
字段中包含地图对象的嵌套记录。 sparklyr
似乎在处理这些方面做得很好。但是 tidyr::unnest
不会转换为 SQL(或 HQL - 可以理解 - 如 LATERAL VIEW explode()
),因此不可用。有没有办法以其他方式取消嵌套数据?
tfl <- head(tf)
tfl
Source: query [?? x 10]
Database: spark connection master=yarn-client app=sparklyr local=FALSE
trkKey meta sources startTime
<chr> <list> <list> <list>
1 3juPe-k0yiMcANNMa_YiAJfJyU7WCQ3Q <S3: spark_jobj> <list [24]> <dbl [1]>
2 3juPe-k0yiAJX3ocJj1fVqru-e0syjvQ <S3: spark_jobj> <list [1]> <dbl [1]>
3 3juPe-k0yisY7UY_ufUPUo5mE1xGfmNw <S3: spark_jobj> <list [7]> <dbl [1]>
4 3juPe-k0yikXT5FhqNj87IwBw1Oy-6cw <S3: spark_jobj> <list [24]> <dbl [1]>
5 3juPe-k0yi4MMU63FEWYTNKxvDpYwsRw <S3: spark_jobj> <list [7]> <dbl [1]>
6 3juPe-k0yiFBz2uPbOQqKibCFwn7Fmlw <S3: spark_jobj> <list [19]> <dbl [1]>
# ... with 6 more variables: endTime <list>, durationInMinutes <dbl>,
# numPoints <int>, maxSpeed <dbl>, maxAltitude <dbl>, primaryKey <chr>
收集数据的时候也有问题。例如,
tfl <- head(tf) %>% collect()
tfl
# A tibble: 6 × 10
trkKey meta sources startTime
<chr> <list> <list> <list>
1 3juPe-k0yiMcANNMa_YiAJfJyU7WCQ3Q <S3: spark_jobj> <list [24]> <dbl [1]>
2 3juPe-k0yiAJX3ocJj1fVqru-e0syjvQ <S3: spark_jobj> <list [1]> <dbl [1]>
3 3juPe-k0yisY7UY_ufUPUo5mE1xGfmNw <S3: spark_jobj> <list [7]> <dbl [1]>
4 3juPe-k0yikXT5FhqNj87IwBw1Oy-6cw <S3: spark_jobj> <list [24]> <dbl [1]>
5 3juPe-k0yi4MMU63FEWYTNKxvDpYwsRw <S3: spark_jobj> <list [7]> <dbl [1]>
6 3juPe-k0yiFBz2uPbOQqKibCFwn7Fmlw <S3: spark_jobj> <list [19]> <dbl [1]>
# ... with 6 more variables: endTime <list>, durationInMinutes <dbl>,
# numPoints <int>, maxSpeed <dbl>, maxAltitude <dbl>, primaryKey <chr>
tfl %>% unnest(meta)
Error: Each column must either be a list of vectors or a list of data frames [meta]
在上面,meta
文件仍然包含 spark_jobj
个元素而不是列表、data.frames,甚至 JSON 个字符串(这是 Hive return 这样的数据)。这会造成 tidyr
甚至无法处理收集到的数据的情况。
有没有办法让 sparklyr
更好地与我缺少的 tidyr
一起工作?如果没有,这是否计划用于未来的 sparklyr
开发?
这不是一个正确的解决方案,但是一个解决方法是使用 Hive 生成 table 或视图(例如,create view db_name.table_name as select ...
)。处理爆炸操作。这为 sparklyr
提供了要处理的平面数据。其中 sc
是通过 sparklyr
的火花连接,假设 Hive 已配置,可以使用 DBI::dbGetQuery(sc, "USE db_name")
,然后在使用 src_tbls(sc)
列出 table 时显示视图。一旦你执行 dat <- tbl(sc, "table_name")
然后它应该从那里航行更顺畅。
因为这不是 sparklyr
解决方案(但更多的是 Hive 解决方案)我不会接受这个答案。
这是另一个不依赖于 Hive 的选项(至少直接如此,LATERAL VIEW explode()
是一个 Hive 的东西)。
tf %>%
sdf_mutate(ft_sql_transformer(
b, paste0("SELECT trkKey, a.fld1 as fld1, a.fld2 as fld2",
"FROM __THIS__ LATERAL VIEW explode(__THIS__.meta) x AS a")))
我也不会接受这个答案,因为我仍然希望看到类似这样的内容:
tf %>%
sdf_mutate(a=ft_explode(meta))
但这需要支持嵌套的 select 语句。也许像 tidyr::unnest
这样的语法可以解决问题:
tf %>%
sdf_mutate(a=ft_explode(meta)) %>%
unnest(a)
我终于有了答案。参见 https://mitre.github.io/sparklyr.nested/ (source: https://github.com/mitre/sparklyr.nested)
tf %>%
sdf_unnest(meta)
这对于 Spark 数据帧的行为类似于 tidyr::unnest
对于本地数据帧的行为。还实现了嵌套 select 和分解操作。
更新:
@cem-bilge 指出 explode
可以在 mutate
中使用。这在数组很简单(字符或数字)但在其他情况下效果不佳的情况下有效。
iris2 <- copy_to(sc, iris, name="iris")
iris_nst <- iris2 %>%
sdf_nest(Sepal_Length, Sepal_Width, Petal.Length, Petal.Width, .key="data") %>%
group_by(Species) %>%
summarize(data=collect_list(data))
然后
iris_nst %>% mutate(data = explode(data)) %>% sdf_schema_viewer()
产生
字段仍然嵌套(虽然展开),而 sdf_unnest
产生
iris_nst %>% sdf_unnest(data) %>% sdf_schema_viewer()
也可以直接在mutate()
中使用explode()
在sparklyr中展开数组
df %>%
mutate(my_values = explode(my_array))
注意:sparklyr.nested 不需要。
在下面的示例中,我加载了一个 parquet 文件,该文件在 meta
字段中包含地图对象的嵌套记录。 sparklyr
似乎在处理这些方面做得很好。但是 tidyr::unnest
不会转换为 SQL(或 HQL - 可以理解 - 如 LATERAL VIEW explode()
),因此不可用。有没有办法以其他方式取消嵌套数据?
tfl <- head(tf)
tfl
Source: query [?? x 10]
Database: spark connection master=yarn-client app=sparklyr local=FALSE
trkKey meta sources startTime
<chr> <list> <list> <list>
1 3juPe-k0yiMcANNMa_YiAJfJyU7WCQ3Q <S3: spark_jobj> <list [24]> <dbl [1]>
2 3juPe-k0yiAJX3ocJj1fVqru-e0syjvQ <S3: spark_jobj> <list [1]> <dbl [1]>
3 3juPe-k0yisY7UY_ufUPUo5mE1xGfmNw <S3: spark_jobj> <list [7]> <dbl [1]>
4 3juPe-k0yikXT5FhqNj87IwBw1Oy-6cw <S3: spark_jobj> <list [24]> <dbl [1]>
5 3juPe-k0yi4MMU63FEWYTNKxvDpYwsRw <S3: spark_jobj> <list [7]> <dbl [1]>
6 3juPe-k0yiFBz2uPbOQqKibCFwn7Fmlw <S3: spark_jobj> <list [19]> <dbl [1]>
# ... with 6 more variables: endTime <list>, durationInMinutes <dbl>,
# numPoints <int>, maxSpeed <dbl>, maxAltitude <dbl>, primaryKey <chr>
收集数据的时候也有问题。例如,
tfl <- head(tf) %>% collect()
tfl
# A tibble: 6 × 10
trkKey meta sources startTime
<chr> <list> <list> <list>
1 3juPe-k0yiMcANNMa_YiAJfJyU7WCQ3Q <S3: spark_jobj> <list [24]> <dbl [1]>
2 3juPe-k0yiAJX3ocJj1fVqru-e0syjvQ <S3: spark_jobj> <list [1]> <dbl [1]>
3 3juPe-k0yisY7UY_ufUPUo5mE1xGfmNw <S3: spark_jobj> <list [7]> <dbl [1]>
4 3juPe-k0yikXT5FhqNj87IwBw1Oy-6cw <S3: spark_jobj> <list [24]> <dbl [1]>
5 3juPe-k0yi4MMU63FEWYTNKxvDpYwsRw <S3: spark_jobj> <list [7]> <dbl [1]>
6 3juPe-k0yiFBz2uPbOQqKibCFwn7Fmlw <S3: spark_jobj> <list [19]> <dbl [1]>
# ... with 6 more variables: endTime <list>, durationInMinutes <dbl>,
# numPoints <int>, maxSpeed <dbl>, maxAltitude <dbl>, primaryKey <chr>
tfl %>% unnest(meta)
Error: Each column must either be a list of vectors or a list of data frames [meta]
在上面,meta
文件仍然包含 spark_jobj
个元素而不是列表、data.frames,甚至 JSON 个字符串(这是 Hive return 这样的数据)。这会造成 tidyr
甚至无法处理收集到的数据的情况。
有没有办法让 sparklyr
更好地与我缺少的 tidyr
一起工作?如果没有,这是否计划用于未来的 sparklyr
开发?
这不是一个正确的解决方案,但是一个解决方法是使用 Hive 生成 table 或视图(例如,create view db_name.table_name as select ...
)。处理爆炸操作。这为 sparklyr
提供了要处理的平面数据。其中 sc
是通过 sparklyr
的火花连接,假设 Hive 已配置,可以使用 DBI::dbGetQuery(sc, "USE db_name")
,然后在使用 src_tbls(sc)
列出 table 时显示视图。一旦你执行 dat <- tbl(sc, "table_name")
然后它应该从那里航行更顺畅。
因为这不是 sparklyr
解决方案(但更多的是 Hive 解决方案)我不会接受这个答案。
这是另一个不依赖于 Hive 的选项(至少直接如此,LATERAL VIEW explode()
是一个 Hive 的东西)。
tf %>%
sdf_mutate(ft_sql_transformer(
b, paste0("SELECT trkKey, a.fld1 as fld1, a.fld2 as fld2",
"FROM __THIS__ LATERAL VIEW explode(__THIS__.meta) x AS a")))
我也不会接受这个答案,因为我仍然希望看到类似这样的内容:
tf %>%
sdf_mutate(a=ft_explode(meta))
但这需要支持嵌套的 select 语句。也许像 tidyr::unnest
这样的语法可以解决问题:
tf %>%
sdf_mutate(a=ft_explode(meta)) %>%
unnest(a)
我终于有了答案。参见 https://mitre.github.io/sparklyr.nested/ (source: https://github.com/mitre/sparklyr.nested)
tf %>%
sdf_unnest(meta)
这对于 Spark 数据帧的行为类似于 tidyr::unnest
对于本地数据帧的行为。还实现了嵌套 select 和分解操作。
更新:
@cem-bilge 指出 explode
可以在 mutate
中使用。这在数组很简单(字符或数字)但在其他情况下效果不佳的情况下有效。
iris2 <- copy_to(sc, iris, name="iris")
iris_nst <- iris2 %>%
sdf_nest(Sepal_Length, Sepal_Width, Petal.Length, Petal.Width, .key="data") %>%
group_by(Species) %>%
summarize(data=collect_list(data))
然后
iris_nst %>% mutate(data = explode(data)) %>% sdf_schema_viewer()
产生
字段仍然嵌套(虽然展开),而 sdf_unnest
产生
iris_nst %>% sdf_unnest(data) %>% sdf_schema_viewer()
也可以直接在mutate()
中使用explode()
在sparklyr中展开数组
df %>%
mutate(my_values = explode(my_array))
注意:sparklyr.nested 不需要。