Apache spark Spark:从RDD到本地机器检索大数据的最佳实践

Apache spark Spark:从RDD到本地机器检索大数据的最佳实践,apache-spark,Apache Spark,我有一个大的RDD(1gb)的纱线集群。在使用此群集的本地计算机上,我只有512MB。我想在本地机器上迭代RDD中的值。我不能使用collect(),因为它会在本地创建太大的数组,这比我的堆还要大。我需要一些迭代的方法。有方法iterator(),但它需要一些额外的信息,我无法提供 UDP:Committed ToLocalitor方法使用Spark映射/过滤/减少并稍后下载结果?我认为通常的Hadoop方法会奏效 Api说有map-filter-saveAsFile命令:使用Spark映射/f

我有一个大的RDD(1gb)的纱线集群。在使用此群集的本地计算机上,我只有512MB。我想在本地机器上迭代RDD中的值。我不能使用collect(),因为它会在本地创建太大的数组,这比我的堆还要大。我需要一些迭代的方法。有方法iterator(),但它需要一些额外的信息,我无法提供


UDP:Committed ToLocalitor方法

使用Spark映射/过滤/减少并稍后下载结果?我认为通常的Hadoop方法会奏效


Api说有map-filter-saveAsFile命令:

使用Spark映射/filter/reduce并稍后下载结果?我认为通常的Hadoop方法会奏效


Api说有map-filter-saveAsFile命令:

更新:
RDD。编写原始答案后出现的ToLocalitator方法是一种更有效的方法。它使用
runJob
在每个步骤上只计算一个分区

TL;DR最初的答案可能会给出一个大致的工作原理:

首先,获取分区索引数组:

val parts=rdd.partitions
然后创建较小的RDD,过滤掉除单个分区之外的所有内容。从较小的RDD收集数据,并迭代单个分区的值:

for(p if(a._1==idx)a._2else迭代器(),true)
//第二个参数为true,以避免rdd改组
val data=partRdd.collect//数据包含单个分区中的所有值
//以数组的形式
//现在,您可以随意处理数据:迭代、保存到文件等。
}

我没有尝试这个代码,但它应该可以工作。如果无法编译,请写一条评论。当然,它只有在分区足够小的情况下才能工作。如果没有,您可以使用
rdd增加分区的数量。coalesce(numParts,true)

更新:
rdd。编写原始答案后出现的ToLocalitator
方法是一种更有效的方法。它使用
runJob
在每个步骤上只计算一个分区

TL;DR最初的答案可能会给出一个大致的工作原理:

首先,获取分区索引数组:

val parts=rdd.partitions
然后创建较小的RDD,过滤掉除单个分区之外的所有内容。从较小的RDD收集数据,并迭代单个分区的值:

for(p if(a._1==idx)a._2else迭代器(),true)
//第二个参数为true,以避免rdd改组
val data=partRdd.collect//数据包含单个分区中的所有值
//以数组的形式
//现在,您可以随意处理数据:迭代、保存到文件等。
}

我没有尝试这个代码,但它应该可以工作。如果无法编译,请写一条评论。当然,它只有在分区足够小的情况下才能工作。如果没有,您可以使用rdd.coalesce(numParts,true)

增加分区的数量,Wildfire的答案在语义上似乎是正确的,但我相信使用Spark的API应该可以大大提高效率。如果您想依次处理每个分区,我不明白为什么不能使用
map
/
过滤器
/
减少
/
减少
/
/
映射分区
操作。你唯一想让所有东西都在一个数组中的一个地方的时候,就是你要执行一个非幺半体操作的时候——但这似乎不是你想要的。您应该能够执行以下操作:

rdd.mapPartitions(recordsIterator => your code that processes a single chunk)
还是这个

rdd.foreachPartition(partition => {
  partition.toArray
  // Your code
})

