LeanCloud 的工程师如何决定晚上吃什么

LeanCloud 的工程师如何决定晚上吃什么

王子亭王子亭
在上个月 LeanCloud 在北京的办公室从北三环搬到了东二环朝阳门附近,对于我们这些晚上只能一起在外面解决晚饭的单身青年来说,晚饭的选择多了很多。之前我们其实在公司内部的 IM 上是有一个机器人的:
const 钦点 = require('random-weighted-choice');

const choices = [
  {weight: 10, id: '金城牛肉面'},
  {weight: 10, id: '重庆小面'},
  {weight: 1, id: '鸭血粉丝汤'},
  {weight: 2, id: '马甸清真寺'},
  {weight: 20, id: '桂林米粉'},
  {weight: 10, id: '煎饼果子'},
  {weight: 5, id: '请点外卖'},
  {weight: 5, id: '黄焖鸡米饭'},
  {weight: 5, id: '卤煮'},
  {weight: 5, id: '重庆小面全国五十强'},
  {weight: 3, id: '江西菜'},
  {weight: 5, id: '请点外卖'},
  {weight: 1, id: '铁锅焖面'}
];

module.exports = function(robot) {
  robot.hear(/吃/, function(res) {
    res.send(钦点(choices));
  });
}

如你所见,这是一个非常简单的随机算法,但有时它的结果并不能让大家信服:大家并不能对每一个餐馆的权重达成一致;这个简单的算法也不会考虑今天有哪些人参加、过去几天吃了什么;因为每次调用给出的结果都不一样,经常会被反复「摇」出不同的结果。

我在这个月刚刚从昆山办公室搬到北京,于是开始着手解决「晚上吃什么」这个问题,我希望建立一个评分系统 —— 每个人对每个餐馆都可以有个评分,然后机器人综合当天吃饭的每个人的评分、过去几天吃过什么给出一个确定的选择。

于是我们先来设计数据结构,其实这是一个蛮通用的需求 —— 几个人为不同的选项来设置偏好,最后选出一个结果:

  • 一个餐厅表,用来存储所有的餐厅
  • 一个偏好表,用来存储每个人对每个餐厅的评价
  • 一个就餐历史表,包括每顿饭去了哪里、都有谁参加

然后需要设计一组命令来与机器人交互,来进行餐馆列表、个人偏好的录入:

然后每天吃饭的流程是这样的:


那么最后这个建议是怎么来的呢?最基本的当然是根据大家设置的偏好,给每个餐馆一个排名:

如果一个人为很多餐馆都设置了偏好,那么他对每一个餐馆的影响权重就会变小。接下来考虑过去五天去过的餐馆,如果一个餐馆昨天刚刚去过,那么今天就不去了;如果前天去过,那么今天的权重就要降低很多等等。因为每天参加晚饭的人都是不同的,所以这个过去五天去过的餐馆是针对每一个人单独计算的,最后的结果也是一个餐馆的排名:

如果止步于此的话,可能会导致最后选择的餐馆非常单一,即使考虑过去五天去过的地方,也很有可能出现五个餐馆不断循环的情况,因此我们有必要为结果添加一丁点随机性。所以我们用餐馆的总数减去餐馆的排名(例如一共 20 个餐馆,那么排第一的餐馆就取 19),然后乘上一个随机数,最后得到一个具有权重但又有一些随机性的结果。值得一提的是这个随机数生成器是以当天的日期为种子的,因此结果虽然有随机性,但在一天内是不会变化的:

最后,在晚饭结束后还需要向机器人汇报,以便给第二天的晚饭做参考。

这个 机器人 使用了 LeanCloud 的云存储作为数据库,运行在云引擎上,通过 Webhook 接入我们团队内部的 IM。在过去的一周里,我用每天晚上等其他同事准备好出发吃饭的时间完成了这个机器人,直接使用 LeanCloud 和云引擎开发还是非常省心的,省去了配置和部署的过程,使我能够快速地迭代,最后完成这第一个版本。

想和我们一起吃晚饭?LeanCloud 目前在招聘 销售工程师、资深 Web 前端工程师、后端工程师(实时通讯系统)、产品经理、技术支持专家(全职/实习)、客户顾问、资深 Android 工程师 等职位,可点击 工作机会 查看。

文章被以下专栏收录
45 条评论
推荐阅读