Python 如何使Apache Spark mapPartition正常工作?

Python 如何使Apache Spark mapPartition正常工作?,python,apache-spark,pyspark,Python,Apache Spark,Pyspark,我正在尝试基于每个分区进行一些工作,我希望返回与输入相同的数据: from urllib3 import HTTPConnectionPool rdd = sc.parallelize(["peter", "john", "harris"]) def sendPartition(iterator): pool = HTTPConnectionPool('ajax.googleapis.com', maxsize=10) for record in iterator:

我正在尝试基于每个分区进行一些工作,我希望返回与输入相同的数据:

from urllib3 import HTTPConnectionPool

rdd = sc.parallelize(["peter", "john", "harris"])
def sendPartition(iterator):
    pool = HTTPConnectionPool('ajax.googleapis.com', maxsize=10)

    for record in iterator:
        r = pool.request('GET', '/ajax/services/search/web', fields={'q': 'urllib3', 'v': '1.0'})

    return iterator


rdd.mapPartitions(sendPartition).count()
我得到这个错误:

TypeError:“非类型”对象不可编辑

附言:这只是我试图实现的目标的简化。我想对每个元素执行复杂的geosearch请求ElasticSearch(因此我无法使用Spark ElasticSearch连接器)。在这个映射分区之前,我有大量的过滤器、映射等管道


PPS:我重新启动了我的spark,现在我得到了“0”作为输出,这比一个错误要好,但是我希望它是“3”。

关于类型错误,它看起来不能使用问题中包含的代码进行复制。我猜在某个时刻,
None
值要么被传递到
RDD
构造函数,要么从
sendPartition
返回

将空RDD作为输出的问题是使用分区迭代器方式的结果。PySpark正在使用
itertools.chain
将数据传递给
mapPartition
,其行为与Scala
迭代器的行为大致相同

import itertools

iter = itertools.chain(range(10))
iter.next()
## 0
完成
for
循环后

for x in iter:
    x
您将得到一个空的

type(iter)
## itertools.chain

iter.nex()
## Traceback (most recent call last)
##     ...
## StopIteration:
虽然
StopIteration
作为正常迭代逻辑的一部分进行处理,但没有要返回的数据

有几种方法可以处理这个问题,最干净的方法是提取函数并使用列表理解

def make_request(record, pool):
    r = pool.request('GET', '/ajax/services/search/web',
        fields={'q': 'urllib3', 'v': '1.0'})
    return r.read() # Or any other data you need.

def sendPartition(iterator):
    pool = HTTPConnectionPool('ajax.googleapis.com', maxsize=10)
    return [make_request(record, pool) for record in iterator]

请注意,如果要使用连接池,必须在退出
mapPartitions
之前读取数据。这意味着没有惰性计算(如生成器)。就个人而言,我会考虑异步请求(例如,在< 3.5)、“RXPY”中,在退出之前分区和评估中的异步请求(例如“代码> AycN/Acto/<代码> >”。

< p>关于类型错误,它看起来不象它可以使用包含在问题中的代码来重放。我猜在某个时刻,
None
值要么被传递到
RDD
构造函数,要么从
sendPartition
返回

将空RDD作为输出的问题是使用分区迭代器方式的结果。PySpark正在使用
itertools.chain
将数据传递给
mapPartition
,其行为与Scala
迭代器的行为大致相同

import itertools

iter = itertools.chain(range(10))
iter.next()
## 0
完成
for
循环后

for x in iter:
    x
您将得到一个空的

type(iter)
## itertools.chain

iter.nex()
## Traceback (most recent call last)
##     ...
## StopIteration:
虽然
StopIteration
作为正常迭代逻辑的一部分进行处理,但没有要返回的数据

有几种方法可以处理这个问题,最干净的方法是提取函数并使用列表理解

def make_request(record, pool):
    r = pool.request('GET', '/ajax/services/search/web',
        fields={'q': 'urllib3', 'v': '1.0'})
    return r.read() # Or any other data you need.

def sendPartition(iterator):
    pool = HTTPConnectionPool('ajax.googleapis.com', maxsize=10)
    return [make_request(record, pool) for record in iterator]

请注意,如果要使用连接池,必须在退出
mapPartitions
之前读取数据。这意味着没有惰性计算(如生成器)。就个人而言,我会考虑异步请求(例如,在<>代码> Aycc/Acto/<代码> 3.5,RXPY别处),在退出之前进行分区和评估。< /P>请提供一个可重复的例子。无法用您提供的代码重现问题。如果我不得不猜测代码中的某个点,那么您的代码就相当于
sc.parallelize(None)
。另一方面,Spark不是这样的工具。@zero323我添加了一些细节。据我所知,它在1.3-1.5和当前主机上运行得很好。我重新启动了Spark,现在我得到了“0”作为输出,这比错误要好,但我希望它是“3”:s.输出应该是0。您为每个分区返回一个空链。请提供一个可复制的示例。无法用您提供的代码重现问题。如果我不得不猜测代码中的某个点,那么您的代码就相当于
sc.parallelize(None)
。另一方面,Spark不是这样的工具。@zero323我添加了一些细节。据我所知,它在1.3-1.5和当前主机上运行得很好。我重新启动了Spark,现在我得到了“0”作为输出,这比错误要好,但我希望它是“3”:s.输出应该是0。为每个分区返回一个空链。