【问题标题】:How to merge two documents into one document by inserting sub-documents on pyspark?如何通过在pyspark上插入子文档将两个文档合并为一个文档?
【发布时间】:2020-09-04 08:00:16
【问题描述】:

我有一个大问题,希望能清楚地解释我想做什么。 我正在尝试在 pyspark (Spark Structured Streaming) 上获取 Stream-Stream 结构,并且我想在从 Kafka 中获取新数据时更新同一个文档。

这些是在本地主机和 MongoCompass 上发送的 JSON 示例:

{
_id: ObjectId("28276465847392747")
id: reply
Company: reply
Value:{

    Date: 20-05-2020
    Last_Hour_Contract: 09.12.25
    Last_Hour: 09.14.30
    Price: 16.08 
    Quantity: 8000 
    Medium_Price: 8.98 
    Min_Price: 8.98 
    Max_Price: 20.33
    News: { id_news: Reply_20-05-20
           title_news: "titolo news"
           text: "text"
           date: 20-05-2020
           hour: 09:13:00
           subject: Reply
        }

     }
}
{
_id: ObjectId("28276465847392747")
id: reply
Company: reply
Value:{

    Date: 20-05-2020
    Last_Hour_Contract: 09.12.25
    Last_Hour: 09.14.30
    Price: 17.78 
    Quantity: 9000 
    Medium_Price: 67.98 
    Min_Price: 8.98 
    Max_Price: 20.33
    News: { id_news: Reply_20-05-20
           title_news: "title_news"
           text: "text"
           date: 20-05-2020
           hour: 09:13:00
           subject: Reply
        }

    }
}

我想要实现的是在新数据到达时将各种文档(基于 Company_Name = "Name_Company")合并到一个文档中。

我想要的JSON文档的设置如下:

{
_id: ObjectId("3333884747656565"),
id: reply
Date: 21-05-2020
Company: Reply
Value:{
    Date: 20-05-2020
    Last_Hour_Contract: 09.12.25
    Last_Hour: 09.14.30
    Price: 16.08
    Quantity: 8000
    Medium_Price: 8.98
    Min_Price: 8.98
    Max_Price: 20.33
    News: {id_news: Reply_20-05-20
           title_news: "title news..."
           text: "text..."
           date: 20-05-2020
           hour: 09:13:00
           subject: Reply
        }
    Date: 21-05-2020    
    Last_Hour_Contract: 09.12.25
    Last_Hour: 09.16.50
    Price: 16.68
    Quantity: 7000
    Medium_Price: 8.98
    Min_Price: 8.98
    Max_Price: 20.33
    News: {id_news: Reply_20-05-20
           title_news: "title news..."
           text: "text..."
           date: 21-05-2020
           hour: 09:14:00
           subject: Reply
        }
   }
}

我还插入了一张图片让你更好地理解(我希望2个箭头可以理解):

如何使用 Pyspark 做到这一点?谢谢

这是我的代码:

def writeStreamer(sdf):
    sdf.select("id_Borsa","NomeAzienda","Valori_Di_Borsa")  \
    .dropDuplicates(["id_Borsa","NomeAzienda","Valori_Di_Borsa"]) \
    .writeStream \
    .outputMode("append") \
    .foreachBatch(foreach_batch_function) \
    .start() 


def foreach_batch_function(sdf, epoch_id):
    sdf.write \
        .format("mongo") \
        .mode("append") \
        .option("spark.mongodb.input.uri", "mongodb://127.0.0.1:27017/DataManagement.Data") \
        .option("spark.mongodb.output.uri", "mongodb://127.0.0.1:27017/DataManagement.Data") \
        .save() #"com.mongodb.spark.sql.DefaultSource"


df_borsa = spark.readStream.format("kafka") \
          .option("kafka.bootstrap.servers", kafka_broker) \
          .option("startingOffsets", "latest") \
          .option("subscribe","Reply_borsa") \
          .load() \
          .selectExpr("CAST(value AS STRING)") 

df_news = spark.readStream.format("kafka") \
          .option("kafka.bootstrap.servers", kafka_broker) \
          .option("startingOffsets", "latest") \
          .option("subscribe","Reply_news") \
          .load() \
          .selectExpr("CAST(value AS STRING)") 


df_borsa = df_borsa.withColumn("Valori_Di_Borsa",F.struct(F.col("Data"),F.col("PrezzoUltimoContratto"),F.col("Var%"),F.col("VarAssoluta"),F.col("OraUltimoContratto"),F.col("QuantitaUltimo"),F.col("QuantitaAcquisto"),F.col("QuantitaVendita"),F.col("QuantitaTotale"),F.col("NumeroContratti"),F.col("MaxOggi"),F.col("MinOggi")))

df_news = df_news.withColumn("News",F.struct(F.col("id_News"),F.col("TitoloNews"),F.col("TestoNews"),F.col("DataNews"),F.col("OraNews")))

# Apply watermarks on event-time columns
dfWithWatermark = df_borsa.select("id_Borsa","NomeAzienda","StartTime","Valori_Di_Borsa").withWatermark("StartTime", "2 hours") # maximal delay

df1WithWatermark = df_news.select("SoggettoNews","EndTime").withWatermark("EndTime", "3 hours") # maximal delay

# Join with event-time constraints
sdf = dfWithWatermark.join(df1WithWatermark,expr(""" 
      SoggettoNews = NomeAzienda AND
      EndTime >= StartTime AND
      EndTime <= StartTime + interval 1 hours
      """),
       "leftOuter").withColumn("Valori_Di_Borsa",F.struct(F.col("Valori_Di_Borsa.*"),F.col("News"))) 


query = writeStreamer(sdf)

spark.streams.awaitAnyTermination()

sdf_printschema():

【问题讨论】:

    标签: mongodb apache-spark pyspark kafka-consumer-api spark-structured-streaming


    【解决方案1】:

    您所要做的就是,使用group 运算符将文档按Company 字段分组,并使用$push 运算符将每个分组文档的value 对象添加到新形成的数组字段values 中.

    所以,上面的 mongo 实现如下:

    db.collection.aggregate([{
        $group: {
            _id: '$Company',
            id: {$first: '$id'},
            date: {$first: '$first'},
            values: {$push: '$value'}
        }
    }])
    

    您可以轻松地将上述聚合转换为 PySpark 实现。

    您需要执行以下操作:

    pipeline = "{'$group': {'_id': '$Company', 'id': {'$first': '$id'}, 'date': {'$first': '$first'}, 'values': {'$push': '$value'}}}"
    df = spark.read.format("mongo").option("pipeline", pipeline).load()
    df.show()
    

    注意:我不是 PySpark 方面的专家,但您可以轻松地将其转换为所需的实现。

    【讨论】:

    • 在 mongocompass 上完美运行!但是在 pyspark 上还没有......我试图在这里的 foreach_batch_function 上插入你的管道但是一旦我输入 MongoCompass 它就会给我返回两个或多个文档
    • 我想和你写的完全一样,但是一旦我进入 MongoCompass 什么都没有发生......我试图在我的代码的不同点插入你的管道但没有。
    • 我比你更不幸。我什至不知道 PySpark。如果你愿意,我会删除这个答案并支持这个问题,这样你就可以从专家那里得到答案?而且,这对我来说也是一个学习。 (不过,我只是引导你)
    • 好的!如果你能做到,你会帮我一个大忙,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2021-08-23
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2021-04-23
    相关资源
    最近更新 更多