离线推荐数据缓存

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


五 离线推荐数据缓存

5.1离线数据缓存之离线召回集

  • 这里主要是利用我们前面训练的ALS模型进行协同过滤召回,但是注意,我们ALS模型召回的是用户最感兴趣的类别,而我们需要的是用户可能感兴趣的广告的集合,因此我们还需要根据召回的类别匹配出对应的广告。

    所以这里我们除了需要我们训练的ALS模型以外,还需要有一个广告和类别的对应关系。

# 从HDFS中加载广告基本信息数据,返回spark dafaframe对象
df = spark.read.csv("hdfs://localhost:9000/data/ad_feature.csv", header=True)

# 注意:由于本数据集中存在NULL字样的数据,无法直接设置schema,只能先将NULL类型的数据处理掉,然后进行类型转换

from pyspark.sql.types import StructType, StructField, IntegerType, FloatType

# 替换掉NULL字符串,替换掉
df = df.replace("NULL", "-1")

# 更改df表结构:更改列类型和列名称
ad_feature_df = df.\
    withColumn("adgroup_id", df.adgroup_id.cast(IntegerType())).withColumnRenamed("adgroup_id", "adgroupId").\
    withColumn("cate_id", df.cate_id.cast(IntegerType())).withColumnRenamed("cate_id", "cateId").\
    withColumn("campaign_id", df.campaign_id.cast(IntegerType())).withColumnRenamed("campaign_id", "campaignId").\
    withColumn("customer", df.customer.cast(IntegerType())).withColumnRenamed("customer", "customerId").\
    withColumn("brand", df.brand.cast(IntegerType())).withColumnRenamed("brand", "brandId").\
    withColumn("price", df.price.cast(FloatType()))

# 这里我们只需要adgroupId、和cateId
_ = ad_feature_df.select("adgroupId", "cateId")
# 由于这里数据集其实很少,所以我们再直接转成Pandas dataframe来处理,把数据载入内存
pdf = _.toPandas()


# 手动释放一些内存
del df
del ad_feature_df
del _
import gc
gc.collect()
  • 根据指定的类别找到对应的广告
import numpy as np
pdf.where(pdf.cateId==11156).dropna().adgroupId

np.random.choice(pdf.where(pdf.cateId==11156).dropna().adgroupId.astype(np.int64), 200)

显示结果:

313       138953.0
314       467512.0
1661      140008.0
1666      238772.0
1669      237471.0
1670      238761.0
            ...   
843456    352273.0
846728    818681.0
846729    838953.0
846810    845337.0
Name: adgroupId, Length: 731, dtype: float64
  • 利用ALS模型进行类别的召回
# 加载als模型,注意必须先有spark上下文管理器,即sparkContext,但这里sparkSession创建后,自动创建了sparkContext

from pyspark.ml.recommendation import ALSModel
# 从hdfs加载之前存储的模型
als_model = ALSModel.load("hdfs://localhost:9000/models/userCateRatingALSModel.obj")
# 返回模型中关于用户的所有属性   df:   id   features
als_model.userFactors

显示结果:

DataFrame[id: int, features: array<float>]
import pandas as pd
cateId_df = pd.DataFrame(pdf.cateId.unique(),columns=["cateId"])
cateId_df

显示结果:

    cateId
0    1
1    2
2    3
3    4
4    5
5    6
6    7
...    ...
6766    12948
6767    12955
6768    12960
6769 rows × 1 columns
cateId_df.insert(0, "userId", np.array([8 for i in range(6769)]))
cateId_df

显示结果:

 userId cateId
0    8    1
1    8    2
2    8    3
3    8    4
4    8    5
...    ...    ...
6766    8    12948
6767    8    12955
6768    8    12960
6769 rows × 2 columns
  • 传入 userid、cataId的df,对应预测值进行排序
als_model.transform(spark.createDataFrame(cateId_df)).sort("prediction", ascending=False).na.drop().show()

