Вы можете создать эквивалент, используя map
/ explode
:
sdf_gather <- function(data, key = "key", value = "value", ...) {
cols <- list(...) %>% unlist()
# Explode with map (same as stack) requires multiple aliases so
# dplyr mutate won't work for us here.
expr <- list(paste(
"explode(map(",
paste("'", cols, "',`", cols, "`", sep = "", collapse = ","),
")) as (", key, ",", value, ")", sep = ""))
keys <- data %>% colnames() %>% setdiff(cols) %>% as.list()
data %>%
spark_dataframe() %>%
sparklyr::invoke("selectExpr", c(keys, expr)) %>%
sdf_register()
}
или функцию Hive stack
:
sdf_gather <- function(data, key = "key", value = "value", ...) {
cols <- list(...) %>% unlist()
expr <- list(paste(
"stack(", length(cols), ", ",
paste("'", cols, "',`", cols, "`", sep="", collapse=","),
") as (", key, ",", value, ")", sep=""))
keys <- data %>% colnames() %>% setdiff(cols) %>% as.list()
data %>%
spark_dataframe() %>%
sparklyr::invoke("selectExpr", c(keys, expr)) %>%
sdf_register()
}
Оба должныдать тот же результат:
long <- sdf_gather(
df, "my_key", "my_value",
"value", "average", "upper_bound", "lower_bound")
long
# Source: table<sparklyr_tmp_7b8f5989ba4d> [?? x 4]
# Database: spark_connection
id attribute1 my_key my_value
<dbl> <chr> <chr> <dbl>
1 1 This value 10
2 1 This average 50
3 1 This upper_bound 80
4 1 This lower_bound 20
5 1 That value 20
6 1 That average 50
7 1 That upper_bound 80
8 1 That lower_bound 20
9 1 These value 30
10 1 These average 50
# ... with more rows
и может быть изменен для поддержки нестандартной оценки.
Обратите внимание, что оба метода требуют однородных типов столбцов.
Примечания
explode
версия генерирует следующий запрос:
SELECT id, attribute1,
explode(map(
'value', `value`,
'average', `average`,
'upper_bound', `upper_bound`,
'lower_bound', `lower_bound`)) as (my_key,my_value)
FROM df
и оптимизированный логический план выполнения
org.apache.spark.sql.catalyst.plans.logical.Generate
Generate explode(map(value, value#16, average, average#17, upper_bound, upper_bound#18, lower_bound, lower_bound#19)), [2, 3, 4, 5], false, [my_key#226, my_value#227]
+- InMemoryRelation [id#14, attribute1#15, value#16, average#17, upper_bound#18, lower_bound#19], StorageLevel(disk, memory, deserialized, 1 replicas)
+- Scan ExistingRDD[id#14,attribute1#15,value#16,average#17,upper_bound#18,lower_bound#19]
в то время как stack
version генерирует
SELECT id, attribute1,
stack(4,
'value', `value`,
'average', `average`,
'upper_bound', `upper_bound`,
'lower_bound', `lower_bound`) as (my_key,my_value)
FROM df
и
org.apache.spark.sql.catalyst.plans.logical.Generate
Generate stack(4, value, value#16, average, average#17, upper_bound, upper_bound#18, lower_bound, lower_bound#19), [2, 3, 4, 5], false, [my_key#323, my_value#324]
+- InMemoryRelation [id#14, attribute1#15, value#16, average#17, upper_bound#18, lower_bound#19], StorageLevel(disk, memory, deserialized, 1 replicas)
+- Scan ExistingRDD[id#14,attribute1#15,value#16,average#17,upper_bound#18,lower_bound#19]
Одинарные значения в кавычках (т. е. 'value'
), в сгенерированном SQL являются литеральными строками, а значения в кавычках представляют ссылку на столбец.