如何设计投放系统系列----灵活的字段映射补全机制

简介:

引言

我们知道搭建系统跟投放系统是两个紧密关联的系统,搭建产出的是页面的结构,投放产出的是页面的数据。搭建产出的页面包含各式各样的模块,这些模块包含的字段也没有太多规律可言,那么投放系统怎么为这些模块补全数据呢?

在回答这个问题之前,我们先尝试解决一些简单的业务 case

几个案例

案例一

有一个商品模块,字段包括:商品的标题、商品图片、购买链接、商品价格、商品描述,想要投放某个选品集的商品,请问投放系统应该怎么设计以补全这些字段信息?

拿到这个需求,最直观的解决方案就是,直接去商品库取选品集对应的商品列表,把商品库里的字段塞到对应的模块字段上。

// 商品选品集
var goodSet = [1,2,3,4,5];

// 从商品库获取对应的商品实体信息
var entityMap = goodService.fetch(goodSet);


var output = [];
for (var i = 0, l = goodSet.length; i < l; ++i) {
  var goodId = goodSet[i];
  var entity = entityMap[goodId];
  if (!entity) {
    continue;
  }
  // 字段映射
  output.push({
    '商品名称': entity['goodName'],
    '商品图片': entity['goodImg'],
    '商品链接': entity['goodLink'],
    '商品价格': entity['goodPrice']
    ...
  });
}
return output;

案例二

有一个店铺模块,字段包括:店铺的名称、店铺的照片、店铺链接,想要投放某个选品集的店铺列表,请问投放系统应该怎么设计以补全这些字段信息?

这个需求跟上面一个类似,依然是最直观的解决方案,直接去店铺库取选品集对应的店铺列表,把店铺库里的字段塞到对应的模块字段上。

// 店铺选品集
var shopSet = [1,2,3,4,5];

// 从店铺库获取对应的店铺实体信息
var entityMap = shopService.fetch(shopSet);


var output = [];
for (var i = 0, l = shopSet.length; i < l; ++i) {
  var shopId = shopSet[i];
  var entity = entityMap[shopId];
  if (!entity) {
    continue;
  }
  // 字段映射
  output.push({
    '店铺名称': entity['shopName'],
    '店铺图片': entity['shopImg'],
    '店铺链接': entity['shopLink']
  });
}
return output;

案例三

同样一个商品模块,字段包括:商品的标题、商品图片、购买链接、商品价格、优惠价格,想要投放某个选品集的商品,请问投放系统应该怎么设计以补全这些字段信息?

这个 case 我们发现单纯的从商品库取不到优惠价格信息,必须去另外一个服务获取商品的优惠价格。

对应的伪代码为:

// 商品选品集
var goodSet = [1,2,3,4,5];

// 从商品库获取对应的商品实体信息
var entityMap = goodService.fetch(goodSet);


var output = [];
for (var i = 0, l = goodSet.length; i < l; ++i) {
  var goodId = goodSet[i];
  var entity = entityMap[goodId];
  if (!entity) {
    continue;
  }
  // 字段映射
  output.push({
    '商品名称': entity['goodName'],
    '商品图片': entity['goodImg'],
    '商品链接': entity['goodLink'],
    '商品价格': entity['goodPrice'],
    // 去优惠券服务获取商品的优惠价格
    '优惠价格': couponService.fetch(goodId).price
  });
}
return output;

到了这里,我们发现模块只要一变,代码就得跟着变,有没有办法能模块变化,代码不变呢?

终极解决方案

相信聪明的你已经可以看出,随着需求的变化,我们的代码变化的都是字段的补全来源以及字段的映射关系,不变的是整个代码的流程。如果我们可以把这些变化的部分做成可配置的,似乎代码就不需要变动了。

我们试着写了这样一个接口

function get(id, field);

这个接口只需要传实体的 id,以及需要返回的字段名,就可以返回对应的值。

每个字段的具体补全逻辑都是 get 的具体实现,我们把实现做成可配置的形式

商品数据源配置
{
    'goodName': {adapter: 'goodService', param: ['id', 'goodName']},
    'goodPrice': {adapter: 'goodService', param: ['id', 'goodPrice']}
    'couponPrice': {adapter: 'couponService', param: ['id', 'couponPrice']}
}
店铺数据源配置
{
    'shopName': {adapter: 'shopService', param: ['id', 'shopName']},
    'shopImg': {adapter: 'shopService', param: ['id', 'shopImg']}
}

接着我们再添加一些配置,配置的是模块素材字段跟数据源中的字段ID的映射关系

商品字段映射
模块素材字段编码 => 数据源字段 ID
{
  '商品名称': 'goodName',
  '商品图片': 'goodImg',
  '商品链接': 'goodLink',
  '商品价格': 'goodPrice',
  '优惠价格': 'couponPrice'
}