显示结果:

+------+------+----------+
|userId|cateId|prediction|
+------+------+----------+
|     8|  7214|  9.917084|
|     8|   877|  7.479664|
|     8|  7266| 7.4762917|
|     8| 10856| 7.3395424|
|     8|  4766|  7.149538|
|     8|  7282| 6.6835284|
|     8|  7270| 6.2145095|
|     8|   201| 6.0623236|
|     8|  4267| 5.9155636|
|     8|  7267|  5.838009|
|     8|  5392| 5.6882005|
|     8|  6261| 5.6804466|
|     8|  6306| 5.2992325|
|     8| 11050|  5.245261|
|     8|  8655| 5.1701374|
|     8|  4610|  5.139578|
|     8|   932|   5.12694|
|     8| 12276| 5.0776596|
|     8|  8071|  4.979195|
|     8|  6580| 4.8523283|
+------+------+----------+
only showing top 20 rows
import numpy as np
import pandas as pd

import redis

# 存储用户召回,使用redis第9号数据库,类型:sets类型
client = redis.StrictRedis(host="192.168.19.137", port=6379, db=9)
# 遍历als_model 中 所有用户的id
for r in als_model.userFactors.select("id").collect():

    userId = r.id

    #准备 当前用户 和 所有类别 一一对应的dataframe
    cateId_df = pd.DataFrame(pdf.cateId.unique(),columns=["cateId"])
    cateId_df.insert(0, "userId", np.array([userId for i in range(6769)]))
    ret = set()

    # 利用模型,传入datasets(userId, cateId),这里控制了userId一样,所以相当于是在求某用户对所有分类的兴趣程度
    cateId_list = als_model.transform(spark.createDataFrame(cateId_df)).sort("prediction", ascending=False).na.drop()
    # 找到前 20个 最感兴趣的类别 从前20个分类中选出500个进行召回
    for i in cateId_list.head(20):
        need = 500 - len(ret)    # 如果不足500个,那么随机选出need个广告
        ret = ret.union(np.random.choice(pdf.where(pdf.cateId==i.cateId).adgroupId.dropna().astype(np.int64), need))
        if len(ret) >= 500:    # 如果达到500个则退出
            break
    client.sadd(userId, *ret)

# 如果redis所在机器,内存不足,会抛出异常

5.2 离线数据缓存之离线特征

# "pid", 广告资源位,属于场景特征,也就是说,每一种广告通常是可以防止在多种资源外下的
# 因此这里对于pid,应该是由广告系统发起推荐请求时,向推荐系统明确要推荐的用户是谁,以及对应的资源位,或者说有哪些
# 这样如果有多个资源位,那么每个资源位都会对应相应的一个推荐列表

# 需要进行缓存的特征值

feature_cols_from_ad = [
    "price"    # 来自广告基本信息中
]

# 用户特征
feature_cols_from_user = [
    "cms_group_id",
    "final_gender_code",
    "age_level",
    "shopping_level",
    "occupation",
    "pvalue_level",
    "new_user_class_level"
]
  • 从HDFS中加载广告基本信息数据
_ad_feature_df = spark.read.csv("hdfs://localhost:9000/data/ad_feature.csv", header=True)

# 更改表结构,转换为对应的数据类型
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType

# 替换掉NULL字符串
_ad_feature_df = _ad_feature_df.replace("NULL", "-1")

# 更改df表结构:更改列类型和列名称
ad_feature_df = _ad_feature_df.\
    withColumn("adgroup_id", _ad_feature_df.adgroup_id.cast(IntegerType())).withColumnRenamed("adgroup_id", "adgroupId").\
    withColumn("cate_id", _ad_feature_df.cate_id.cast(IntegerType())).withColumnRenamed("cate_id", "cateId").\
    withColumn("campaign_id", _ad_feature_df.campaign_id.cast(IntegerType())).withColumnRenamed("campaign_id", "campaignId").\
    withColumn("customer", _ad_feature_df.customer.cast(IntegerType())).withColumnRenamed("customer", "customerId").\
    withColumn("brand", _ad_feature_df.brand.cast(IntegerType())).withColumnRenamed("brand", "brandId").\
    withColumn("price", _ad_feature_df.price.cast(FloatType()))