Wildfire的答案在语义上似乎是正确的,但我相信通过使用Spark的API,您应该能够大大提高效率。如果您想依次处理每个分区,我不明白为什么不能使用
map
/
过滤器
/
减少
/
减少
/
/
映射分区
操作。你唯一想让所有东西都在一个数组中的一个地方的时候,就是你要执行一个非幺半体操作的时候——但这似乎不是你想要的。您应该能够执行以下操作:

rdd.mapPartitions(recordsIterator => your code that processes a single chunk)
还是这个

rdd.foreachPartition(partition => {
  partition.toArray
  // Your code
})

对于Spark 1.3.1,格式如下

val parts = rdd.partitions
    for (p <- parts) {
        val idx = p.index
        val partRdd = data.mapPartitionsWithIndex { 
           case(index:Int,value:Iterator[(String,String,Float)]) => 
             if (index == idx) value else Iterator()}
        val dataPartitioned = partRdd.collect 
        //Apply further processing on data                      
    }
val parts=rdd.partitions
对于(p
if(index==idx)值else迭代器()}
val dataPartitioned=partRdd.collect
//对数据进行进一步处理
}

对于Spark 1.3.1,格式如下

val parts = rdd.partitions
    for (p <- parts) {
        val idx = p.index
        val partRdd = data.mapPartitionsWithIndex { 
           case(index:Int,value:Iterator[(String,String,Float)]) => 
             if (index == idx) value else Iterator()}
        val dataPartitioned = partRdd.collect 
        //Apply further processing on data                      
    }
val parts=rdd.partitions
对于(p
if(index==idx)值else迭代器()}
val dataPartitioned=partRdd.collect
//对数据进行进一步处理
}

这里的方法与@widlife的方法相同,但是是用pyspark编写的

这种方法的好处是,它允许用户按顺序访问RDD中的记录。我使用这段代码将RDD中的数据输入机器学习工具进程的STDIN中

rdd = sc.parallelize(range(100), 10)
def make_part_filter(index):
    def part_filter(split_index, iterator):
        if split_index == index:
            for el in iterator:
                yield el
    return part_filter

for part_id in range(rdd.getNumPartitions()):
    part_rdd = rdd.mapPartitionsWithIndex(make_part_filter(part_id), True)
    data_from_part_rdd = part_rdd.collect()
    print "partition id: %s elements: %s" % (part_id, data_from_part_rdd)
产生输出:

partition id: 0 elements: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
partition id: 1 elements: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
partition id: 2 elements: [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
partition id: 3 elements: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
partition id: 4 elements: [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
partition id: 5 elements: [50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
partition id: 6 elements: [60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
partition id: 7 elements: [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
partition id: 8 elements: [80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
partition id: 9 elements: [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

这里的方法与@widlife相同,但是是用pyspark编写的

这种方法的好处是,它允许用户按顺序访问RDD中的记录。我使用这段代码将RDD中的数据输入机器学习工具进程的STDIN中

rdd = sc.parallelize(range(100), 10)
def make_part_filter(index):
    def part_filter(split_index, iterator):
        if split_index == index:
            for el in iterator:
                yield el
    return part_filter

for part_id in range(rdd.getNumPartitions()):
    part_rdd = rdd.mapPartitionsWithIndex(make_part_filter(part_id), True)
    data_from_part_rdd = part_rdd.collect()
    print "partition id: %s elements: %s" % (part_id, data_from_part_rdd)
产生输出:

partition id: 0 elements: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
partition id: 1 elements: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
partition id: 2 elements: [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
partition id: 3 elements: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
partition id: 4 elements: [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
partition id: 5 elements: [50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
partition id: 6 elements: [60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
partition id: 7 elements: [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
partition id: 8 elements: [80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
partition id: 9 elements: [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

pyspark数据帧解决方案使用:

分隔符='|'
df_results=hiveCtx.sql(sql)
columns=df_results.columns
打印分隔符.连接(列)
#使用toLocalitator()而不是collect(),因为这样可以避免拉取所有
#相反,“迭代器将消耗同样多的内存
#作为此RDD中最大的分区。”
最大缓冲行计数=10000
行计数=0
输出=cS