全国职业院校技能大赛-大数据应用赛项-数据挖掘-01

子任务一:特征工程
剔除订单信息表与订单详细信息表中用户id与商品id不存在现有的维表中的记录,同时建议多利用缓存并充分考虑并行度来优化代码,达到更快的计算效果。1、根据Hive的dwd库中相关表或MySQL中shtd_store中相关表(order_detail、sku_info),计算出与用户id为6708的用户所购买相同商品种类最多的前10位用户(只考虑他俩购买过多少种相同的商品,不考虑相同的商品买了多少次),将10位用户id进行输出,若与多个用户购买的商品种类相同,则输出结果按照用户id升序排序,输出格式如下,将结果截图粘贴至客户端桌面【Release\任务C提交结果.docx】中对应的任务序号下;
结果格式如下:
-------------------相同种类前10的id结果展示为:--------------------
1,2,901,4,5,21,32,91,14,52
 

 def main(args: Array[String]): Unit = {
   val spark: SparkSession = sparkSessionUtils.getSession
   import spark.implicits._

   val order_detail: DataFrame = mysqlUtils.read(spark, "ds_db01", "order_detail")
   val order_info: DataFrame = mysqlUtils.read(spark, "ds_db01", "order_info")

//    根据order_id连接起来,查出每个用户购买的商品并去重
   val data: Dataset[Row] = order_detail.join(order_info, order_detail("order_id") === order_info("id"))
     .select("user_id", "sku_id")
     .distinct()

//    6708用户所购买的商品
   val user6708_skuids: Array[Int] = data.filter(col("user_id") === 6708).select("sku_id").map((_: Row) (0).toString.toInt).collect()

   val user_ids: String = data.withColumn("cos", when(col("sku_id").isin(user6708_skuids: _*), 1.0).otherwise(0.0))
   .groupBy("user_id")
     .agg(sum("cos").as("same"))
     .filter(col("user_id") !== 6708)
   .orderBy(desc("same"), asc("user_id"))
     .limit(10)
     .map((_: Row) (0).toString)
     .collect()
     .mkString(",")

val str = user_ids.map(_(0).toString)
 .collect()
 .mkString(",")

println("-------------------相同种类前10的id结果展示为:--------------------")
println(str)

   
   sparkSessionUtils.close(spark)
 }

2、根据Hive的dwd库中相关表或MySQL中shtd_store中相关商品表(sku_info),获取id、spu_id、price、weight、tm_id、category3_id 这六个字段并进行数据预处理,对price、weight进行规范化(StandardScaler)处理,对spu_id、tm_id、category3_id进行one-hot编码处理(若该商品属于该品牌则置为1,否则置为0),并按照id进行升序排序,在集群中输出第一条数据前10列(无需展示字段名),将结果截图粘贴至客户端桌面【Release\任务C提交结果.docx】中对应的任务序号下。

字段

类型

中文含义

备注

id

double

主键

price

double

价格

weight

double

重量

spu_id#1

double

spu_id 1

若属于该spu_id,则内容为1否则为0

spu_id#2

double

spu_id 2

若属于该spu_id,则内容为1否则为0

.....

double

tm_id#1

double

品牌1

若属于该品牌,则内容为1否则为0

tm_id#2

double

品牌2

若属于该品牌,则内容为1否则为0

……

double

category3_id#1

double

分类级别3 1

若属于该分类级别3,则内容为1否则为0

category3_id#2

double

分类级别3 2

若属于该分类级别3,则内容为1否则为0

……

结果格式如下:
--------------------第一条数据前10列结果展示为:---------------------
1.0,0.892346,1.72568,0.0,0.0,0.0,0.0,1.0,0.0,0.0

