如何使用MongoDB中的过滤记录构建Spark数据框?

时间:2016-08-09 09:40:16

标签: mongodb apache-spark mongodb-query pyspark

我的应用程序是使用MongoDB作为平台构建的。 DB中的一个集合具有大量数据,并且已选择通过计算检索和生成分析数据的apache spark。 我已配置Spark Connector for MongoDB与MongoDB进行通信。 我需要使用 pyspark 查询MongoDB集合,并构建一个由mongodb查询的结果集组成的数据框。 请建议我一个合适的解决方案。

2 个答案:

答案 0 :(得分:5)

您可以将数据直接加载到数据框中,如下所示:

# Create the dataframe
df = sqlContext.read.format("com.mongodb.spark.sql.DefaultSource").option("uri", "mongodb://127.0.0.1/mydb.mycoll").load()

# Filter the data via the api
df.filter(people.age > 30)

# Filter via sql
df.registerTempTable("people")
over_thirty = sqlContext.sql("SELECT name, age FROM people WHERE age > 30")

有关详细信息,请参阅Mongo Spark连接器Python API部分或introduction.py。 SQL查询被转换并传递回连接器,以便在发送到spark集群之前可以在MongoDB中查询数据。

您还可以在将结果返回Spark之前提供自己的aggregation pipeline以应用于集合:

dfr = sqlContext.read.option("pipeline", "[{ $match: { name: { $exists: true } } }]")
df = dfr.option("uri", ...).format("com.mongodb.spark.sql.DefaultSource").load()

答案 1 :(得分:0)

对于我来说,过滤没有达到预期的性能,因为所有过滤都是在Spark中发生的,而不是在Mongo中发生的。 为了提高性能,我在加载数据时必须通过手动聚合管道。由于official documentation仅讨论如何使用RDD,因此可能很难找到它。

经过大量的试验,我设法使用Scala数据帧来做到这一点:

val pipeLine =  "[{ $match: { 'data.account.status: 'ACTIVE', " +
      "'data.account.activationDate: {$gte : '2020-10-11', $lte : '2020-10-13'}}}]"

  val readConfig: ReadConfig = ReadConfig(
    Map(
      "uri" -> getMongoURI(),
      "database" -> dataBaseName,
      "collection" -> collection,
      "pipeLine" -> pipeLine
    )
  )

// This one took 260 seconds
val df: DataFrame = MongoSpark.load(sparkSession, readConfig)
df.count()

使用过滤器且不使用管道的替代方法将所有数据提取到Spark。情况并非如此,但我认为这与所使用的查询有关。

  val readConfig: ReadConfig = ReadConfig(
    Map(
      "uri" -> getMongoURI(),
      "database" -> dataBaseName,
      "collection" -> collection
    )
  )
// This one took 560 seconds
val df: DataFrame = MongoSpark.load(sparkSession, readConfig)
df.filter("data.account.status == 'ACTIVE' AND " +
      "data.account.activationDate>= '2020-05-13' AND data.account.activationDate <= '2021-06-05'"
    ).count()

我做了一些测试,从总共持有140万个文档的localhost Mongo DB中获取40万个文档:

  1. (RDD +管道),根据官方文档:144秒
  2. (DF +管道),如上面的示例:260秒
  3. (带有过滤器的DF),如上面的示例:560秒
  4. (RDD +管道).toDf:736秒

由于使用数据框与RDD的其他一些高级好处,我们最终选择了第二个选项。

最后,不要忘记在MongoDB中创建正确的索引!

编辑:我正在使用spark-sql 2.3.1mongo-spark-connector 2.3.2mongo-java-driver 3.12.3