店铺字段映射
{
  '店铺名称': 'shopName',
  '店铺图片': 'shopImg',
  '店铺链接': 'shopLink'
}

最后我们再修改下伪代码:


function get(id, field) {
    var param = configService.getDatastoreConfig(field).param;
    return adapterFactory.get(field).apply(param);
}


// 选品集
var entitySet = [1,2,3,4,5];
// 实体类型
var entityType = model.entityType;
// 获取字段映射配置
var fieldMappingConfig = configService.getFieldMappingConfig(entityType);

var output = [];
for (var i = 0, l = entitySet.length; i < l; ++i) {
  var entityId = entitySet[i];

  var entity = {id: entityId};
  // 遍历模块的字段列表
  for (var j = 0; j < model.fields.length; ++j) {
    // 模块字段编码
    var field = model.fields[j];
    // 补全该字段的值,get 会用数据源配置的类和参数补全该字段的值
    entity[field] = get(entityId, fieldMappingConfig[field]);
  }

  output.push(entity);
}
return output;

上面其实也是我们 UTCP 系统目前的设计思路。

get

get 接口对应的就是 AbstractEntity.get 方法。

字段映射配置

image.png

数据源配置

image.png

目录
相关文章
|
12天前
|
存储 人工智能 Java
【程序设计】做一个发送系统邮件的功能,如何设计数据表? 转至元数据结尾
重构系统邮件发送旨在实现统一的邮件发送功能,通过公共API提供服务。设计包括两个核心数据表:`mail` 表用于存储邮件基本信息,如邮件ID、业务类型、发送者、标题、内容、附件信息、发送状态和时间戳;`mail_receiver` 表记录邮件接收者信息,包括邮件ID、接收者邮箱、接收者类型、发送状态和重试次数。为了优化查询性能,建议创建`Email_Content`表,将`content`和`attach_file`从`Email`表中分离,以减少主表大小。这有助于提高主表的查询速度,并通过定期的数据结转策略,确保热表只存储最近的数据。
43 0
|
2月前
|
存储 算法 数据库
【C++ 软件设计思路】学习C++中如何生成唯一标识符:从UUID到自定义规则
【C++ 软件设计思路】学习C++中如何生成唯一标识符:从UUID到自定义规则
156 0
|
2月前
行为关系支持配置码表:让标签加工与理解更直观!
该功能解决了在行为分析和标签处理中,编码字段理解困难的问题。它允许标签开发人员在配置行为关系时直接关联码表,便于识别字段含义,同时,也让业务人员在查看标签时能直接看到真实含义,提高工作效率。此更新简化了工作流程,提升了标签资产的理解度。
行为关系支持配置码表:让标签加工与理解更直观!
|
2月前
|
存储 自然语言处理
平台设计-代码字段与标签
在平台里描述对象的属性可以使用代码和标签
|
10月前
|
存储 JSON BI
如何使用事物码 SAT 查找某个 SAPGUI 屏幕字段对应的后台存储数据库表的名称试读版
如何使用事物码 SAT 查找某个 SAPGUI 屏幕字段对应的后台存储数据库表的名称试读版
|
2月前
|
人工智能 算法 测试技术
【简历优化平台-03】轻字段信息的合理性及单独算法
【简历优化平台-03】轻字段信息的合理性及单独算法
|
11月前
|
SQL Java 关系型数据库
从系统报表页面导出20w条数据到本地只用了4秒,我是如何做到的
最近有个学弟找到我,跟我描述了以下场景: 他们公司内部管理系统上有很多报表,报表数据都有分页显示,浏览的时候速度还可以。但是每个报表在导出时间窗口稍微大一点的数据时,就异常缓慢,有时候多人一起导出时还会出现堆溢出。 他知道是因为数据全部加载到jvm内存导致的堆溢出。所以只能对时间窗口做了限制。以避免因导出过数据过大而引起的堆溢出。最终拍脑袋定下个限制为:导出的数据时间窗口不能超过1个月。
|
12月前
|
存储 机器人 应用服务中间件
|
消息中间件 人工智能 算法
很全的敏感词匹配系统的设计与实践(1)
很全的敏感词匹配系统的设计与实践(1)
|
开发框架 前端开发 JavaScript
java程序设计与j2ee中间件技术/软件开发技术(III)-大作业-采用MVC模式实现商品信息的查询显示(可以模糊查询)、增加和删除功能,商品表自拟,实现简单菜单操作和分页显示(一)
java程序设计与j2ee中间件技术/软件开发技术(III)-大作业-采用MVC模式实现商品信息的查询显示(可以模糊查询)、增加和删除功能,商品表自拟,实现简单菜单操作和分页显示
326 1
java程序设计与j2ee中间件技术/软件开发技术(III)-大作业-采用MVC模式实现商品信息的查询显示(可以模糊查询)、增加和删除功能,商品表自拟,实现简单菜单操作和分页显示(一)