def main(args: Array[String]): Unit = {
   val spark = sparkSessionUtils.getSession

   val windowSpec1: WindowSpec = Window.orderBy("spu_id")
   val windowSpec2: WindowSpec = Window.orderBy("tm_id")
   val windowSpec3: WindowSpec = Window.orderBy("category3_id")

   val source: DataFrame = mysqlUtils.read(spark, "ds_db01", "sku_info")
     .select("id", "spu_id", "price", "weight", "tm_id", "category3_id")
     .withColumn("spu_id_index", dense_rank().over(windowSpec1) - 1)
     .withColumn("tm_id_index", dense_rank().over(windowSpec2) - 1)
     .withColumn("category3_id_index", dense_rank().over(windowSpec3) - 1)

   source.show()
   val df = source.write.saveAsTable("dwd.sku_info_vector")

   val hotEncoder: OneHotEncoder = new OneHotEncoder()
     .setInputCols(Array("spu_id_index", "tm_id_index", "category3_id_index"))
     .setOutputCols(Array("spu_id_hot", "tm_id_hot", "category3_id_hot"))
     .setDropLast(false)

   val vectorAssembler1: VectorAssembler = new VectorAssembler()
     .setInputCols(Array("price"))
     .setOutputCol("price_v")

   val vectorAssembler2: VectorAssembler = new VectorAssembler()
     .setInputCols(Array("weight"))
     .setOutputCol("weight_v")

   val standardScaler1: StandardScaler = new StandardScaler()
     .setInputCol("price_v")
     .setOutputCol("price_sca")
     .setWithMean(true)

   val standardScaler2: StandardScaler = new StandardScaler()
     .setInputCol("weight_v")
     .setOutputCol("weight_sca")
     .setWithMean(true)

   val pipelineModel: PipelineModel = new Pipeline()
     .setStages(Array(vectorAssembler1, vectorAssembler2, standardScaler1, standardScaler2, hotEncoder))
     .fit(source)

   spark.udf.register("vectorToArray", (v1: SparseVector) => {
     v1.toArray.mkString(",")
   })

   spark.udf.register("vectorToDouble", (v1: DenseVector) => {
     v1.apply(0)
   })

   val result = pipelineModel.transform(source)
     .withColumn("spu_id_hot", expr("vectorToArray(spu_id_hot)"))
     .withColumn("tm_id_hot", expr("vectorToArray(tm_id_hot)"))
     .withColumn("category3_id_hot", expr("vectorToArray(category3_id_hot)"))
     .withColumn("price_sca", expr("vectorToDouble(price_sca)"))
     .withColumn("weight_sca", expr("vectorToDouble(weight_sca)"))
     .select("id", "price_sca", "weight_sca", "spu_id_hot", "tm_id_hot", "category3_id_hot")
     .orderBy(asc("id"))
     .limit(1)

println("--------------------第一条数据前10列结果展示为:---------------------")
result.collect().foreach(r => {
 println(r.toSeq.flatMap(r => r.toString.split(",")).take(10).mkString(","))
})


   sparkSessionUtils.close(spark)
 }


子任务二:推荐系统
1、根据子任务一的结果,计算出与用户id为6708的用户所购买相同商品种类最多的前10位用户id(只考虑他俩购买过多少种相同的商品,不考虑相同的商品买了多少次),并根据Hive的dwd库中相关表或MySQL数据库shtd_store中相关表,获取到这10位用户已购买过的商品,并剔除用户6708已购买的商品,通过计算这10位用户已购买的商品(剔除用户6708已购买的商品)与用户6708已购买的商品数据集中商品的余弦相似度累加再求均值,输出均值前5商品id作为推荐使用,将执行结果截图粘贴至客户端桌面【Release\任务C提交结果.docx】中对应的任务序号下。

