使用R与DuckDB实现列的序列化与反序列化问题排查
序列化HTML列与DuckDB交互的问题及解决方案
已验证解决方案
感谢@r2evans的解答,针对该场景的可行方案如下:
- 写入数据库时,对目标列执行序列化:
dplyr::mutate(x = sapply(.data$x, serialize, connection = NULL)) - 从数据库读取后,反序列化并恢复HTML类型:
dplyr::mutate(x = lapply(.data$x, \(x) htmltools::HTML(unserialize(x))))
问题详情
需要将包含HTML类型列的数据框写入DuckDB,因原始数据类型与数据库不兼容,先对该列做序列化处理,但从数据库读取后无法将其反序列化为原始HTML类型。
可复现示例
基础数据构造:
df <- tibble::tibble(x = 1:5, y = letters[1:5]) # A tibble: 5 × 2 x y <int> <chr> 1 1 a 2 2 b 3 3 c 4 4 d 5 5 e
序列化目标列后的数据:
input <- df |> dplyr::mutate(x = lapply(x, serialize, NULL)) # A tibble: 5 × 2 x y <list> <chr> 1 <raw [35]> a 2 <raw [35]> b 3 <raw [35]> c 4 <raw [35]> d 5 <raw [35]> e
写入并读取DuckDB:
conn <- duckdb::dbConnect(duckdb::duckdb(), ":memory:") duckdb::dbWriteTable(conn, "df", input) output <- DBI::dbGetQuery(conn, "SELECT * FROM df") |> tibble::as_tibble() # A tibble: 5 × 2 x y <list> <chr> 1 <raw [35]> a 2 <raw [35]> b 3 <raw [35]> c 4 <raw [35]> d 5 <raw [35]> e
针对基础int类型的反序列化能正常恢复,但实际HTML场景异常:
output |> dplyr::mutate(x = lapply(x, unserialize)) # A tibble: 5 × 2 x y <list> <chr> 1 <int [1]> a 2 <int [1]> b 3 <int [1]> c 4 <int [1]> d 5 <int [1]> e
补充说明
实际场景中,序列化的列存储的是HTML字符串,序列化前的数据结构:
# A tibble: 5 × 2 x y <list> <chr> 1 <html> a 2 <html> b 3 <html> c 4 <html> d 5 <html> e
执行反序列化代码后,得到不符合预期的结果:
# A tibble: 5 × 2 x y <list> <chr> 1 <raw> a 2 <raw> b 3 <raw> c 4 <raw> d 5 <raw> e
更多信息
序列化前后的数据详情:
> before[1] [[1]] <a href='data:text/csv;base64,Zm9v' download='foo.csv'><button style='background-color:#67C2DC; color:white; border:none; padding:5px;font-weight:bold; cursor:pointer; border-radius:4px; font-size:12px;'>CSV</button></a> > after[1] [[1]] [1] 58 0a 00 00 00 03 00 04 04 01 00 03 05 00 00 00 00 05 55 54 46 2d 38 00 00 00 18 00 02 8c 7a 58 0a 00 00 00 03 ... [ reached getOption("max.print") -- omitted 166065 entries ] > class(before) [1] "list" > class(before[1]) [1] "list" > class(before[1][[1]]) [1] "html" "character" > class(after) [1] "list" > class(after[1]) [1] "list" > class(after[1][[1]]) [1] "raw"
尝试所有现有建议均无效,反序列化后始终得到<raw>类型数据:
> unserialize(after[1][[1]]) [1] 58 0a 00 00 00 03 00 04 04 01 00 03 05 00 00 00 00 05 55 54 46 2d 38 00 00 00 18 00 02 8c 5b 58 0a 00 00 00 03 ...
内容的提问来源于stack exchange,提问作者FISR
相关产品推荐
相关产品推荐

