新手友好!基于零代码平台浏览器市场与用户画像分析-数据加工(1)全流程演示
一、实验背景
1.1实验目的
- 熟悉数据集构成与半结构化日志数据特点,掌握文本日志解析、字段拆分的实操方法
- 完成数据规整,将零散原始日志转化为标准结构化数据表
- 实现多维度数据聚合、字段衍生与跨表关联,搭建适配分析场景的指标体系
1.2实验环境
- 零代码在线实验平台:本次实验基于助睿数智平台:
- 数据集成平台(助睿 ETL)
- 助睿BI 数据可视化探索平台
- MySQL
- 数据规模:1000 用户,800 万 + 条行为记录,约 825MB
1.3 实验数据
本实验基于首届中国互联网数据挖掘竞赛公开数据集开展,是非常典型的计算机用户行为半结构化日志数据,专门用于用户行为分析、习惯挖掘、活跃度预测与用户画像研究
二、实验步骤
2.1 日志数据结构化转换
新建项目,输入名称 “互联网用户行为日志数据加工”,点击确定创建。由于本次实验的数据量过大,我们仅使用其中 20 个 TXT 数据来学习如何将半结构化数据转换为结构化数据。
首先获取本次的实验数据集:打开项目,点击 “文件库”,右键根目录,点击 “新建目录”,输入目录名为 “互联网用户行为日志数据集”,点击确定。
接下来点击 “公共空间”,点击 “数据资源”,点击属于 “互联网用户行为日志数据集” 下的数据卡片右上角的更多,并点击 “导出”,在弹出的窗口中选择导出到刚刚创建的目录下,点击 “确定”。
可以看到在 “互联网用户行为日志数据集” 的目录下,新增了数据文件。接下来重复以上导出操作,将本次实验用到的 20 个数据都导出到 “互联网用户行为日志数据集”。
新建转换并命名为 “互联网用户行为日志数据表”,在该工作流中拖拽执行一个 SQL 脚本组件,通过执行 SQL 脚本创建一个标签表。
选择目标数据库连接 “团队私有数据库”,注入SQL脚本,完成后运行转换流
SQL 脚本如下:
CREATE TABLE behavior_events ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键', session_id VARCHAR(255) COMMENT '会话唯一ID', user_id VARCHAR(100) COMMENT '用户ID', session_start_time VARCHAR(50) COMMENT '会话开始时间', event_seconds INT COMMENT '事件发生秒数', process_name VARCHAR(255) COMMENT '进程名称', process_id VARCHAR(100) COMMENT '进程ID', url TEXT COMMENT '访问网址', addr_handle VARCHAR(255) COMMENT '地址栏句柄', tab_handle VARCHAR(255) COMMENT '标签页句柄', browser_version VARCHAR(100) COMMENT '浏览器版本', window_handle VARCHAR(255) COMMENT '窗口句柄', app_name VARCHAR(255) COMMENT '程序名称', company_name VARCHAR(255) COMMENT '开发公司', source_file VARCHAR(255) COMMENT '原始日志文件名', create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间', INDEX idx_session_id (session_id), INDEX idx_user_id (user_id) ) COMMENT '用户行为事件明细表';新建转换并命名为 “日志文件名批量采集”,在该工作流中拖拽 “获取文件名” 组件。
双击 “获取文件名” 组件,在配置窗口中点击文件或目录后的 “浏览文件” 按钮,在弹出的窗口中选择我们上面创建的目录 “互联网用户行为日志数据集”,单击 “确定”。
选择目录后,点击 “增加”,选择的目录出现在下方的路径中,点击 “确认”。
拖拽Java 代码组件组件到画布中,并创建 “获取文件名组件” 到 “Java 代码” 的连线,连接类型选择主输出步骤。
双击 “Java” 组件,输入以下代码:
// 全局变量定义 String pathField; String shortFilenameField; public boolean processRow() throws HopException { if (first) { pathField = "filename"; shortFilenameField = "short_filename"; first = false; } Object[] r = getRow(); if (r == null) { setOutputDone(); return false; } String path = get(Fields.In, pathField).getString(r); String short_filename = get(Fields.In, shortFilenameField).getString(r); String user_id = ""; String l_start = ""; if (short_filename != null) { String name = short_filename.replace(".txt", ""); String[] parts = name.split("_"); if (parts.length >= 3) { user_id = parts[0]; l_start = parts[1] + " " + parts[2].replace("-", ":"); } } String session_id = user_id + "_" + l_start; java.io.BufferedReader br = null; try { br = new java.io.BufferedReader(new java.io.FileReader(path)); String line = ""; // 跳过前两行(Last和L_Start) br.readLine(); br.readLine(); while ((line = br.readLine()) != null) { if (line.trim().isEmpty()) { continue; } // 解析键值对 String[] kvPairs = line.split("\\[=\\]"); String t = ""; String p = ""; String i = ""; String u = ""; String a = ""; String b = ""; String v = ""; String w = ""; String n = ""; String c = ""; for (String kv : kvPairs) { int sepIdx = kv.indexOf("<=>"); if (sepIdx == -1) { continue; } String key = kv.substring(0, sepIdx).trim(); String val = kv.substring(sepIdx + 3); if ("T".equals(key)) { t = val; } else if ("P".equals(key)) { p = val; } else if ("I".equals(key)) { i = val; } else if ("U".equals(key)) { u = val; } else if ("A".equals(key)) { a = val; } else if ("B".equals(key)) { b = val; } else if ("V".equals(key)) { v = val; } else if ("W".equals(key)) { w = val; } else if ("N".equals(key)) { n = val; } else if ("C".equals(key)) { c = val; } } // 创建输出行 Object[] outRow = createOutputRow(r, data.outputRowMeta.size()); get(Fields.Out, "session_id").setValue(outRow, session_id); get(Fields.Out, "user_id").setValue(outRow, user_id); get(Fields.Out, "l_start").setValue(outRow, l_start); get(Fields.Out, "t").setValue(outRow, t); get(Fields.Out, "p").setValue(outRow, p); get(Fields.Out, "i").setValue(outRow, i); get(Fields.Out, "u").setValue(outRow, u); get(Fields.Out, "a").setValue(outRow, a); get(Fields.Out, "b").setValue(outRow, b); get(Fields.Out, "v").setValue(outRow, v); get(Fields.Out, "w").setValue(outRow, w); get(Fields.Out, "n").setValue(outRow, n); get(Fields.Out, "c").setValue(outRow, c); get(Fields.Out, "source_file").setValue(outRow, short_filename); putRow(data.outputRowMeta, outRow); } } catch (Exception e) { logError(e.getMessage(), e); } finally { try { if (br != null) { br.close(); } } catch (Exception e) { // ignore } } return true; }在字段空白表格处依次插入将java代码中输出的字段进行配置,参考如下:
字段名 | 类型 |
session_id | String |
user_id | String |
l_start | String |
t | String |
p | String |
i | String |
u | String |
a | String |
b | String |
v | String |
w | String |
n | String |
c | String |
source_file | String |
配置完成后点击“确认”
拖拽 “字段选择” 组件到画布中,创建 “Java 代码组件” 到 “字段选择” 组件的连线,连接类型选择主输出步骤。
双击 “字段选择” 组件,点击移除选项,并在字段名称下方空白处点击 “获取字段”,选中上一步骤中的Java代码输出的字段后,右键删除选中的行,最后剩下的字段点击确认。
拖拽 “表输出” 组件到画布中,创建 “字段选择” 组件到 “表输出” 组件的连线,连接类型选择主输出步骤。
双击 “表输出” 组件,进行如下配置
在数据库字段中,建立表字段与流字段的映射关系后点击确认,最后执行转换流
打开 “元数据” 页面,在 “团队私有数据库” 上右键选择 “加载元数据”,点击数据探查,选中目标表 behavior_events点击查询,查看数据是否符合预期。
2.2 数据分析方向确定
得到 behavior_events 后,我们需要决定分析什么。对 behavior_events 按进程名 process_name 统计使用人数,可以快速看出哪些程序覆盖的用户最广。这个统计的价值在于:它能帮我们从九百多万条杂乱记录中,迅速锁定最值得分析的候选对象。
2.3 分析方案设计与数据确定
新建转换工作流,并命名为“创建进程统计表”,在该工作流中拖拽“执行一个SQL脚本”组件,通过执行SQL脚本来创建一个标签表
配置如下:
SQL脚本:
-- 创建程序/软件统计表 CREATE TABLE program_stats ( program_name VARCHAR(255) NOT NULL, -- 程序/软件名称 user_count INT NOT NULL -- 使用用户数 );由于数据量较大,为了顺利运行转换流,我们点开“元数据”,双击“团队私有数据库”,勾选“使用结果流”。完成后运行转换流
新建转换流“统计进程用户规模”,拖拽“表输入”组件到画布中,数据库连接选择“团队私有数据库”,并获取 behavior_events 得所有SQL查询语句
拖拽“字段选择”组件到画布中,并创建“表输入”组件到“字段选择”组件得连线,双击“字段选择”组件,点击tab选项“移除”,然后再字段名称下方空白处右键点击“获取字段”,选中user_id、process_name 两个字段,右键点击“删除选中的行”
字段 process_name 可能存在空值,为避免后续操作错误,需要将空值替换为“未知”。拖拽“替换NULL值”组件到画布中,并创建“字段选择”组件到“替换NULL值”组件的连线,连接线类型选中“主输出步骤”。 双击“替换NULL值”组件,勾选“选择字段”,在下方字段表格中插入一行,并配置如下:
拖拽“排序字段”组件到画布中,创建“替换NULL值”组件到“排序记录”组件的连线,连接线类型选中“主输出步骤”, 双击“排序记录”组件,将数据按照“process_name”字段升序排序
接下来就可以对排序后的数据进行分组聚合统计了,拖拽“分组”组件到画布中,创建“排序记录”组件到“分组”组件的连线,双击分组组件并按如下配置:
拖拽 “表输出” 组件,创建 “分组” 组件到 “表输出” 组件的连线。双击 “表输出” 组件,选择团队私有数据库,目标表为 “program_stats”,指定数据库字段,建立字段映射,最后执行转换即可
点击实验平台左边菜单“助睿BI”,进入助睿BI首页,由于之前的实验已经创建了团队私有数据库的数据源连接,本次实验无需再创建数据源连接,可直接创建数据集
右上角数据源选择进程统计表 program_stats 所在位置,将 program_stats 拖拽至画布中,为了方便观察,可以将字段备注修改为中文,修改完成后保存并发布
新建“进程用户数量分析”工作表,数据集选择刚刚创建的数据集“进程用户数据统计”,图表类型选择“水平条图”,将字段“program_name”拖拽至Y轴,“user_count”拖拽至X轴,并将“user_count”按照降序排序
由此,我们可以看到,浏览器类进程的用户数明显高于其他软件。这表明浏览器是覆盖面最广的应用,样本充足;同时浏览器记录包含 url,可进一步分析网站偏好。因此,确定浏览器为分析对象,并围绕以下业务问题展开分析:
- 浏览器市场格局:哪些浏览器用户最多、使用时长最长?
- 用户画像:不同浏览器的用户在年龄、职业上有何差异?
- 使用习惯:用户集中在什么时段使用浏览器?
- 竞争迁移:用户是否会从一款浏览器切换到另一款?
- 流失预测:哪些用户可能停止使用 iexplore.exe 浏览器?
- 个性化推荐:根据用户的网站访问历史,可以推荐哪些网站?
为了回答这些问题,我们可以预先设计一套可视化方案。下表列出了每张图表对应的业务问题、所需数据字段以及最终输出的数据表名,后续数据加工将围绕它们展开。
输出表名 | 内容 | 粒度 |
browser_coverage.csv | 每个浏览器的用户数、总使用时长 | 每个浏览器一行 |
browser_hourly.csv | 每个浏览器按小时统计活跃用户数 | 浏览器 × 小时 |
browser_demographic.csv | 每个浏览器按年龄分段、职业的用户分布 | 浏览器 × 年龄组 × 职业 |
browser_retention.csv | 每个浏览器从第3周到第4周的留存率 | 每个浏览器一行 |
browser_migration.csv | 用户从第3周主用浏览器切换到第4周主用浏览器的迁移对及人数 | 源浏览器 → 目标浏览器 |
churn_features.csv | 每个用户前三周的 Chrome 行为特征及标签 | 每个用户一行 |
churn_probability.csv | 每个用户的流失概率(AI Studio 输出) | 每个用户一行 |
feature_importance.csv | 流失预测模型的特征重要性 | 每个特征一行 |
high_risk_users.csv | 流失概率最高的 20% 用户及其关键特征 | 每用户一行(约200行) |
本次实验我们先完成前2个数据的加工,首先需要在团队私有数据库中先创建这2个数据表
创建两个转换流“创建浏览器的用户数总使用时长统计表”、“创建每个浏览器按小时统计活跃用户数统计表”,两个转换流各拖拽“执行一个SQL脚本”组件到画布中,分别输入对应SQL:
创建浏览器的用户数总使用时长统计表SQL:
CREATE TABLE `browser_coverage` ( `browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名', `user_count` INT NOT NULL COMMENT '使用用户数(去重)', `total_duration_sec` BIGINT NOT NULL COMMENT '总使用时长(秒)' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浏览器用户覆盖率与总时长';创建每个浏览器按小时统计活跃用户数统计表SQL:
CREATE TABLE `browser_hourly` ( `browser_name` VARCHAR(50) NOT NULL COMMENT '浏览器进程名', `hour` TINYINT NOT NULL COMMENT '小时(0-23)', `active_user_count` INT NOT NULL COMMENT '活跃用户数', PRIMARY KEY (`browser_name`, `hour`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浏览器按小时活跃用户数';2.4 数据清洗、聚合与关联加工
新建转换流“互联网用户行为日志数据清洗抽取”, 拖拽 “表输入” 组件到画布中,连接线上公共数据源(因为团队私有数据库中的数据只有 20 个数据,仅作教学,全部数据已存放在线上公共数据源中的 behavior_events 表中),获取 behavior_events 的所有 SQL 查询语句。
拖拽 “字段选择” 组件到画布中,创建 “表输入” 组件到 “字段选择” 组件的连线。双击 “字段选择” 组件,点击移除 tab 选项,在字段名称下方空白处右键点击 “获取字段”,选中 session_id, user_id, session_start_time, process_name, url, event_seconds 后删除选中的行,保留下来的字段就是要移除的字段,点击 “确认”。
拖拽 “过滤记录” 组件到画布中,创建 “字段选择” 组件到 “过滤记录” 组件的连线,连接类型选择主输出步骤。
拖拽 “排序记录” 组件到画布中,创建 “过滤记录” 组件到 “排序记录” 组件的连线,连接类型选择 True 输出步骤。
再拖一个 “空操作(什么也不做)” 组件到画布中,创建 “过滤记录” 组件到 “空操作(什么也不做)” 组件的连线,连接类型选择 False 输出步骤。
双击 “过滤记录” 组件,设置过滤条件:
点击第一个“field”,选择“process_name”,表示过滤条件为process_name的值
点击中间的函数符号,选择“IN LIST”
点击“value”,类型选择“String”,值为主要浏览器的进程名:“iexplore.exe;360chrome.exe;360se.exe;chrome.exe;sogouexplorer.exe;QQBrowser.exe”,表示process_name的值在其中的记录则为True,否则为False
原始日志只记录了焦点切换的时刻,没有直接给出停留时长。但通过前后两条记录的 event_seconds 相减,就能算出用户在每个窗口上停留了多久。这个时长是后续聚合(总使用时长)的基础数据。
这一步骤需要用到3个组件:
- 排序记录:按 session_id 和 event_seconds 升序排列,确保同一个会话内的行为按时间顺序处理
- 分析查询:获取同一会话内下一行的 event_seconds 值,存入新字段 next_event_seconds
- 计算器:计算 next_event_seconds - event_seconds 得到停留时长 duration_sec
首先,“排序记录”组件在上一步骤已经拖入了,双击“排序记录”组件,按 session_id 和 event_seconds 升序排列
拖拽“分析查询”组件到画布中,创建“排序记录”组件到“分析查询”组件的连线,双击“分析查询”组件,分组字段为“session_id”,新增加的字段“next_event_seconds”,要取值的字段为“event_seconds”,类型“前第N行”,N为“1”
拖拽 “计算器” 组件到画布中,创建 “分析查询” 组件到 “计算器” 组件的连线。双击 “计算器” 组件,插入新字段行,新字段输入 “duration_sec”,计算公式选择 “A - B”,字段 A 选择 “next_event_seconds”,字段 B 选择 “event_seconds”,值类型为 “Integer”。
使用 “字段选择”,只保留 user_id, process_name, session_start_time, url, duration_sec。
使用 “过滤记录” 组件,过滤掉 duration_sec <= 0 的记录,配置如下;
拖拽 “剪切字符串” 组件到画布中,创建过滤记录 1 组件到拖拽剪切字符串组件的连线,连接类型选择 True 输出,配置如下:
目前获取的数据中,session_start_time 的类型为String,为方便提前提取好小时,需要将session_start_time 的类型设置为Date。拖拽字段选择组件到画布中,创建剪切字符串组件到字符选择组件的连线,连接线类型选择“主输出步骤”,字段选择2组件的配置如下:
通过计算器组件,我们可以提取 yyyy-MM-dd HH:mm:ss 中的HH,拖拽计算器组件到画布中,创建字符选择组件到计算器组件的连线,连接线类型选择“主输出步骤”,计算器 1组件的配置如下:
原始数据是每条窗口切换记录,粒度太细。我们真正关心的是“每个用户每天每浏览器每小时用了多久、启动了几次”。这一步将数据压缩到合适的粒度,同时为后续所有统计表提供统一的基础数据。
接下来我们就可以分组聚合组件来统计用户每天使用浏览器的时段数据了,但在分组聚合前,先使用排序记录组件进行排序,避免分组聚合结果出错
拖拽排序记录组件到画布中,创建“计算器 1”组件到“排序记录 1”组件的连线,排序记录 1组件的配置如下:
接下来,拖拽分组组件,创建“排序记录 1”组件到分组组件的连线,分组组件的配置如下:
接下来我们先生成市场格局表:
拖拽分组组件到画布中,创建“分组”组件到“分组 1”组件的连线,配置如下:
拖拽“表输出”组件到画布中,创建“分组 1”组件到“表输出 组件的连线”,配置如下:
接着我们生成时段统计表:
拖拽“排序记录”组件到画布中,创建“分组”组件到“排序记录 2”组件的连线,数据传输模式选择复制发送,排序记录配置如下:
拖拽分组组件到画布中,创建“排序记录 2”组件到“分组 2”组件的连线,分组配置如下:
拖拽“表输出”组件到画布中,创建“分组 2”组件到“表输出 1组件的连线”,配置如下:
最后我们的完整转换流如下:
运行转换流,运行完成后加载元数据,在数据探查中选中两个表查询数据是否符合预期
三、实验结果
日志数据结构化转换完成:
成功将 20 个半结构化 TXT 日志文件解析为标准结构化数据,写入behavior_events用户行为事件明细表。
字段完整包含会话 ID、用户 ID、会话开始时间、事件秒数、进程名称、URL、浏览器版本、来源文件等,数据格式规范、可用于后续分析。
进程用户规模统计完成:
成功生成program_stats进程用户数量统计表,按进程名统计去重用户数。
统计结果显示:浏览器类进程(360chrome、chrome、IE、QQ 浏览器等)用户数远高于其他软件,确定以浏览器为核心分析对象。
浏览器核心指标表生成:
成功创建browser_coverage表,统计各浏览器去重用户数与总使用时长,清晰呈现市场格局。
成功创建browser_hourly表,按 0–23 小时统计各浏览器活跃用户数,形成用户时段分布特征。
数据清洗与加工完成:
完成浏览器数据筛选、停留时长计算、日期 / 小时提取、空值处理、去重与聚合。
输出粒度统一、质量可靠的小时级用户行为明细,可直接支撑 BI 可视化与用户画像分析。
四、问题与解决
4.1 问题
问题:执行统计用户进程规模转换流和日志数据抽取加工转换流时报错显示无数据
4.2 原因
原因:平台不稳定
4.3 解决
解决:重新运行转化为结构数据转换流,接着按序运行统计用户进程规模转换流和日志数据抽取加工转换流
五、实验总结
本次实验基于助睿数智零代码 ETL 平台,完成互联网用户行为日志从半结构化解析、结构化转换、数据清洗聚合到指标输出的全流程数据加工,成功实现日志文件批量导入、SQL 建表、日志解析、字段筛选、时长计算、分组统计与表输出等操作,生成用户行为明细、进程用户统计、浏览器市场格局与时段活跃等标准数据表,明确浏览器为核心分析对象并完成关键指标建模。实验过程中解决了平台不稳定导致的无数据报错问题,掌握了零代码数据集成与可视化分析的核心方法,达成数据规整、多维度聚合与业务化指标输出的目标,为后续用户画像、行为分析与数据可视化奠定了扎实基础。
