使用来自多个RDD的相同密钥提取和保存值的最佳方法

时间:2017-07-21 13:48:17

标签: python apache-spark pyspark

我在PySpark中创建了两个RDD,其数据是从HBase中提取的。我想收集具有相同行键的项目,存储项目,然后搜索与每个项目相关联的值。理想情况下,我将结果存储在pyspark.sql对象中,因为我想将Levenshtein距离应用于其内容。

详细说明:

在HBase中,我有位置数据,其中行键是给定区域的geohash,并且在列中,该区域中有多个场所,位置上有更多详细信息(带有描述和其他文本数据的json)。 我有两个HBase表,两个位置可以相同。我想搜索这两个RDD中的数据,检查类似的地理位置并将结果存储在新的数据结构中。

我不想重新发明轮子而且我刚刚开始学习Spark,因此我想知道:做这项任务的最佳方法是什么?内置函数rdd.intersection是一个很好的解决方案吗?

2 个答案:

答案 0 :(得分:3)

已编辑:实际上,多亏了@ Aneel的评论,我可以纠正一些错误。 实际上对RDD进行join调用会给出相同的结果(连接在RDD的第一列完成,值是两个RDD的其余列的元组),作为调用带有Spark SQL的JOIN放弃,而不是像之前指出的那样执行cogroup,因为@Aneel在一个单独的键下指出了cogroup壁球键值对。

现在另外一点,我尝试了@Aneel的方法,以及上面的要点,并尝试对它进行基准测试,这是结果,使用数据库'社区版(非常小的集群,6GB的内存,1个核心和Spark 2.1),这里是link。 (代码也在帖子的末尾)

结果如下:

  • 对于100000大小的列表:
    • Spark SQL:1.32s
    • RDD加入:0.89s
  • 对于250000大小的列表:
    • Spark SQL:2.2s
    • RDD加入:2.0s
  • 对于500000大小的列表:
    • Spark SQL:3.6s
    • RDD加入:4.6s
  • 对于1000000大小的列表:
    • Spark SQL:7.7s
    • RDD加入:10.2s
  • 对于10000000大小的列表(这里我称timeit只进行10次测试,或者它将在圣诞节前运行。当然精度会降低):
    • Spark SQL:57.6s
    • RDD加入:89.9s

实际上,对于小型数据集来说,RDD似乎比数据帧更快,但是一旦达到阈值(大约250k记录),Dataframes连接开始变得更快

现在正如@Aneel建议的那样,请记住我做了一个非常简单的例子,你可能想对你自己的数据和环境进行一些测试(我的2个列表中没有超过10M行,因为已经花了2.6分钟来初始化。)

初始化代码:

#Init code
NUM_TESTS=100
from random import randint
l1 = []
l2 = []

import timeit
for i in xrange(0, 10000000):
  t = (randint(0,2000), randint(0,2000))
  v = randint(0,2000)
  l1.append((t,v))
  if (randint(0,100) > 25): #at least 25% of the keys should be similar
    t = (randint(0,2000), randint(0,2000))
  v = randint(0,2000)
  l2.append((t,v))

rdd1 = sc.parallelize(l1)
rdd2 = sc.parallelize(l2)

Spark SQL测试:

#Test Spark SQL    
def callable_ssql_timeit():
  df1 = spark.createDataFrame(rdd1).toDF("id", "val")
  df1.createOrReplaceTempView("table1")
  df2 = spark.createDataFrame(rdd2).toDF("id", "val")
  df2.createOrReplaceTempView("table2")
  query="SELECT * FROM table1 JOIN table2 ON table1.id=table2.id"
  spark.sql(query).count()


print(str(timeit.timeit(callable_ssql_timeit, number=NUM_TESTS)/float(NUM_TESTS)) +  "s")

RDD加入测试:

#Test RDD join
def callable_rdd_timeit():
  rdd1.join(rdd2).count()
print(str(timeit.timeit(callable_rdd_timeit, number=NUM_TESTS)/float(NUM_TESTS)) + "s")

答案 1 :(得分:2)

既然你想使用pyspark.sql DataFrames,那么在开始时如何将RDD转换为它们呢?

df1 = spark.createDataFrame(rdd1)
df1.createOrReplaceTempView("table1").toDF("geohash", "other", "data", )
df2 = spark.createDataFrame(rdd2)
df2.createOrReplaceTempView("table2").toDF("geohash", "other", "data", "fields")
spark.sql("SELECT * FROM table1 JOIN table2 ON table1.geohash = table2.geohash").show()

如果要对类似(不相同)的地理位置进行操作,可以注册用户定义的函数来计算它们之间的距离。