Apache spark get_json_对象与from_json对象的性能

Apache spark get_json_对象与from_json对象的性能,apache-spark,pyspark,apache-spark-sql,Apache Spark,Pyspark,Apache Spark Sql,我很好奇Spark如何使用get\u json\u object方法,以及我是否正确使用了它。假设我有一个字符串类型的列data(JSON编码),每行的值都相当大(~1MB) 如果我想检索和处理参数的子集,我可以轻松地执行以下操作: param_a=get_json_对象(“data”,“$.my.param.a”).cast(“int”) param_b=get_json_对象(“data”,“$.my.param.b”).cast(“int”) 我的总和=参数a+参数b Spark会自动推

我很好奇Spark如何使用
get\u json\u object
方法,以及我是否正确使用了它。假设我有一个字符串类型的列
data
(JSON编码),每行的值都相当大(~1MB)

如果我想检索和处理参数的子集,我可以轻松地执行以下操作:

param_a=get_json_对象(“data”,“$.my.param.a”).cast(“int”)
param_b=get_json_对象(“data”,“$.my.param.b”).cast(“int”)
我的总和=参数a+参数b
Spark会自动推导出只需要在内部解码一次JSON,然后重新使用该状态,还是会在每次调用
get\u JSON\u object
时解码


或者,我可以使用来自_json的
并在定义良好的模式中检索:

\u schema=StructType().添加(“a”,IntegerType()).添加(“b”,IntegerType())
params=from_json(获取_json_对象(“数据”,“$.my.param”),_模式)
my_sum=参数[“a”]+参数[“b”]
因此,我的问题是:这些方法在性能上是否具有可比性,和/或是否有其他理由使用一种方法优于另一种方法?

因此我编写了一个测试()来测试它。基本上是一个执行上述操作的设置,具有以下变量:

  • 要解码的参数数
  • 行数
  • 每个数据行的大小
  • 平均超过100次的复制/实验次数
使用100行8个参数和1KB数据JSON编码的字符串内容(以及500次复制),结果如下:

{<function _method_b at 0x7fb73d30e200>: 0.16155768394470216,
 <function _method_a at 0x7fb73d30e320>: 0.22132105827331544}
{:0.16155768394470216,
: 0.22132105827331544}
因此,在这种情况下,在实施模式方面似乎有大约25%的改进

此外:

  • 将参数数量从8减少到2实际上浪费了差异:
{:0.15471874809265138,
: 0.14935027599334716}

因此:我的结论是,如果您想要解释一个结构的许多参数,那么实施模式的性能会有所提高,但如果只是少数,那么性能也会一样好(并且更易于读/写)只需使用
get_json_object
和casting即可。

我对Apache Spark这一部分的理解非常有限,但我想与大家分享一下
get_json_object
的代码,这可以提供更多的信息(或许可以得到一个非常有用的答案)


tl;dr:我建议在访问多个json字段时使用
from_json(get_json_object(…),…)
以避免更昂贵的
get_json_object
s(内存方面)

(我使用的是Scala,但这并不重要,只是它更接近于“裸机”)

您可能已经注意到,物理查询计划使用两个不同的
get#u json_object
表达式(一个带有
#10
,另一个带有
#11
唯一标识符)

get_json_object
只是一个隐藏在幕后的催化剂表达式,而方法就是所有神奇之处

在某个时刻,eval执行
CreateJacksonParser.utf8String(jsonFactory,jsonStr)
。它使用了这个
jsonFactory
值,这个值恰好在任何Java/Python/Scala/JVM代码中共享,因为它是
val
的一部分。在Scala中,关键字
object
给出了Spark执行器(单个JVM)上所有任务的单个实例。这当然是共享实例,但这只是一个工厂(不是JSON解析器本身)

我的理解是,每次请求一个新的JSON解析器时,都会创建一个新的JSON解析器(可能是因为它是一个可变的“野兽”)。你得看看杰克逊的才能知道

{<function _method_b at 0x7f43d7dc4200>: 0.15471874809265138,
 <function _method_a at 0x7f43d7dc4320>: 0.14935027599334716}
// let's use a very simple query to demo the concept
val q = sql("""SELECT get_json_object('{"a":"b"}', '$.a'), get_json_object('{"aa":"bb"}', '$.aa')""")
scala> q.explain
== Physical Plan ==
*(1) Project [b AS get_json_object({"a":"b"}, $.a)#10, bb AS get_json_object({"aa":"bb"}, $.aa)#11]
+- *(1) Scan OneRowRelation[]