目的: 我们希望使用AWS Glue Data Catalog为存储在S3存储桶中的JSON数据创建一个表,然后我们将通过Redshift Spectrum进行查询和解析。
背景 JSON数据来自DynamoDB Streams并且是深层嵌套的。第一级JSON具有一组一致的元素:Keys,NewImage,OldImage,SequenceNumber,ApproximateCreationDateTime,SizeBytes和EventName。唯一的变化是有些记录没有NewImage,有些没有OldImage。但是,在第一级以下,架构差异很大。
理想情况下,我们希望使用Glue仅解析第一级JSON,并且基本上将较低级别视为大型STRING对象(我们将根据需要使用Redshift Spectrum对其进行解析)。目前,我们将整个记录加载到Redshift中的单个VARCHAR列中,但记录接近Redshift中数据类型的最大大小(最大VARCHAR长度为65535)。因此,我们希望在记录达到Redshift之前执行第一级解析。
到目前为止我们尝试/引用的内容:
问题: 我们如何使用Glue(或其他方法)允许我们只解析这些记录的第一级 - 同时忽略顶层元素下面的不同模式 - 这样我们就可以从Spectrum访问它或将其物理加载到红移?
我是Glue的新手。我花了很多时间在Glue文档中并在论坛上查看(有些稀疏)信息。我可能会遗漏一些明显的东西 - 或者这可能是目前形式的胶水限制。欢迎任何建议。
谢谢!
答案 0 :(得分:1)
我不确定您是否可以使用表定义执行此操作,但您可以使用映射函数将顶级值强制转换为JSON字符串,从而通过ETL作业完成此操作。文档:[link]
import json
# Your mapping function
def flatten(rec):
for key in rec:
rec[key] = json.dumps(rec[key])
return rec
old_df = glueContext.create_dynamic_frame.from_options(
's3',
{"paths": ['s3://...']},
"json")
# Apply mapping function f to all DynamicRecords in DynamicFrame
new_df = Map.apply(frame=old_df, f=flatten)
从这里你可以选择导出到S3(可能是Parquet或其他一些柱状格式以优化查询)或者直接从我的理解中直接进入Redshift,尽管我还没有尝试过。
答案 1 :(得分:0)
这是目前胶水的限制。你看过胶水分类器了吗?这是我还没有用过的唯一一件,但可能适合你的需求。您可以为字段或类似内容定义JSON路径。
除此之外 - Glue Jobs是要走的路。它是背景中的Spark,所以你几乎可以做任何事情。设置开发端点并使用它。在过去三周里,我遇到了各种障碍,并决定完全放弃任何和所有Glue功能,只有Spark,这样既可移动又实际工作。
在设置开发端点时,您可能需要记住的一件事是IAM角色必须具有“/”路径,因此您很可能需要手动创建具有此路径的单独角色。自动创建的路径为“/ service-role /".
答案 2 :(得分:0)
你应该添加胶水分类器,最好是$ [*]
在s3中抓取json文件时,它将读取文件的第一行。
您可以创建粘贴作业,以便将此json文件的数据目录表加载到redshift中。
我唯一的问题是Redshift Spectrum在读取数据目录中的json表时遇到问题。
如果您找到了解决方案,请告诉我
答案 3 :(得分:0)
我发现对浅层嵌套json有用的过程
以 i=0
corpus = lapply(corpus, function(x)
ifelse(x == "short", {i<<-i+1;paste0("short", i)}, x )
) # appends index to each occurrence so itoken distinguishes them
it = itoken(corpus)
tcm = create_vocabulary(it) %>% vocab_vectorizer() %>% create_tcm(it, . , skip_grams_window = 2, weights = rep(1,2))
attempt = as.matrix(forceSymmetric(tcm, "U") %>%
.[grep("^short", rownames(.)), -grep("^short", colnames(.))]
) # filters the resulting full tcm
# yields intended result but is hacky/slow:
print(attempt)
different here document is a
short2 1 0 1 0 1
short1 0 0 1 1 1
的第一级应用映射;
分解datasource0
或struct
对象以摆脱元素级别
array
,其中df1 = datasource0.toDF().select(id,col1,col2,...,explode(coln).alias(coln)
需要explode
;
通过from pyspark.sql.functions import explode
选择要保持完整的JSON对象。
将intact_json = df1.select(id, itct1, itct2,..., itctm)
转换回dynamicFrame并关联
dynamicFrame以及通过df1
删除完整的列;
使用基于'id'的完整表联接关系表 列。
答案 4 :(得分:0)
截至2018年12月20日,我能够手动将具有第一级json字段的表定义为类型为STRING的列。然后在胶水脚本中,dynamicframe将列作为字符串。从那里,您可以在字段上执行Unbox
类型的json
操作。这将对字段进行json解析并得出真实的模式。将Unbox
与Filter
结合使用,可以循环访问并处理来自同一输入的异构json模式,前提是您可以遍历模式列表。
但是,请注意,这太慢了。我认为胶水是在循环的每次迭代期间从s3下载源文件。我一直在尝试找到一种方法来保留初始源数据,但是即使您将它们指定为粘胶StringType,.toDF
仍会派生出字符串json字段的架构。如果可以找出性能更好的解决方案,请在此处添加评论。