def foreachPartition(partition):

    import redis
    import json
    client = redis.StrictRedis(host="192.168.19.137", port=6379, db=10)

    for r in partition:
        data = {
            "price": r.price
        }
        # 转成json字符串再保存,能保证数据再次倒出来时,能有效的转换成python类型
        client.hset("ad_features", r.adgroupId, json.dumps(data))

ad_feature_df.foreachPartition(foreachPartition)
  • 从HDFS加载用户基本信息数据
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, LongType, FloatType

# 构建表结构schema对象
schema = StructType([
    StructField("userId", IntegerType()),
    StructField("cms_segid", IntegerType()),
    StructField("cms_group_id", IntegerType()),
    StructField("final_gender_code", IntegerType()),
    StructField("age_level", IntegerType()),
    StructField("pvalue_level", IntegerType()),
    StructField("shopping_level", IntegerType()),
    StructField("occupation", IntegerType()),
    StructField("new_user_class_level", IntegerType())
])
# 利用schema从hdfs加载
user_profile_df = spark.read.csv("hdfs://localhost:8020/csv/user_profile.csv", header=True, schema=schema)
user_profile_df

显示结果:

DataFrame[userId: int, cms_segid: int, cms_group_id: int, final_gender_code: int, age_level: int, pvalue_level: int, shopping_level: int, occupation: int, new_user_class_level: int]
def foreachPartition2(partition):

    import redis
    import json
    client = redis.StrictRedis(host="192.168.199.188", port=6379, db=10)

    for r in partition:
        data = {
            "cms_group_id": r.cms_group_id,
            "final_gender_code": r.final_gender_code,
            "age_level": r.age_level,
            "shopping_level": r.shopping_level,
            "occupation": r.occupation,
            "pvalue_level": r.pvalue_level,
            "new_user_class_level": r.new_user_class_level
        }
        # 转成json字符串再保存,能保证数据再次倒出来时,能有效的转换成python类型
        client.hset("user_features1", r.userId, json.dumps(data))

user_profile_df.foreachPartition(foreachPartition2)

广告推荐系统目的:
	根据已知的用户数据和所消费商品品类数据构建出“用户-物品品类-用户对物品品类的打分矩阵”训练出ALS模型,
	然后根据ALS模型对每个用户预测得出偏好程度最高的前N个商品品类,然后还可以根据每个商品品类中对应的销量最高的商品进行推荐给用户

广告推荐系统流程:
	1.使用Flume收集用户行为数据/点击数据(日志文件)进行清洗存储到HDFS,然后进行统计达到整体认识。
	2.使用用户行为数据构建ALS模型进行打分来取出用户感兴趣的商品。首先构建“用户-物品品类-用户对物品品类的打分矩阵”,利用标签和打分规则对用户行为进行打分,
	  其中包括每个行为都有自己的打分上限。最后利用spark mlib进行构建ALS模型进行训练。
	3.使用点击数据的基础上通过逻辑回归构建预测点击模型实现CTR预估。
	4.这里主要是利用我们前面训练的ALS模型进行协同过滤召回,但是注意,我们ALS模型召回的是用户最感兴趣的类别,而我们需要的是用户可能感兴趣的广告的集合,
	  因此我们还需要根据召回的类别匹配出对应的广告。所以这里我们除了需要我们训练的ALS模型以外,还需要有一个广告和类别的对应关系。
	5.根据ALS模型预测得出每个用户偏好程度最高的前N个商品品类,根据每个商品品类中对应的销量最高的商品进行推荐给用户

