Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 计算每个键的唯一值的有效方法_Python_Apache Spark_Pyspark - Fatal编程技术网

Python 计算每个键的唯一值的有效方法

Python 计算每个键的唯一值的有效方法,python,apache-spark,pyspark,Python,Apache Spark,Pyspark,我有一个成员列表,其中有许多属性,其中两个是名称和ID。我希望在RDD中得到一个元组列表。元组将包含作为第一个元素的ID,以及作为第二个元素的与ID相关联的unique名称计数 e、 例如:ID, 以下是我为完成此任务而编写的代码: IDnametuple = members.map(lambda a: (a.ID, a.name)) # extract only ID and name idnamelist = IDnametuple.groupByKey()

我有一个成员列表,其中有许多属性,其中两个是名称和ID。我希望在RDD中得到一个元组列表。元组将包含作为第一个元素的
ID
,以及作为第二个元素的与ID相关联的
unique
名称计数

e、 例如:
ID,

以下是我为完成此任务而编写的代码:

IDnametuple = members.map(lambda a: (a.ID, a.name))   # extract only ID and name
idnamelist = IDnametuple.groupByKey()                 # group the IDs together 
idnameunique_count = (idnamelist
     # set(tup[1]) should extract unique elements, 
     # and len should tell the number of them
    .map(lambda tup: (tup[0], len(set(tup[1]))))) 
它非常慢,而且比为每个成员计算唯一属性的类似操作慢得多


有没有更快的方法?据我所知,我尝试使用尽可能多的内置程序,这是加快速度的正确方法

没有任何细节,我们只能猜测,但显而易见的选择是
groupByKey
。如果每个id都与大量名称相关联,那么由于大量的洗牌,它可能会非常昂贵。最简单的改进是
aggregateByKey
combineByKey

create\u combiner=set
def合并_值(acc,x):
附件增补(x)
返回acc
def合并器(acc1、acc2):
acc1.更新(acc2)
返回acc1
id_name_unique_count=(id_name_tuple#保持一致的命名约定
.combineByKey(创建合并器、合并值、合并合并器)
.mapValues(len))
如果唯一值的预期数量较大,则您可能更愿意替换近似值的精确方法。一种可能的方法是使用Bloom filter来跟踪唯一值,而不是
set

有关
groupByKey
vs
aggregateByKey
reduceebykey
combineByKey
)的更多信息,请参阅:


    • 没有任何细节,我们只能猜测,但显而易见的选择是
      groupByKey
      。如果每个id都与大量名称相关联,那么由于大量的洗牌,它可能会非常昂贵。最简单的改进是
      aggregateByKey
      combineByKey

      create\u combiner=set
      def合并_值(acc,x):
      附件增补(x)
      返回acc
      def合并器(acc1、acc2):
      acc1.更新(acc2)
      返回acc1
      id_name_unique_count=(id_name_tuple#保持一致的命名约定
      .combineByKey(创建合并器、合并值、合并合并器)
      .mapValues(len))
      
      如果唯一值的预期数量较大,则您可能更愿意替换近似值的精确方法。一种可能的方法是使用Bloom filter来跟踪唯一值,而不是
      set

      有关
      groupByKey
      vs
      aggregateByKey
      reduceebykey
      combineByKey
      )的更多信息,请参阅:


      这基本上是计算不同键值对的字数示例:

      from operator import add
      IDnametuple = sc.parallelize([(0, "a"),(0, "a"),(0, "b"),(1, "a"),(1, "b"),(1, "c"),(2, "z")])
      idnameunique_count = (IDnametuple.distinct()
                                        .map(lambda idName : (idName[0], 1))
                                        .reduceByKey(add))
      

      因此
      idnameunique\u count.collect()
      返回
      [(0,2)、(1,3)、(2,1)]
      ,其中
      (0,a”)
      仅计数一次。正如@zero323所提到的,这里的键将
      groupByKey
      替换为
      reduceByKey
      ,以避免创建中间名称列表。您所需要的只是名称计数,这是一个小得多的对象,它可能是一个巨大的列表。您的版本还使用
      set()
      在闭包代码中顺序消除重复项,而
      distinct
      作为分布式并行RDD转换执行

      这基本上是计算不同键值对的字数示例:

      from operator import add
      IDnametuple = sc.parallelize([(0, "a"),(0, "a"),(0, "b"),(1, "a"),(1, "b"),(1, "c"),(2, "z")])
      idnameunique_count = (IDnametuple.distinct()
                                        .map(lambda idName : (idName[0], 1))
                                        .reduceByKey(add))
      

      因此
      idnameunique\u count.collect()
      返回
      [(0,2)、(1,3)、(2,1)]
      ,其中
      (0,a”)
      仅计数一次。正如@zero323所提到的,这里的键将
      groupByKey
      替换为
      reduceByKey
      ,以避免创建中间名称列表。您所需要的只是名称计数,这是一个小得多的对象,它可能是一个巨大的列表。您的版本还使用
      set()
      在闭包代码中顺序消除重复项,而
      distinct
      作为分布式并行RDD转换执行

      这种方法有一个问题——它必须洗牌两次。一次获取
      不同的
      值,一次获取
      reduceByKey
      。关于并行性。。。除非键的数量与可用核心的数量相当,否则它与在分组数据上使用集合时完全相同。通过使用集合作为累加器,您只能处理键的唯一值集合位于单个工作进程内存中的数据集。在我的解决方案中,您没有这个限制,因为您只为每个键存储一个数字,如“避免GroupByKey”中所述。您的解决方案基本上是使用集合重新实现groupByKey。我不理解你对密钥和核心之间关系的评论。这就是限制。要执行
      distinct
      ,您必须
      reduceByKey
      ,只有在重复数较大时才会执行。在这种情况下,
      combineByKey
      应该已经减少了数据量。否则,第一个潜在的故障点是洗牌和存储
      ((k,v),null)
      对,这些对必须放入内存中。接下来,您将执行另一次洗牌,这通常需要再次洗牌大部分数据。这是你通过计算得到的部分。关于键核关系。默认情况下,Spark中的每个操作都是按分区顺序进行的。因此,如果散列值的数量足够大,足以填满所有分区,那么就无法提高并行性。关键是这些((k,v),对)不需要放入单个工作进程的内存中,因为它们可以驻留在多个分区中,而这些分区可以托管在多个工作进程中。如果你没有足够的分区,你可以重新分区,你不需要在内存中同时有所有的分区,你也可以添加更多的工人,这就是