每日一题:个性化推荐

介绍

当下,移动互联网技术和智能手机的发展,使得采集用户数据的能力变得空前强大,无时无刻,无所不在。拥有这些数据后,全行业的个性化推荐能力变得更加容易实现,不论是淘宝京东,还是今日头条,无疑是这个时代的最大受益者。个性化推荐的本质是根据不同的人群,将最有可能感兴趣的内容优先推荐给相应的用户,最大限度的提高转化率。

本题需要在已提供的基础项目中,使用 Nodejs 实现个性化推荐的效果。

准备

本题已经内置了初始代码,打开实验环境,目录结构如下:

1
2
3
4
5
├── index.html
├── customized.html
├── data.json
└── js
└── index.js

其中:

  • index.html 是标签选择页面。
  • customized.html 是根据选择标签渲染的个性化推荐页面。
  • data.json 是后台标签的数据文件。
  • js/index.js 是需要补充代码的文件。

注意:打开环境后发现缺少项目代码,请手动键入下述命令进行下载:

1
2
cd /home/project
wget https://labfile.oss.aliyuncs.com/courses/14311/10.zip && unzip 10.zip && rm 10.zip

目标

请在 js/index.js 文件中补全代码,最终实现个性化推荐的功能。

首先,在终端运行以下命令启动服务器:

1
node ./js/index.js

当看到终端输出:server is running in port 8080,表明服务器启动成功。

并在浏览器中通过 8080 端口预览 index.html 页面,显示如下所示:

起始页面

在完成勾选后,点击确认,页面会发送 post 请求并跳转到新的页面,你需要根据用户的勾选项,从 data.json 中查询对应的数据,并读取 customized.html 文件的内容,两者结合生成结果页面数据,并返回给前端浏览器:

  1. 如果用户没有勾选任何标签,直接点击确认,新页面给与提示:

提示

提示信息的 DOM 结构如下:

1
<div class="unselect">你还未选择任何感兴趣的标签!</div>
  1. 如果用户勾选了标签,则返回对应的标签的查询信息以及相关推荐,比如用户选择了标签 Javascript,除了查询tagJavascript的内容,也需要查询Javascript的相关推荐标签HTML5CSS3
    的内容(即 relevance字段对应的数据),一并返回。
    • 注意:不再需要进一步查询相关推荐的相关推荐,即不需要查询 HTML5 的相关推荐标签的内容。
  • 多个标签之间的相关标签可能重复,需要对查询内容进行去重,比如选择了标签 JavascriptCSS3,最终的去重结果应该是标签 JavascriptCSS3HTML5 的内容。

选择

结果

每一条信息的 DOM 结构如下:

1
2
3
4
<div class="interest">
<div class="tag">标签名</div>
<div>标签内容</div>
</div>

customized.html 文件中已提供基础的样式,请保证你生成的节点带有指定的 class 信息,并填充到 body 中。 在代码更新后,请记得重启服务器!

规定

  • 请勿修改 js/index.js 文件外的任何内容。
  • 请严格按照考试步骤操作,切勿修改考试默认提供项目中的文件名称、文件夹路径、class 名、id 名、图片名等,以免造成无法判题通过。
  • 满足题目需求后,重启服务器并保持 Web 服务处于可以正常访问状态,点击「提交检测」系统会自动判分。

判分标准

  • 完成目标 1,得 5 分。
  • 完成目标 2,得 20 分。

总通过次数: 50 | 总提交次数: 115 | 通过率: 43.5%

题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
req.on("end", () => {
let { interested = [] } = qs.parse(body);
// TODO: 补充个性化页面处理代码
let html = ''
if (!interested.length) {
html = `<div class="unselect">你还未选择任何感兴趣的标签!</div>`
} else {
// 处理interested只有一个,不是数组的情况
const hashMap = {}
const result = []
if (!Array.isArray(interested)) interested = [interested]
for(let i = 0; i < interested.length; i++) {
// 外层遍历
for(let j = 0; j < data.length; j++) {
// 内层遍历匹配
if (interested[i] === data[j]['tag'] && !hashMap[interested[i]]) {
// 使用tag匹配,如果匹配,和不重复出现(hashMap)就填入数据
result.push(data[j])
hashMap[interested[i]] = 1
// 深度优先,在此遍历re
for(let tag of data[j]['relevance']) {
// 这里也可以用hashmap,都行
if (interested.indexOf(tag) === -1) {
interested.push(tag)
}
}
}
}
}
// 处理html
for(let item of result)
html += `<div class="interest">
<div class="tag">${item.tag}</div>
<div>${item.content}</div>
</div>`
// console.log(html);
}
let customized = fs.readFileSync(path.join(__dirname, "../customized.html"), {
encoding: "utf8",
});
customized = customized.replace('<body></body>', `<body>${html}</body>`)
// 将读取的 index.html 内容写入响应中,并返回给前端展示
res.writeHead(200, { "Content-Type": "text/html" });
res.write(customized);
res.end();
});