第一个模型:创建ALS实现的打分模型并召回商品
	可以是 训练用户userId对商品分类cateId的打分模型,用于向用户推荐TOP-N的商品品类,然后根据商品品类和商品之间的对应关系,给用户推荐该商品品类中销量最高的商品。
	也可以是 训练用户userId对品牌分类brandId的打分模型,用于向用户推荐TOP-N的商品品牌,然后根据品牌分类和商品之间的对应关系,给用户推荐该品牌分类中销量最高的商品。
	打分模型训练的矩阵数据:用户 — 商品分类/品牌分类 — 评分(根据用户行为和打分规则进行打分,如PV一次浏览打1分)

离线数据缓存之离线召回集
	这里主要是利用我们前面训练的ALS模型进行协同过滤召回,但是注意,我们ALS模型召回的是用户最感兴趣的类别,
	而我们需要的是用户可能感兴趣的广告的集合,因此我们还需要根据召回的类别匹配出对应的广告。
 	所以这里我们除了需要我们训练的ALS模型以外,还需要有一个广告和类别的对应关系。

# 从HDFS中加载广告基本信息数据,返回spark dafaframe对象
df = spark.read.csv("hdfs://localhost:9000/data/ad_feature.csv", header=True)

# 注意:由于本数据集中存在NULL字样的数据,无法直接设置schema,只能先将NULL类型的数据处理掉,然后进行类型转换
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType

# 替换掉NULL字符串,替换掉
df = df.replace("NULL", "-1")

# 更改df表结构:更改列类型和列名称
ad_feature_df = df.\
    withColumn("adgroup_id", df.adgroup_id.cast(IntegerType())).withColumnRenamed("adgroup_id", "adgroupId").\
    withColumn("cate_id", df.cate_id.cast(IntegerType())).withColumnRenamed("cate_id", "cateId").\
    withColumn("campaign_id", df.campaign_id.cast(IntegerType())).withColumnRenamed("campaign_id", "campaignId").\
    withColumn("customer", df.customer.cast(IntegerType())).withColumnRenamed("customer", "customerId").\
    withColumn("brand", df.brand.cast(IntegerType())).withColumnRenamed("brand", "brandId").\
    withColumn("price", df.price.cast(FloatType()))

# 这里我们只需要adgroupId(商品ID)和cateId(商品分类ID):代表的是每个商品和商品类别之间的对应关系的数据
_ = ad_feature_df.select("adgroupId", "cateId")
# 由于这里数据集其实很少,所以我们再直接转成Pandas dataframe来处理,把数据载入内存
pdf = _.toPandas()


# 手动释放一些内存
del df
del ad_feature_df
del _
import gc
gc.collect()
 
# 根据指定的类别找到对应的广告
import numpy as np
# 取出属于cateId(商品分类ID)为11156的adgroupId(商品ID)
pdf.where(pdf.cateId==11156).dropna().adgroupId
# 随机取出200个属于cateId(商品分类ID)为11156的adgroupId(商品ID)
# 假如知道这个cateId(商品分类ID)中的哪个adgroupId(商品ID)的销量高的话,那么不使用随机取的方式,可以使用只取出销量排在前N个的商品
np.random.choice(pdf.where(pdf.cateId==11156).dropna().adgroupId.astype(np.int64), 200)

显示结果:
行索引    adgroupId(商品ID)
313       138953.0
314       467512.0
1661      140008.0
1666      238772.0
1669      237471.0
1670      238761.0
            ...   
843456    352273.0
846728    818681.0
846729    838953.0
846810    845337.0
Name: adgroupId, Length: 731, dtype: float64

