Spark和Python使用自定义文件格式/生成器作为RDD的输入
我想问一下Spark中的输入可能性。我可以从中看出,我可以使用Spark和Python使用自定义文件格式/生成器作为RDD的输入,python,hadoop,apache-spark,Python,Hadoop,Apache Spark,我想问一下Spark中的输入可能性。我可以从中看出,我可以使用sc.textFile()将文本文件读取到RDD,但我想在分发到RDD之前做一些预处理,例如,我的文件可能是JSON格式的,例如{id:123,text:“…”,value:6}我只想使用JSON的某些字段进行进一步处理 我的想法是,是否有可能以某种方式使用Python生成器作为SparkContext的输入 或者,如果Spark中有更自然的方式来处理自定义文件,而不是Spark的纯文本文件 编辑: 似乎接受的答案应该是可行的,但这让
sc.textFile()
将文本文件读取到RDD,但我想在分发到RDD之前做一些预处理,例如,我的文件可能是JSON格式的,例如{id:123,text:“…”,value:6}
我只想使用JSON的某些字段进行进一步处理
我的想法是,是否有可能以某种方式使用Python生成器作为SparkContext的输入
或者,如果Spark中有更自然的方式来处理自定义文件,而不是Spark的纯文本文件
编辑:
似乎接受的答案应该是可行的,但这让我想到了下面更实际的问题是的,您可以使用
SparkContext.parallelize()从python变量创建RDD:
此变量也可以是迭代器。最快的方法可能是按原样加载文本文件,并进行处理以在生成的RDD上选择所需的字段。这将使整个集群的工作并行化,并且比在一台机器上进行任何预处理更有效地扩展
对于JSON(甚至XML),我认为您不需要自定义输入格式。由于PySpark在Python环境中执行,因此可以使用Python中经常提供的函数来反序列化JSON并提取所需的字段
例如:
import json
raw = sc.textFile("/path/to/file.json")
deserialized = raw.map(lambda x: json.loads(x))
desired_fields = deserialized.map(lambda x: x['key1'])
required_fields
现在是原始JSON文件中key1
下所有值的RDD
您可以使用此模式提取字段的组合、按空格分割字段或其他方式
desired_fields = deserialized.map(lambda x: (x['key1'] + x['key2']).split(' '))
如果这变得太复杂,您可以用一个常规Python函数替换lambda
,该函数可以执行您想要的所有预处理,只需调用deserialized.map(my_preprocessing_func)
就可以将JSON加载到RDD中,然后在RDD上进行处理,以仅过滤您需要的数据。这样做的好处是,这种“预处理”类型的工作可以在Spark集群中并行化。你能举一个例子说明你想先做什么样的处理吗?通过预处理,我的主要意思是我只想从JSON或XML中选择例如字段text1,text2,然后我可以做一些事情,比如用空格分割它并将其保存为文本文件。我看不到任何解析JSON RDD的自然方法。现在,我只能考虑将JSON或XML作为sc.textFile()文件进行处理,只要看到所需的键,就使用以下字符串。那是你的意思吗?是的,我想我对你想做的事有感觉。如果我误解了,请评论我的答案。我正在尝试实现并运行这个示例,所以我会在我成功后尽快让您知道这是否对我有效。我现在很惊讶这真的能起作用,因为例如,我的JSON可能比所有机器的RAM内存都大,所以我希望一次只加载一部分,因此JSON.loads(x)只会得到一部分,它将无法正确解析它?实际上这应该能起作用,但这让我想到了@ziky90中的一个特别的后续问题:“我的JSON可能比所有机器的RAM内存都大”,这不应该是一个问题。如果源数据集中每行有一个JSON对象,Spark将能够很好地处理它,即使数据集很大。即使您尝试缓存数据集,Spark也会尽可能多地缓存数据,并处理磁盘中的其余数据。不幸的是,当生成器生成的列表大于RAM内存时,这将不起作用,因为Spark会在内部将生成器转换为列表。你对这里的解决办法有什么想法吗?我担心情况会是这样。很抱歉,除了在Spark中进行所有处理或尝试修补源代码之外,我不知道如何进一步处理。
desired_fields = deserialized.map(lambda x: (x['key1'] + x['key2']).split(' '))