结果格式如下:
------------------------推荐Top5结果如下------------------------
相似度top1(商品id:1,平均相似度:0.983456)
相似度top2(商品id:71,平均相似度:0.782672)
相似度top3(商品id:22,平均相似度:0.7635246)
相似度top4(商品id:351,平均相似度:0.7335748)
相似度top5(商品id:14,平均相似度:0.522356)
 

 def main(args: Array[String]): Unit = {
   val spark = sparkSessionUtils.getSession
   val order_detail = mysqlUtils.read(spark, "ds_db01", "order_detail_copy1")
   val order_info = mysqlUtils.read(spark, "ds_db01", "order_info")
//  找出每个用户所购买的商品
   val user_buy_sku = order_detail.join(order_info, order_detail("order_id") === order_info("id"))
     .select("user_id", "sku_id")
     // 题目要求不考虑同一个商品多次购买的情况所以需要去重
     .distinct()

   user_buy_sku.show()

   import spark.implicits._
//  找出用户6708所购买的商品
   val user_6708_sku_ids: Array[Double] = user_buy_sku
     .filter(col("user_id") === 2790)
     .select("sku_id")
     .map(_(0).toString.toDouble)
     .collect()

   println(user_6708_sku_ids.mkString(","))
//  找出与用户6708所购买的相同商品最多的前10位用户
   val other_10_user_ids = user_buy_sku
     .filter(col("user_id") !== 2790)
     .withColumn("is_cos", when(col("sku_id").cast(DoubleType).isin(user_6708_sku_ids: _*), 1).otherwise(0))
     .groupBy(col("user_id"))
     .agg(sum("is_cos").as("count_cos"))
     .orderBy(col("count_cos").desc)
     .select("user_id")
     .map(_(0).toString.toLong)
     .limit(10)
     .collect()

   println(other_10_user_ids.mkString(","))
//  找出相似度最高的前10位用户所购买的商品
   val other_10_sku_ids = user_buy_sku.filter(col("user_id").isin(other_10_user_ids: _*))
     .select("sku_id")
     .map(_(0).toString.toDouble)
     .collect()

   println(other_10_sku_ids.mkString(","))
//  读取上题商品的特征向量表并将除id列的其他列转换为向量/ mysql中的sku_info表
   val sku_info_vector = spark.table("dwd.sku_info_vector")
   println("---------------------")
   sku_info_vector.show()

//    val sku_info_vector = mysqlUtils.read(spark,"ds_db01","sku_info")
//  将数据进行标准化
   val vectorAssembler = new VectorAssembler()
     .setInputCols(sku_info_vector.columns.tail)
     .setOutputCol("features")
   val dataFrame = new Pipeline()
     .setStages(Array(vectorAssembler))
     .fit(sku_info_vector)
     .transform(sku_info_vector)
   println("+++++++++++++++++++++")
   dataFrame.show()

   val mapData = dataFrame
     .select("id", "features")
     .map(r => {
       LabeledPoint(r(0).toString.toInt, r(1).asInstanceOf[linalg.Vector])
     })
   println(s"mapData ----------------------------")
   mapData.show()

   val normalizer = new Normalizer()
     .setInputCol("features")
     .setOutputCol("norm_features")
     .setP(2.0)

   val normalized_data = normalizer
     .transform(mapData)
     .select("label", "norm_features")

   normalized_data.show()
//  定义余弦相似度udf函数
   spark.udf.register("cos", (v1: DenseVector, v2: DenseVector) => {
     1 - breeze.linalg.functions.cosineDistance(breeze.linalg.DenseVector(v1.values), breeze.linalg.DenseVector(v2.values))
   })

//    注册自定义的余弦相似度udf,前提是的
//    def cosineSimilarity(v1: DenseVector, v2: DenseVector): Double = {
//      1 - cosineDistance(breeze.linalg.DenseVector(v1.values), breeze.linalg.DenseVector(v2.values))
//    }

//  将数据进行条件自连接并根据余弦相似度算出最高的5个商品输出
   val result = normalized_data.crossJoin(normalized_data)
     .toDF("left_label", "left_norm_vector", "right_label", "right_norm_vector")
     .filter(col("left_label") !== col("right_label"))
     .withColumn("cos", expr("cos(left_norm_vector,right_norm_vector)"))
     .orderBy(desc("cos"))
     // left_label 用户购买的   right_label 其他用户购买的并剔除指定用户购买
     .filter(col("left_label").isin(user_6708_sku_ids: _*))
     .filter(!col("right_label").isin(user_6708_sku_ids: _*) && col("right_label").isin(other_10_sku_ids: _*))  //完成了剔除
     .groupBy("right_label")
     .agg(avg("cos").as("cos"))
     .orderBy(desc("cos"))
     .limit(5)

println("------------------------推荐Top5结果如下------------------------")
result.collect().zipWithIndex.foreach {
 case (row, index) =>
   val right_label = row.getAs[Double]("right_label").toInt
   val cos = row.getAs[Double]("cos")
   val output = s"相似度top${index + 1} (商品id:$right_label,平均相似度:$cos)" 
   println(output)
}

  sparkSessionUtils.close(spark)
 }

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值