# 利用ALS模型进行类别的召回
# 加载als模型,注意必须先有spark上下文管理器,即sparkContext,但这里sparkSession创建后,自动创建了sparkContext
from pyspark.ml.recommendation import ALSModel
# 从hdfs加载之前存储的ALS模型:该模型是之前通过ALS训练出来的(用户-商品-评分)模型用于给用户推荐商品。
# ALS模型中保存的是用户数据为'userId'列、物品数据为'cateId'列、评分数据为'rating'列。
als_model = ALSModel.load("hdfs://localhost:9000/models/userCateRatingALSModel.obj")
# userFactors(用户矩阵):返回模型中关于用户的所有属性DataFrame:包含id列、features列
als_model.userFactors
显示结果:
DataFrame[id: int, features: array<float>]

import pandas as pd
#构建不重复的cateId(商品分类ID)
cateId_df = pd.DataFrame(pdf.cateId.unique(),columns=["cateId"])
cateId_df
显示结果:
行索引 cateId
0       1
1       2
2       3
3       4
4       5
5       6
6       7
...    ...
6766    12948
6767    12955
6768    12960
6769 rows × 1 columns


# cateId(商品分类ID)为第0列,那么此处实际是在cateId前面插入1列"userId",并且初始化"userId"这一列的值均为8,
# 之所以取值为8是因为为了举例研究单个用户ID为8对于所有商品品类的偏好。
cateId_df.insert(0, "userId", np.array([8 for i in range(6769)]))
cateId_df
显示结果:
   userId cateId
0    8    1
1    8    2
2    8    3
3    8    4
4    8    5
...    ...    ...
6766    8    12948
6767    8    12955
6768    8    12960
6769 rows × 2 columns


# spark.createDataFrame(cateId_df):因为cateId_df是pandas的DataFrame,此处转换为spark的DataFrame。
# ALS模型中保存的是用户数据为'userId'列、物品数据为'cateId'列、评分数据为'rating'列。
# 通过传入DataFrame的cateId_df(包含userid、cataId) 然后进行ALS模型transform转换,对最终模型预测得出的DataFrame中的预测值"prediction"进行降序排序。
# 预测值"prediction":实际是用户ID(userId)为8的用户对于每个cateId(商品分类ID)的评分预测值(即喜好程度)。
# 也即最终对用户ID(userId)对于每个cateId(商品分类ID)的评分预测值(即喜好程度)进行降序排序。
# na.drop():代表dropna(),去掉空值数据
als_model.transform(spark.createDataFrame(cateId_df)).sort("prediction", ascending=False).na.drop().show()
显示结果:
+------+------+----------+
|userId|cateId|prediction|
+------+------+----------+
|     8|  7214|  9.917084|
|     8|   877|  7.479664|
|     8|  7266| 7.4762917|
|     8| 10856| 7.3395424|
|     8|  4766|  7.149538|
|     8|  7282| 6.6835284|
|     8|  7270| 6.2145095|
|     8|   201| 6.0623236|
|     8|  4267| 5.9155636|
|     8|  7267|  5.838009|
|     8|  5392| 5.6882005|
|     8|  6261| 5.6804466|
|     8|  6306| 5.2992325|
|     8| 11050|  5.245261|
|     8|  8655| 5.1701374|
|     8|  4610|  5.139578|
|     8|   932|   5.12694|
|     8| 12276| 5.0776596|
|     8|  8071|  4.979195|
|     8|  6580| 4.8523283|
+------+------+----------+
only showing top 20 rows



import numpy as np
import pandas as pd
import redis

