首页 / 资讯中心 / 文章详情

企业级用户画像标签系统工程:HBase、Spark与ES全链路实践

企业级用户画像标签系统工程:HBase、Spark与ES全链路实践 ★ FEATURED ARTICLE
简介这是一份系统讲解大数据用户画像全流程构建的完整PDF文档共686页面向产品经理、运营人员和算法工程师。内容从用户画像概念与发展入手明确Personal与User Profile的差异随后进入项目环境搭建涵盖HDFS、Hive、HBase上的数据采集与ETL流程。标签开发部分重点讲了三类方式规则匹配标签、统计标签与挖掘标签其中挖掘标签深入KMeans聚类、决策树等算法并结合Spark MLlib完成分类与回归案例实践。进一步还包含使用Elasticsearch建立标签索引、基于ALS完成商品推荐以及从HBase、Hive、MySQL、HDFS等多源加载业务数据的方法形成从数据到标签再到应用的闭环。资源包为单个PDF文件大小约38.69MB目前已有1474人学习适合希望完整掌握用户画像建模、数据挖掘与推荐系统落地的读者。1. 用户画像不是抽象概念落地上百万用户的标签系统工程用户画像这个词简历里出现得多真正上过生产线的少。大部分人做过的事情是用 SQL 拉了用户性别、年龄段、消费金额然后在 BI 报表里画了个圆形的“用户特征图”。那不是用户画像那只是描述性统计。这份 686 页的资料把企业级用户画像的完整链路拆成了六段ETL 数据接入、HBase 标签存储、规则/统计/挖掘三类标签开发、Spark MLlib 里的 KMeans 与决策树、Elasticsearch 标签索引以及基于 ALS 的商品推荐。适合两类人一类是刚被安排做用户画像、需要一套可落地架构的大数据开发另一类是数据产品经理想搞清楚标签从定义到验证的完整闭环到底长什么样。下面我会把链路中真正值钱的部分展开讲包括标签表结构怎么设计、三类标签的开发顺序为什么不能乱以及我反复踩过的五个坑。2. 拆解标签体系从本体论到 HBase 里的 tbl_profile2.1 用户画像的三种定义阶段决定了你的技术选型用户画像这个概念在业界经历了三个阶段每个阶段的定义不同对应的技术方案也完全不同。第一个阶段是 Alan Cooper 提出的 Personas中文叫用户角色它是基于访谈和调研构造的目标用户代表比如“28 岁、喜欢健身、用 iPhone 的都市白领”。这个阶段的核心方法是定性研究适合产品初期做定位不适合大规模数据应用。第二个阶段是从用户行为中逐步学习兴趣模型代表是 Syskill Webert 通过显式收集用户对页面的满意度统计分析学习出用户兴趣模型。第三个阶段是数据驱动的 User Profile也就是这份资料重点讲的内容——利用用户在系统里产生的浏览、订单、购物车、搜索记录等海量行为数据通过算法模型预测用户未来行为比如会不会流失、会不会购买、偏好什么品类。选型上我的判断标准是数据量在百万级以下、标签维度不超过 20 个用 MySQL 加定时脚本完全够用。一旦用户量过千万、标签维度上百就必须上分布式存储和计算也就是资料里说的 HDFS、Hive、HBase 这条链路。很多项目翻车不是技术问题是第一阶段和第三阶段的定义混着用——拿 Persona 的思路来做 User Profile最后做出来的东西既不是定性研究也不是数据模型。2.2 属性、偏好、行为三类标签数据来源和开发方式完全不同资料里把用户画像的研究方向切成了三块用户属性、用户偏好、用户行为。这三类标签是分层递进的关系不能混在一个开发流程里处理。标签类别典型数据来源示例开发方式用户属性注册信息、实名认证性别、年龄、地域、会员等级规则匹配标签做清洗和映射即可用户偏好订单、收藏、购物车偏好的品类、价格带、品牌主要是统计标签按维度聚合沉淀用户行为浏览日志、点击流活跃时段、访问频次、流失倾向统计标签 挖掘标签KMeans、决策树用户属性是最基础的标签直接从注册表同步用规则匹配就能完成。用户偏好要基于业务数据做聚合比如用户近 90 天在哪个品类下的单最多喜欢买什么价位的商品。用户行为偏标签是最复杂的单纯的频次和时长统计不够需要用聚类来做分群用分类模型来预测流失概率。注意一个问题实际项目中很多人把“偏好”和“行为”混淆。偏好是基于长期业务数据的判断比如一个人一个月内在母婴品类下了 5 单可以打“母婴偏好”标签。但用户偶尔浏览了一次奢侈品页面不能直接打“奢侈品感兴趣”标签——这就是资料里强调的行为动机乱归因问题后面避坑章节我会展开讲。2.3 HBase 标签表设计一张表装下用户标签和商品标签用户画像的标签最终要落到存储上。资料给出的方案是用 HBase 存储表名叫 tbl_profileRowKey 是 userId列簇分为两类user 列簇存用户标签item 列簇存商品标签。列名是 tagName列值是 tagValue。这个设计的核心思路是一张表、一个 RowKey就能同时承载“用户身上有哪些标签”和“用户和哪些商品发生了关系”这两类信息。查询时只要 get 一个 RowKey就能拿到该用户的全部标签性能非常好。hbase shell # 创建用户画像标签表预分区 10 个避免热点写入 create tbl_profile, {NAME user, VERSION 1}, {NAME item, VERSION 1}, {SPLITS [1, 2, 3, 4, 5, 6, 7, 8, 9]}参数说明VERSION 1 表示每个单元格只保留一个历史版本因为标签值只关心最新的保留多版本会浪费存储。SPLITS 是指定预分区边界HBase 默认只有一个 Region数据量大了会频繁分裂预分区能提前把数据分散到多个 RegionServer 上。除了标签主表还需要一张标签元数据表用来管理每个标签的定义。资料里给了个清晰的例子tagId 是 384表示“男”385 表示“女”。这张表解决的问题是标签的代码必须可解释。HBase 里存储的 tagValue 可能是“384”但下游业务方看不懂 384 是什么意思通过 tagInfo 表关联就能把它翻译成“男”。CREATE TABLE tag_info ( tag_id INT PRIMARY KEY, tag_name VARCHAR(50), tag_desc VARCHAR(200), tag_category VARCHAR(20) ); INSERT INTO tag_info VALUES (384, gender_male, 用户的性别为男性, attribute), (385, gender_female, 用户的性别为女性, attribute), (386, high_value, 近90天消费金额排名前10%, statistics);设计要点是标签名用英文下划线风格方便代码里直接引用tag_desc 写清楚口径包括时间窗口和计算方式tag_category 区分是属性标签、统计标签还是挖掘标签方便后续管理。2.4 打标流程七步走完一个标签的完整生命周期资料里用了一个很生动的比喻产品经理给用户打标签就像丈母娘考察女婿——先问你有没有房再问房子在哪里、多大面积、全款还是贷款。这就是从单维度到多维度、从简单到复杂的迭代过程。一个标签从需求到上线我一般会走七步第一步明确业务目标。做标签前先回答这个标签给谁用解决什么决策问题。不知道目标就动手打标做出来的东西大概率没人用。第二步盘点可用数据。标签涉及的数据在哪个库、什么表、什么字段、覆盖多少用户。第三步确定标签维度。一个目标可能需要多个维度共同刻画比如“高价值用户”不能只看消费金额还要看消费频次和最近一次消费时间。第四步定义计算口径。规则类标签直接写 SQL挖掘类标签要确定特征字段和算法。口径必须白纸黑字写清楚包括时间窗口比如“近 90 天”还是“自然年”。第五步开发与计算。跑任务生成标签值写入 HBase。第六步验证效果。验证的核心指标是这个标签能不能把用户区分开比如打了“高价值”标签的用户在后续的转化率上是不是真的显著高于未打标用户。第七步沉淀与迭代。验证有效的标签进入正式标签库无效的调整口径或者下线。这套流程看起来简单但大部分团队做到第五步就停了。验证和迭代这两步最容易被跳过而恰恰是它们决定了标签系统是越用越准还是一堆垃圾标签堆积成山。3. ETL 与调度把业务数据搬进大数据平台的常见姿势3.1 三种数据源导入Sqoop、Flume 和直接落 Hive用户画像要建标签先得有数据。资料里明确提到标签系统要支持从 HBase、Hive、MySQL、HDFS 等多种数据源加载业务数据。这里的关键点在于不同数据源的采集方式完全不同不能一把梭。常见做法是业务库到 HDFS 用 Sqoop日志流到 HDFS 用 Flume已经存在 Hive 里的数据直接建外表映射。Sqoop 是 Hadoop 生态里最经典的关系型数据库导入工具支持增量导入。sqoop import \ --connect jdbc:mysql://dw-mysql:3306/business_db \ --username reader \ --password ${READER_PWD} \ --table user_reg_info \ --columns user_id,gender,birthday,province,city,register_time \ --where register_time 2024-01-01 \ --target-dir /warehouse/profile/ods/user_reg_info \ --num-mappers 4 \ --incremental append \ --check-column id参数说明--incremental append 是追加模式配合 --check-column 指定自增主键或时间字段每次增量导入只拉取新数据。--num-mappers 是并行度4 个 mapper 基本够用大批量导入可以调到 8但要关注源库的负载。密码不直接写在命令行里用环境变量引用避免密码泄露。如果是埋点日志这类流式数据Flume 是更合适的方案配置一个 spooldir 或 taildir source下沉到 HDFS 按天分目录存储。我自己在实际项目里更推荐直接用 log 采集到 Kafka再从 Kafka 落 HDFS扩展性更强。数据落 HDFS 之后需要在 Hive 里建外表和分区关联。3.2 Oozie 与 Hue 集成定时任务的编排方式数据采集是每天跑一次的节奏不可能手工执行。资料里给出的方案是 Oozie 与 Hue 集成。Oozie 是 Hadoop 的工作流调度引擎核心概念是 workflow用 XML 定义一组有依赖关系的 action第一个 action 完成后才能执行下一个。workflow-app nameprofile-etl-wf xmlnsuri:oozie:workflow:0.5 start tosqoop-import/ action namesqoop-import sqoop xmlnsuri:oozie:sqoop-action:0.2 job-tracker${jobTracker}/job-tracker name-node${nameNode}/name-node commandimport --connect jdbc:mysql://dw-mysql:3306/business_db --table user_reg_info --target-dir /warehouse/profile/ods/user_reg_info --incremental append --check-column id --num-mappers 4/command /sqoop ok tohive-tag-compute/ error tofail/ /action action namehive-tag-compute hive xmlnsuri:oozie:hive-action:0.5 job-tracker${jobTracker}/job-tracker name-node${nameNode}/name-node scripthive/tag_compute.sql/script /hive ok toend/ error tofail/ /action kill namefail messageJob failed, check logs: ${wf:errorMessage(wf:lastErrorNode())}/message /kill end nameend/ /workflow-app如果把 Oozie 的 XML 配置直接告诉业务团队他们大概率会懵。所以生产环境通常把 Oozie 接进 Hue在 Web 界面里拖拽配置业务人员也能看明白任务依赖关系。调度配置里有几个参数容易翻车一是频次要设对日任务用 frequency 24 小时周期二是失败重试次数建议设 3 次每次间隔 10 分钟三是任务超时时间要留缓冲区比如计算任务平时跑 20 分钟超时时间设 60 分钟避免上游数据延迟导致任务被杀。3.3 数据质量检查先查这四类问题再计算标签ETL 做完不等于数据能直接用。标签计算对数据质量极其敏感上游几个脏数据就能污染整个标签。我在每次 ETL 完成后都会先跑一遍质量检查脚本查四类问题空值率、重复记录、枚举合法性、时间越界。-- 空值率检查user_reg_info 表中关键字段空值占比 SELECT COUNT(*) AS total_cnt, SUM(CASE WHEN gender IS NULL THEN 1 ELSE 0 END) AS gender_null_cnt, ROUND(SUM(CASE WHEN gender IS NULL THEN 1 ELSE 0 END) / COUNT(*), 4) AS gender_null_rate FROM profile.ods_user_reg_info WHERE dt ${yesterday};逻辑说明通过聚合函数统计空值数量和空值占比。如果性别字段的空值率超过 5%说明注册流程改了或者同步链路断了要回去查源表如果注册时间大量晚于当前日期说明源库有脏数据需要过滤后再做标签。数据质量检查这件事没有一劳永逸的方案但是可以把每天的检查结果写入一张质量监控表超过阈值自动报警。不要等到标签上线被业务方质疑数据不准了才回头排查那时候排查成本高得多。4. 标签开发顺序规则、统计、挖掘三类不能跳着做4.1 规则匹配标签用 SQL 就能搞定先做这类资料里给出的标签开发排期很明确规则匹配标签 2 天统计标签 1 天挖掘标签 2 天机器学习入门 1 天标签索引化 1 天。开发顺序为什么这样安排因为规则标签是最简单的投入成本最低而且能快速验证整个链路通不通。规则匹配标签的本质是把业务规则翻译成 SQL。比如用户的年龄段标签INSERT OVERWRITE TABLE profile.dws_user_age_tag SELECT user_id, CASE WHEN age 18 THEN age_under_18 WHEN age BETWEEN 18 AND 24 THEN age_18_24 WHEN age BETWEEN 25 AND 34 THEN age_25_34 WHEN age BETWEEN 35 AND 44 THEN age_35_44 ELSE age_45_plus END AS tag_value FROM profile.dws_user_base_info WHERE dt ${yesterday};注意这里的分段方式并不是唯一的。同样一份年龄数据如果业务目标是“筛选保险潜在用户”35 岁以上才是重点如果是“筛选游戏新品种子用户”18-24 岁才是核心。所以规则标签的第一步不是写 SQL是跟业务方确认分段的业务意义。这就是资料里说的没有目标盲目干活是用户标签最常见的坑。写完计算结果之后要把结果同步到 HBase。规则标签的数据量通常不大常见做法是直接用 Spark 批量读 Hive 表写入 HBase 的 tbl_profile 表。写之前注意列簇的选择用户属性类标签写入 user 列簇商品相关标签写入 item 列簇。4.2 统计标签聚合出用户的行为偏好统计标签比规则标签复杂要基于订单、浏览等行为数据做聚合。典型例子是“用户近 90 天购买品类偏好”。实现的思路分两步先按用户品类聚合算购买次数和金额再在用户维度内做排名取 Top 3。// 使用 Spark DataFrame 计算用户品类偏好 import org.apache.spark.sql.functions._ import org.apache.spark.sql.expressions.Window val orderDF spark.table(dwd_order_detail) .filter($order_time date_add(current_date(), -90)) // 第一步用户 品类聚合 val userCategory orderDF .groupBy(user_id, category_id) .agg( count(order_id).as(buy_cnt), sum(order_amount).as(buy_amount) ) // 第二步按用户分组按购买次数排名取 Top3 val rankSpec Window.partitionBy(user_id).orderBy(desc(buy_cnt)) val top3 userCategory .withColumn(rn, row_number().over(rankSpec)) .filter($rn 3)逻辑说明先按 user_id 和 category_id 两个维度分组统计 90 天内的购买次数和金额再用窗口函数在每个用户分组内按购买次数倒序排名过滤出 Top 3。参数说明时间窗口设为近 90 天这是一个经验值太短了冷启动期用户数据稀疏太长了用户的兴趣偏移会被平均掉。统计标签的开发痛点在于维度组合爆炸。一个用户可以有品类偏好、价格带偏好、品牌偏好、购买时段偏好每个维度都要单独开发代码量很大。我的习惯是把这些聚合逻辑封装成一个公共特征计算模块按配置生成标签而不是每个标签单独写一段。4.3 挖掘标签KMeans 分群与决策树预测注意使用边界挖掘标签是资料里技术含量最高的部分也是翻车最多的部分。需要明确一点不是所有标签都需要机器学习。能用规则或者统计解决的问题不要上模型。挖掘标签解决的是那些无法通过显式规则描述的问题比如“用户分属于什么客群”“用户未来会不会流失”。KMeans 聚类适合做用户分群。比如用消费频率、消费金额、活跃时长三个特征把用户聚成价格敏感型、品质导向型、低频沉默型等客群。// Spark MLlib KMeans 用户分群 import org.apache.spark.ml.clustering.KMeans import org.apache.spark.ml.feature.VectorAssembler import org.apache.spark.ml.evaluation.ClusteringEvaluator // 特征列组合成向量 val featureCols Array(buy_freq, avg_order_amount, active_days) val assembler new VectorAssembler() .setInputCols(featureCols) .setOutputCol(features) val featureDF assembler.transform(userFeatureDF) // 训练 KMeans聚类簇数设为 4 val kmeans new KMeans() .setK(4) .setSeed(42L) .setMaxIter(20) .setFeaturesCol(features) .setPredictionCol(cluster_id) val model kmeans.fit(featureDF) val result model.transform(featureDF) // 计算轮廓系数验证聚类质量 val evaluator new ClusteringEvaluator() .setFeaturesCol(features) .setMetricName(silhouette) val silhouetteScore evaluator.evaluate(result) println(ssilhouette score: $silhouetteScore)参数说明setK(4) 是聚类簇数这个值不是越大越好建议先用肘部法则确定——跑不同 K 值画损失函数曲线看拐点。setSeed(42L) 固定随机种子保证每次训练结果可复现这是生产环境必须养成的习惯否则别人复现不了你的结果。setMaxIter(20) 是最大迭代次数一般 20 次内能收敛。ClusteringEvaluator 里的 silhouette 指标范围是 [-1, 1]越大越好一般大于 0.25 就可以接受低于这个值说明特征没选好或者 K 值不对。决策树适合做二分类预测比如用户流失预测。这类标签有一个很容易翻车的点把历史统计直接当预测。资料里特别强调“高价值用户”如果指的是未来消费高那必须用预测模型不能简单统计历史消费金额然后除以人数排名。历史买得多不等于未来买得多要建模预测。// Spark MLlib 决策树用户流失预测 import org.apache.spark.ml.classification.DecisionTreeClassifier import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator val dt new DecisionTreeClassifier() .setLabelCol(label) .setFeaturesCol(features) .setMaxDepth(5) .setMinInstancesPerNode(50) val Array(train, test) data.randomSplit(Array(0.8, 0.2), seed 42L) val model dt.fit(train) val predictions model.transform(test) val evaluator new MulticlassClassificationEvaluator() .setLabelCol(label) .setPredictionCol(prediction) .setMetricName(accuracy) println(stest accuracy: ${evaluator.evaluate(predictions)})参数说明setMaxDepth(5) 限制树深度为 5防止过拟合。树太深会把训练集的特征学得过于细致测试集表现反而差。setMinInstancesPerNode(50) 要求每个叶子节点至少包含 50 个样本这也是一个正则化手段。数据集按 8:2 切分训练集和测试集固定随机种子保证实验可复现。使用边界的建议KMeans 和决策树都属于入门级算法效果依赖特征工程远大于算法本身。如果特征质量差换再复杂的模型也救不回来。资料把这部分定位成“机器学习入门 1 天”是有道理的——在用户画像项目里算法的价值占比不超过 30%另外 70% 在标签设计和特征工程。5. 避坑用户画像项目的五大典型翻车现场现象到复盘这部分内容是资料里最有价值的章节之一原作者总结了打标签过程中的五大常见问题。以下每一条都是我的亲身经历按现象、原因、解决三段式复盘。5.1 没有业务目标就开打标签做完了没人用现象团队花了两周做出几百个标签结果业务方反馈不知道用哪些、怎么用标签上线一个季度使用率不到 10%。原因被“性别男女就是一个标签”这种说法误导以为只要做了分类就算标签完全没有考虑标签要服务的具体业务目标。同一个用户年龄数据保险运营和游戏运营的关注点完全不同没有目标就没有分段的依据。解决每个标签必须关联一个业务场景和目标。做标签之前先让业务方回答三个问题这个标签用于哪个运营活动用什么策略期望带来什么效果答不上来的标签需求直接暂缓。至少要求标签的元数据表里加一个“业务场景”字段倒逼团队想清楚再动手。5.2 高价值用户标签不区分历史与未来把统计当预测现象用历史消费金额排名前 10% 定义“高价值用户”给这批人做了超高额度的优惠券倾斜结果次月这批用户的回购率并没有显著高于其他用户营销成本却翻倍。原因把历史统计口径直接当成未来预测。用户过去买得多受促销、季节、偶发大额采购影响很大无法代表未来的消费潜力。资料里强调如果要打的是未来情况意味着要做预测不能简单基于历史数据统计。解决把标签从概念上切分。历史类标签用统计口径命名上明确加“历史”例如“历史高消费用户”预测类标签必须上模型用决策树或者逻辑回归预测未来 30 天购买概率预测结果定期回测准确率。这两类标签绝对不能混在一个标签里否则业务方拿去用就会错。5.3 行为动机乱归因把一次偶然行为当偏好现象用户在某次大促期间因为折扣力度大下单了一个高端品牌的商品系统给用户打了“高端品牌偏好者”标签。之后给该用户推送该高端品牌的新品结果用户完全没有点击。原因只观察到一次购买行为就断定用户对品牌有偏好。用户下单的原因可能是打折、可能是凑单、可能是帮别人买行为不等于动机。资料里说得直接错误的、随意的归因会误导业务行动。解决行为类偏好的判定必须基于长期和多维度的数据支撑。比如至少观察 90 天内 3 次以上的品牌购买记录并且购买时的折扣率低于某个阈值才打“品牌忠诚”标签。下单后 7 天内退货率超过 50% 的行为不能计入偏好计算。5.4 多目标混合成“综合评价”指标互相污染现象某团队做高价值用户评分把活跃度、付费金额、毛利三个指标加权成一个公式。结果一些活跃度极高但从不付费的“白嫖用户”综合分排进了头部运营按这个名单做会员权益发放白白送出去大量成本。原因不同业务目标的数据混合进同一个模型。活跃度高代表运营价值付费金额高代表商业价值毛利高代表盈利价值这三类价值不应混成一个所谓的综合评价指标。解决严格执行“不同类目标不混合”的原则特别是涉及钱的目标。要算商业价值就只用付费相关指标要算活跃度就单独用活跃指标。如果确实需要综合评价必须明确每个指标的权重来源和业务含义并且在结果验证时按目标拆开看分层效果。5.5 结果缺少检验标签只做了“贴”没做“验”现象打完标签直接上线从没检查过标签能不能有效区分用户。某个“沉睡用户”标签圈出来的用户跟全量用户的次日留存率几乎一样没有显著差异。原因团队把打标本身当成了成果没有建立验证机制。打标的目的就是区分用户如果区分效果在目标指标上没有差异这个标签就没有存在价值。解决把“打标-验证-积累-二次打标”做成闭环。上线前用历史数据回测验证打标群体和未打标群体在核心目标指标上的差异是否显著上线后跟踪标签实际使用效果区分度不达标的标签回到定义阶段重新调整口径。这个验证流程是标签质量最后一道防线不能省。6. 把标签用起来Elasticsearch 索引与 ALS 推荐闭环6.1 为什么标签要进 Elasticsearch而不是直接查 HBaseHBase 适合按 RowKey 查单用户的所有标签但业务方真正高频的需求是“找出满足多个标签组合的用户群”——比如筛选 25-34 岁、一线城市、近 90 天购买过母婴品类、未来 30 天流失概率大于 60% 的用户。这类多条件组合查询是 HBase 的弱项却是 Elasticsearch 的强项。资料里给出的方案是用户标签除了存 HBase还要同步一份到 Elasticsearch 做索引。同步方式用 Spark 读 HBase再调用 ES 的 bulk API 批量写入。PUT /user_profile/_mapping { properties: { userId: { type: keyword }, gender: { type: keyword }, ageSegment: { type: keyword }, cityLevel: { type: keyword }, buyCategory: { type: keyword }, highValueFlag: { type: boolean }, riskScore: { type: float } } }设计要点所有只用于筛选的字段都用 keyword 类型不做全文分词。userId 是 keyword 是为了精确匹配gender 和 cityLevel 这类枚举值用 keyword 很合适riskScore 用 float因为后续要按分数区间过滤。ES 的 mapping 一旦创建不能改字段类型所以早期就要把标签字段规划好。6.2 多标签组合查询bool 查询的 DSL 写法最常见的组合查询是筛出“高价值且近期活跃”的用户作为一次精准营销的推送人群。ES 的 bool 查询可以同时处理 must、filter、must_not 三种语义。GET /user_profile/_search { query: { bool: { filter: [ { term: { highValueFlag: true } }, { range: { riskScore: { lte: 0.4 } } } ], must: [ { terms: { buyCategory: [母婴, 辅食] } } ], must_not: [ { term: { cityLevel: 五线城市 } } ] } }, size: 5000 }参数说明filter 上下文中的条件会被 ES 缓存适合高价值标签这种过滤性强、变化频率低的字段查询性能更好。must 影响相关性评分terms 表示匹配列表中任意一个值。must_not 是排除条件这里排除五线城市用户因为母婴品类在一二线城市的渗透率显著更高。size 设为 5000 是单次拉取的上限如果人群量更大要配合 search_after 做分页拉取。这套查询链路打通之后运营在活动页面上选几个标签就能圈出一批人群做投放这才是用户画像系统的价值落地。6.3 ALS 推荐给浏览过的用户推荐 Top10 商品资料里提到用户浏览商品时给用户推荐 Top10 商品用到的算法是 ALS——交替最小二乘法。ALS 是协同过滤算法的实现之一核心思想是通过用户对商品的评分这里用点击、加购、购买行为量化成隐式反馈学习出用户和商品两个低维向量然后用向量的内积预测用户对未见商品的偏好程度。import org.apache.spark.ml.recommendation.ALS val als new ALS() .setMaxIter(10) .setRank(12) .setRegParam(0.01) .setUserCol(userId) .setItemCol(itemId) .setRatingCol(rating) .setColdStartStrategy(drop) val model als.fit(trainSet) // 为每个用户推荐 Top10 商品 val userRecs model.recommendForAllUsers(10) userRecs.show(false)参数说明setMaxIter(10) 是 ALS 迭代次数一般 10 次足够收敛加大迭代次数收益递减。setRank(12) 是隐特征维度也就是把用户和商品映射到 12 维向量空间。rank 值太小拟合不够太大容易过拟合且训练变慢12 到 20 之间是通用区间。setRegParam(0.01) 是正则化系数防止模型过于依赖训练集中的个别数据。setColdStartStrategy(drop) 解决冷启动问题——新用户没有行为记录模型的预测结果不可靠直接丢弃而不是给出随机推荐。ALS 训练完成之后推荐结果需要回写。推荐出来的商品列表要落到 HBase 或者 Redis用户浏览商品时直接从缓存读取 Top10 推送。我见过一个团队把 ALS 推荐结果直接放在 Spark 内存里每次请求实时算用户一多就扛不住了。正确做法是离线算好、在线查询。另外提醒一句ALS 的输入是评分矩阵把浏览、加购、下单转成不同权重的评分时权重的设置要通过实验调不要拍脑袋。我一般会用 浏览1、加购2、下单5 作为初始值然后对比不同权重下推荐商品的点击率再调整。从那以后我每次搭用户画像系统都会强制走一遍“目标 → 口径 → 验证 → 沉淀”的流程规则标签能解决的绝不上模型历史指标和预测标签分开存所有标签上线前必须过区分度验证。这套习惯是从无数次翻车里总结出来的希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站