如何通过spark dataframe api

时间:2016-05-30 10:02:43

标签: apache-spark cassandra datastax datastax-enterprise

这是我的spark应用程序的一部分。第一部分是我在过去1小时内获得所有文章的部分,代码的第二部分抓取所有这些文章的评论。第三部分将评论添加到文章中。 问题是articles.map(lambda x:(x.id,x.id)).join(axes)部分太慢,大约需要1分钟。我想把它提高到10秒甚至更短但不知道怎么做?谢谢你的回复。

articles = sqlContext.read.format("org.apache.spark.sql.cassandra").options(table="articles", keyspace=source).load() \
                        .map(lambda x:x).filter(lambda x:x.created_at!=None).filter(lambda x:x.created_at>=datetime.now()-timedelta(hours=1) and x.created_at<=datetime.now()-timedelta(hours=0)).cache()

axes = sqlContext.read.format("org.apache.spark.sql.cassandra").options(table="axes", keyspace=source).load().map(lambda x:(x.article,x))

speed_rdd = articles.map(lambda x:(x.id,x.id)).join(axes)

修改

这是我的新代码,我根据您的建议进行了更改。它现在已经是以前的2倍,所以谢谢你;)。我想用轴部分的代码的最后一部分进行另一项改进,这仍然太慢,需要38秒才能获得3000万个数据:

range_expr = col("created_at").between(
                            datetime.now()-timedelta(hours=timespan),
                            datetime.now()-timedelta(hours=time_delta(timespan))
                        )
        article_ids = sqlContext.read.format("org.apache.spark.sql.cassandra").options(table="article_by_created_at", keyspace=source).load().where(range_expr).select('article','created_at').persist()


        axes = sqlContext.read.format("org.apache.spark.sql.cassandra").options(table="axes", keyspace=source).load()

我在这里尝试了这个(它应该替换我的代码的最后一个轴部分),这也是我想要的解决方案,但它似乎没有正常工作:

in_expr = col("article").isin(article_ids.collect())
        axes = sqlContext.read.format("org.apache.spark.sql.cassandra").options(table="axes", keyspace=source).load().where(in_expr)

我总是收到此错误消息:

in_expr = col("article").isin(article_ids.collect())
Traceback (most recent call last):                                              
  File "<stdin>", line 1, in <module>
TypeError: 'Column' object is not callable

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

1)只要在Cassandra中进行过滤(使用主键进行过滤或二级索引),Spark-Cassandra连接器就会自动检测谓词下推:https://github.com/datastax/spark-cassandra-connector/blob/master/doc/14_data_frames.md#pushing-down-clauses-to-cassandra

2)对于更有效的连接,您可以调用方法repartitionByCassandraReplica。不幸的是,这种方法可能不适用于PySpark,仅适用于Scala / Java API。请阅读此处的文档:https://github.com/datastax/spark-cassandra-connector/blob/master/doc/2_loading.md#performing-efficient-joins-with-cassandra-tables-since-12

3)另一个提示是尝试调试并了解连接器如何创建Spark分区。文档中提到了一些示例和警告:https://github.com/datastax/spark-cassandra-connector/blob/master/doc/16_partitioning.md

答案 1 :(得分:2)

作为mentioned before,如果您想获得合理的效果,请不要将您的数据转换为RDD。它不仅不会使谓词下推等优化变得不可能,而且还会带来将数据从JVM迁移到Python的巨大开销。

相反,您应该以类似于此的方式使用SQL表达式/ DataFrame API:

from pyspark.sql.functions import col, expr, current_timestamp

range_expr = col("created_at").between(
    current_timestamp() - expr("INTERVAL 1 HOUR"),
    current_timestamp())

articles = (sqlContext.read.format("org.apache.spark.sql.cassandra")
    .options(...).load()
    .where(col("created_at").isNotNull())  # This is not really required
    .where(range_expr))

也应该像以前一样使用标准的Python实用程序来制定谓词表达式:

import datetime

range_expr = col("created_at").between(
    datetime.datetime.now() - datetime.timedelta(hours=1),
    datetime.datetime.now()
)

应该执行后续join而不会将数据移出数据框:

axes = (sqlContext.read.format("org.apache.spark.sql.cassandra")
    .options(...)
    .load())

articles.join(axes, ["id"])