# 如果redis所在机器,内存不足,会抛出异常
# 存储用户召回,使用redis第9号数据库,类型:sets类型
client = redis.StrictRedis(host="192.168.19.137", port=6379, db=9)
# 遍历als_model中所有用户的id:userFactors(用户矩阵)中的id列为用户ID
for r in als_model.userFactors.select("id").collect():
    #获取每个userId 
    userId = r.id
    # 准备 当前用户 和 所有类别 一一对应的dataframe
    # pdf:包含了adgroupId(商品ID)和cateId(商品分类ID),代表的是每个商品和商品类别之间的对应关系的数据。
    # cateId_df:构建出不重复的cateId(商品分类ID)列的数据
    cateId_df = pd.DataFrame(pdf.cateId.unique(),columns=["cateId"])
    # 即在cateId(商品分类ID)列前面增加1列"userId"(当前遍历的用户ID),代表该用户对应所有每个cateId(商品分类ID)
    cateId_df.insert(0, "userId", np.array([userId for i in range(6769)]))
    ret = set()

    # 利用训练好的ALS模型,传入cateId_df(即datasets(userId, cateId)),这里控制了userId均为同一个用户,所以相当于是在求某用户对所有分类的兴趣程度
    # spark.createDataFrame(cateId_df):因为cateId_df是pandas的DataFrame,此处转换为spark的DataFrame。
    # ALS模型中保存的是用户数据为'userId'列、物品数据为'cateId'列、评分数据为'rating'列。
    # 通过传入DataFrame的cateId_df(包含userid、cataId) 然后进行ALS模型transform转换,对最终模型预测得出的DataFrame中的预测值"prediction"进行降序排序。
    # 预测值"prediction":实际是用户(userId)对于每个cateId(商品分类ID)的评分预测值(即喜好程度)。
    # 也即最终对用户(userId)对于每个cateId(商品分类ID)的评分预测值(即喜好程度)进行降序排序。
    # na.drop():代表dropna(),去掉空值数据
    cateId_list = als_model.transform(spark.createDataFrame(cateId_df)).sort("prediction", ascending=False).na.drop()
    # 找到前20个最感兴趣的cateId(商品分类ID),然后从前20个商品分类中选出一共500个商品进行召回
    for i in cateId_list.head(20):
        # 如果前20个商品分类中选出的商品都不足500个的话,那么再随机选出need个广告商品。
        # 如果第一个商品类别中都已经挑选出500个商品的话,那么则不需要再从后面的商品类别中继续取出商品了。
        need = 500 - len(ret)   
        # pdf:包含了adgroupId(商品ID)和cateId(商品分类ID),代表的是每个商品和商品类别之间的对应关系的数据。
        # 从pdf的DataFrame中随机取出need个属于cateId(商品分类ID)的adgroupId(商品ID)
        # 假如知道这个cateId(商品分类ID)中的哪个adgroupId(商品ID)的销量高的话,那么不使用随机取的方式,可以使用只取出销量排在前N个的商品
        ret = ret.union(np.random.choice(pdf.where(pdf.cateId==i.cateId).adgroupId.dropna().astype(np.int64), need))
        # 如果达到500个商品(adgroupId商品ID)则退出
        if len(ret) >= 500:    
            break
    #userId对应的500个adgroupId(商品ID)存储到redis
    client.sadd(userId, *ret) 
# 离线数据缓存之离线特征
# 1."pid", 广告资源位,属于场景特征,也就是说,每一种广告通常是可以防止在多种资源外下的。
#   因此这里对于pid,应该是由广告系统发起推荐请求时,向推荐系统明确要推荐的用户是谁,以及对应的资源位,或者说有哪些。
#   这样如果有多个资源位,那么每个资源位都会对应相应的一个推荐列表。
# 2.需要把以下特征值缓存到redis:从HDFS中获取广告基本信息数据"price"缓存到redis,从HDFS获取用户基本信息数据缓存到redis
# 3.缓存的目的:因为需要实时预测出用户是否喜欢这些商品,那么需要实时根据广告基本信息数据"price"和用户基本信息数据进行计算,
#   如果此时从hdfs中获取的话则延迟很慢,因此需要预先从hdfs获取数据缓存到redis,便于要计算时可以实时地从redis中获取。
#   当已经训练好模型之后需要一个实时性的推荐结果的时候,才需要把模型依赖计算的数据缓存到redis。

