使用bigrquery+dplyr调用外部脚本函数时出现<tbl_lazy>$方法报错
问题描述
我使用dplyr接口编写用于BigQuery数据库表QC的通用函数,通过source()将其引入一系列表专属的RMD文档中。在RMD文件中直接运行代码完全正常,但封装为函数后持续报错:
Error in `table$variable`: ! The `$` method of <tbl_lazy> is for internal use only. ℹ Use `dplyr::pull()` to get the values in a column.
报错的示例函数:
count_records_by_group <- function(table, variable) { table %>% group_by(variable) %>% summarise(count = n()) %>% data.frame() }
硬编码变量名可正常运行,但不符合通用函数设计初衷:
count_records_by_group <- function(table) { table %>% group_by(year) %>% summarise(count = n()) %>% data.frame() }
已尝试eval(parse("variable"))、dplyr::pull(table, variable)等方式,临时方案是将整张表加载到内存,但不适用于多数大表。使用包版本:dplyr 1.1.4,dbplyr 2.5.0,bigrquery 1.5.1。
解决方案
这不是bug,是未正确处理**非标准求值(NSE)**导致的问题。dbplyr处理懒加载表(tbl_lazy)时,不能直接将变量名裸传给group_by,需使用dplyr的整洁评估语法:
方法1:使用{{ }}(推荐,dplyr 1.0+)
这是最简洁的写法,自动处理变量引用:
count_records_by_group <- function(table, variable) { table %>% group_by({{ variable }}) %>% summarise(count = n()) %>% data.frame() }
调用时直接传入列名:count_records_by_group(my_bq_table, year)
方法2:使用.data代词(适合传入字符串类型的列名)
如果variable是字符串(如variable = "year"),用.data代词引用列:
count_records_by_group <- function(table, variable) { table %>% group_by(.data[[variable]]) %>% summarise(count = n()) %>% data.frame() }
调用方式:count_records_by_group(my_bq_table, "year")
方法3:传统NSE写法(enquo() + !!)
兼容旧版dplyr的写法:
count_records_by_group <- function(table, variable) { var_enquo <- enquo(variable) table %>% group_by(!!var_enquo) %>% summarise(count = n()) %>% data.frame() }
调用方式与方法1一致,直接传入列名。
以上方法均无需加载整张表到内存,可让dbplyr正确生成SQL查询发送至BigQuery,避免tbl_lazy相关报错。
内容的提问来源于stack exchange,提问作者frontflip
相关产品推荐
相关产品推荐

