当前位置:网站首页>表达式引擎在转转平台的实践
表达式引擎在转转平台的实践
2022-08-01 10:52:00 【InfoQ】
一、业务背景介绍
二、工程现状
{
"label_红布林标签ID": {
"url": "红布林落地页地址",
"name": "红布林配置",
"其他字段": "省略表示"
},
"uid_帮卖用户ID_searchType_2": {
"url": "转转帮卖暗拍落地页地址",
"name": "转转帮卖暗拍配置",
},
"uid_帮卖用户ID": {
"url": "转转帮卖落地页地址",
"name": "转转帮卖配置",
},
"cateId_图书社会科学分类ID": {
"url": "图书科学类落地页地址",
"name": "图书科学类配置",
},
"cateId_图书自然科学分类ID": {
"url": "图书科学类落地页地址",
"name": "图书科学类配置",
}
}

- 每次新增一种配置维度,需要上线才能完成Key的拼接逻辑和读取逻辑,且读取的优先级硬编码。
- 已有的属性无法自由组合,如转转帮卖暗拍配置的规则为:卖家ID+搜索类型叠加,只能硬编码的方式进行拼接Key,下次的组合维度发生变化还需要开发。
- 相同业务需要维护多条配置,如图书社会科学和自然科学对应的落地页地址都是一个,按照Map的的配置方式需要配置2条、3条、甚至更多。
- 长此以往,Key的拼接和解析逻辑越来越难以维护,配置也越来越庞大。
- 每次上线只是开发拼接Key的逻辑和读取逻辑,都是重复工作,成本高,收益低。
三、方案选型
四、使用表达式引擎重构
4.1 架构设计

4.2 配置重构
[
{
"url": "红布林落地页地址",
"name": "红布林配置",
"ruleEl": "list.contains(labelList, 红布林标签ID)",
"priority": 20,
"其他字段": "省略表示"
},
{
"url": "转转帮卖暗拍落地页地址",
"name": "转转帮卖暗拍配置",
"ruleEl": "帮卖用户ID == product.userId && 2 == product.product.searchType",
"priority": 20
},
{
"url": "转转帮卖落地页地址",
"name": "转转帮卖配置",
"ruleEl": "帮卖用户ID == product.userId",
"priority": 20
},
{
"url": "游戏代练陪玩落地页地址",
"name": "游戏代练陪玩配置",
"ruleEl": "代练分类ID == product.cateId || 陪玩分类ID == product.cateId",
"priority": 20
},
]
4.3 上线小插曲
-XX:+TraceClassLoading
[Loaded Script_1645773082560_152/982082822 from com.googlecode.aviator.Expression]
[Loaded Script_1645773082514_151/1163475645 from com.googlecode.aviator.Expression]
com.googlecode.aviator下的Expression
Script_当前时间戳_一个ID
public Object execute(final String expression, final Map<String, Object> env,
final boolean cached) {
// 1.编译表达式
Expression compiledExpression = compile(expression, cached);
if (compiledExpression != null) {
return compiledExpression.execute(env);
} else {
throw new ExpressionNotFoundException("Null compiled expression for " + expression);
}
}
public Expression compile(final String expression, final boolean cached) {
if (expression == null || expression.trim().length() == 0) {
throw new CompileExpressionErrorException("Blank expression");
}
if (cached) { // 2.缓存开启与否
FutureTask<Expression> task = this.cacheExpressions.get(expression);
if (task != null) {
return getCompiledExpression(expression, task);
}
task = new FutureTask<Expression>(new Callable<Expression>() {
@Override
public Expression call() throws Exception {
return innerCompile(expression, cached);
}
});
FutureTask<Expression> existedTask = this.cacheExpressions.putIfAbsent(expression, task);
if (existedTask == null) {
existedTask = task;
existedTask.run();
}
return getCompiledExpression(expression, existedTask);
} else {
// 3.实时编译
return innerCompile(expression, cached);
}
}
public ASMCodeGenerator(final AviatorEvaluatorInstance instance,
final AviatorClassLoader classLoader, final OutputStream traceOut, final boolean trace) {
this.classLoader = classLoader;
this.instance = instance;
this.compileEnv = new Env();
this.compileEnv.setInstance(this.instance);
// 上面打印的生成ASM的类名
this.className = "Script_" + System.currentTimeMillis() + "_" + CLASS_COUNTER.getAndIncrement();
// Auto compute frames
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
visitClass();
}
4.4 重构前后对比
- 封装后的组件大量应用到列表页,首页等场景中,动态灵活的规则配置在大促618,双11期间事半功倍。
- 利用表达式内置的函数和自定义函数,避免同类需求多次开发,避免重复造轮子。
- 常规类配置需求,利用表达式引擎基本做到需求变更无上线。
五、总结和感悟
边栏推荐
- MFC implementation road map navigation system
- Small application project works WeChat gourmet recipes applet graduation design of finished product (1) the development profile
- Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (4) Opening Report
- Custom Types - Enums, Unions
- 进制与转换、关键字
- 如何设计一个分布式 ID 发号器?
- Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (3) Background Functions
- Generate certificates using KeyStore
- DBPack SQL Tracing 功能及数据加密功能详解
- C#/VB.NET 将PPT或PPTX转换为图像
猜你喜欢
Promise学习(一)Promise是什么?怎么用?回调地狱怎么解决?
PowerPC技术与市场杂谈
Solve vscode input! Unable to quickly generate skeletons (three methods for the new version of vscode to quickly generate skeletons)
EasyRecovery热门免费数据检测修复软件
STM32 Personal Notes - Watchdog
冰冰学习笔记:gcc、gdb等工具的使用
Google Earth Engine APP——15行代码搞定一个inspector高程监测APP
解决vscode输入! 无法快捷生成骨架(新版vscode快速生成骨架的三种方法)
小程序毕设作品之微信美食菜谱小程序毕业设计成品(3)后台功能
jmeter
随机推荐
解决new Thread().Start导致高并发CPU 100%的问题
gc的意义和触发条件
Stone Technology builds hard-core brand power and continues to expand the global market
Introduction to data warehouse layering (real-time data warehouse architecture)
retired paddling
MFC实现交通图导航系统
【cartographer ros】10: Delay and error analysis
回归预测 | MATLAB实现TPA-LSTM(时间注意力注意力机制长短期记忆神经网络)多输入单输出
Why Metropolis–Hastings Works
冰冰学习笔记:gcc、gdb等工具的使用
怎么找出电脑隐藏的软件(如何清理电脑隐藏软件)
AI篮球裁判火了,走步算得特别准,就问哈登慌不慌
RK3399平台开发系列讲解(内核入门篇)1.52、printk函数分析 - 其函数调用时候会关闭中断
pgAdmin 4 v6.12 发布,PostgreSQL 开源图形化管理工具
activiti工作流的分页查询避坑
CTO strongly banning the use of the Calendar, that in what?
【随心笔记】假期快过去了,都干了点什么
How I secured 70,000 ETH and won a 6 million bug bounty
复现assert和eval成功连接或失败连接蚁剑的原因
DBPack SQL Tracing 功能及数据加密功能详解