# 广告基本信息中要缓存的价格信息
feature_cols_from_ad = [
    "price"     
]

# 用户基本信息数据中要缓存的用户特征值
feature_cols_from_user = [
    "cms_group_id",
    "final_gender_code",
    "age_level",
    "shopping_level",
    "occupation",
    "pvalue_level",
    "new_user_class_level"
]

#从HDFS中加载广告基本信息数据
_ad_feature_df = spark.read.csv("hdfs://localhost:9000/data/ad_feature.csv", header=True)
# 更改表结构,转换为对应的数据类型
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType

# 替换掉NULL字符串
_ad_feature_df = _ad_feature_df.replace("NULL", "-1")
# 更改df表结构:更改列类型和列名称
ad_feature_df = _ad_feature_df.\
    withColumn("adgroup_id", _ad_feature_df.adgroup_id.cast(IntegerType())).withColumnRenamed("adgroup_id", "adgroupId").\
    withColumn("cate_id", _ad_feature_df.cate_id.cast(IntegerType())).withColumnRenamed("cate_id", "cateId").\
    withColumn("campaign_id", _ad_feature_df.campaign_id.cast(IntegerType())).withColumnRenamed("campaign_id", "campaignId").\
    withColumn("customer", _ad_feature_df.customer.cast(IntegerType())).withColumnRenamed("customer", "customerId").\
    withColumn("brand", _ad_feature_df.brand.cast(IntegerType())).withColumnRenamed("brand", "brandId").\
    withColumn("price", _ad_feature_df.price.cast(FloatType()))

def foreachPartition(partition):
    import redis
    import json
    client = redis.StrictRedis(host="192.168.19.137", port=6379, db=10)
    # 遍历分区中的每行数据
    for r in partition:
        data = {
            "price": r.price
        }
        # 转成json字符串再保存,能保证数据再次倒出来时,能有效的转换成python类型
        # "ad_features"为大key,adgroupId(商品ID)为小key,data为value(商品价格price)
        client.hset("ad_features", r.adgroupId, json.dumps(data))

ad_feature_df.foreachPartition(foreachPartition)


#从HDFS加载用户基本信息数据
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, LongType, FloatType

# 构建表结构schema对象
schema = StructType([
    StructField("userId", IntegerType()),
    StructField("cms_segid", IntegerType()),
    StructField("cms_group_id", IntegerType()),
    StructField("final_gender_code", IntegerType()),
    StructField("age_level", IntegerType()),
    StructField("pvalue_level", IntegerType()),
    StructField("shopping_level", IntegerType()),
    StructField("occupation", IntegerType()),
    StructField("new_user_class_level", IntegerType())
])
# 利用schema从hdfs加载
user_profile_df = spark.read.csv("hdfs://localhost:8020/csv/user_profile.csv", header=True, schema=schema)
user_profile_df
# 显示结果 :DataFrame[userId: int, cms_segid: int, cms_group_id: int, final_gender_code: int, age_level: int, pvalue_level: int, 
# shopping_level: int, occupation: int, new_user_class_level: int]


def foreachPartition2(partition):
    import redis
    import json
    client = redis.StrictRedis(host="192.168.199.188", port=6379, db=10)
    # 遍历分区中的每行数据
    for r in partition:
        data = {
            "cms_group_id": r.cms_group_id,
            "final_gender_code": r.final_gender_code,
            "age_level": r.age_level,
            "shopping_level": r.shopping_level,
            "occupation": r.occupation,
            "pvalue_level": r.pvalue_level,
            "new_user_class_level": r.new_user_class_level
        }
        # 转成json字符串再保存,能保证数据再次倒出来时,能有效的转换成python类型
        # "user_features"为大key,userId(用户ID)为小key,data为value(用户基本信息数据)
        client.hset("user_features", r.userId, json.dumps(data))

user_profile_df.foreachPartition(foreachPartition2)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

あずにゃん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值