本文重点为介绍一个计算广告的匹配算法,来自 Indexing Boolean Expression 。这种匹配算法可以匹配较为复杂的布尔表达式。
尽量以说人话的方式解释这种算法。
不涉及权重排序等规则。
document1: { a: [1,2] },document2: { a:[1], b: [9] }
a.1: [document1, document2], a.2: [document1],b.1: [document2]
既然所有的逻辑公式都可以转为 CNF,那么我们的目标就是实现一个可快速查找目标所匹配的 CNF 布尔表达式(boolean expressions)的算法。
先来匹配 DNF 表达式
=
的数量记为 ks1: a=1、b=3
为例所以可以将 k > 2 的直接排除掉a 存在 且 b 不存在
以 ElasticSearch 为例,说明如何将匹配规则存入和如何匹配目标
匹配规则 BE1: (a == 1 | a == 2 | b = 3) && c!=1 |
// 文档1,在查询时 [1,2] 满足一个即可,所以可以将同一子句中 a 的两个值合并在一起
{
BE: 'BE1',
a: [1,2],
info: {
C: 1,
d: '=',
trueList: [0, -1]
},
}
// 文档2
{
BE: 'BE1',
b: 3,
info: {
C: 1,
d: '=',
trueList: [0, -1]
}
}
// 文档3
{
BE: 'BE1',
c: 1,
info: {
C: 2,
d: '!=',
trueList: [0, -1]
}
}
// 也可以将匹配规则的真值计数器 trueList 存在别的地方
{
"query": {
"bool": {
"should": [
{
term: {
a: 1
}
},
{
term: {
b: 2
}
}
]
}
}
}
// 只命中了 a
{
BE: 'BE1',
a: [1,2],
info: {
C: 1,
d: '=',
trueList: [0, -1]
},
}
以下实践结论来自 windows 平台 Edge 浏览器与 mac 平台 Chrome 浏览器
// worker.js
self.addEventListener("install", (event) => {
self.skipWaiting()
})
self.addEventListener('activate', (event) => {
event.waitUntil(() => {})
})
self.addEventListener('push', (event) => {
event.waitUntil(() => {})
})
self.addEventListener('sync', (event) => {
event.waitUntil(() => {})
})
代码所包含的四个事件中,install 与 activate 事件是 service worker 的生命周期事件。
event.waitUntil 方法也是很重要的方法。
install:install 事件发生在 worker 被安装或更新时,然后进入等待状态,在某个时机进入激活中,避免与旧的已激活的 worker 冲突。调用 skipWaiting 可跳过等待。
activate:activate 事件表示当前 worker 已经正式工作。
push:push 事件是 web-push 能力的服务消息推送事件。重点之一。
sync:sync 则是由页面客户端发起的,我们可以用来做一定的推送能力。重点之一。
web push 是依赖于浏览器客户端的推送能力,由浏览器厂商提供(大概)。可以在用户订阅后,在未打开过(大概)站点的情况下收到推送消息。
// client 部分,worker 为 serviceWorker.register 注册后的实例
const pushSubscription = worker.pushManager
.subscribe({
applicationServerKey: urlBase64ToUint8Array(publicVapidKey),
userVisibleOnly: true
})
fetch('/server', pushSubscription)
subscribe 的参数 applicationServerKey 为服务生成的公钥,完成订阅后 pushSubscription 中会包含分配的 endpoint 信息,即此客户端接受消息的推送地址。
然后需要将此 pushSubscription 信息提交给使用者的服务,在服务中使用相关信息进行消息推送,请参考其他文章。
endpoint 在 Edge 中为 https://wns2-sg2p.notify.windows.com/xxxxxxxxxxxx,在 chrome 中为 google 的 gcm 地址,后者有众所周知的连不上的问题。
如果需要使用浏览器的 web push 能力需要向厂商申请,需要进一步调研。
我们尝试其他方式进行。
sync 如名是用来做同步的。需要客户端代码发起同步注册:
worker.sync.register('sync-name')
然后已注册的 worker 即会触发 sync 事件。此时 worker 内需要进行轮询、长链接等方式进行消息获取,并调用通知进行展示,示例代码如下:
// worker.js
self.addEventListener('sync', (event) => {
function poll () {
fetch('/data-server/').then(res => {
self.registration.showNotification('来自轮询的消息', { body: res.data })
setTimeout(() => {
poll()
}, 30 * 1000)
})
}
poll()
}
看到这里可能会觉得为什么需要在 sync 中进行轮询,为什么不在 worker 中直接轮询?
实践发现 service-worker 在 tab 或浏览器退出后很快就会被回收,执行停止,这个时间最多也就 十几秒。
event.waitUntil 接受一个 promise,会告诉事件分发器事件仍然在进行,通知避免浏览器终止 worker 线程的执行,为了延长 worker 线程存活时间,我们将 poll 包装成一个不执行 resolve 的 promise 即可延长存活时间。 测试得在在关闭浏览器或页签后,最多执行了 3 分钟左右(同时,出现了一个现象,worker 在 5 分钟后又激活了一轮,15 分钟后又一轮,后续未观察,但同时 poll 里用来做标记的 id 变了)。并未达到长期存活的效果。
专业的态度应该着眼于项目和团队的积极结果,关注个人和团队的成长,围绕最后的成功开展工作。
软件开放行业是一个不停发展和永远变化的领域,你必须一直跟上步伐稳步前进,否则就会摔倒出局。
通常情况是,客户看到软件后认为很多地方不需要修改,且想要的功能不在原始的文档中。 我们真正的敌人是变化,不是客户、用户、队友或管理者。敏捷取决于你识别和适应变化的能力。
除了从用户处得到反馈,我们还能如何从其他起到获得反馈?
保证开发出的代码无论是在项目进行中还是在项目完成后,都易于理解、扩展和维护,避免在不知不觉中演变成一个怪物。
调试时面对的真正问题是,无法用固定的时间来限制;对项目来说,没有准确把握的时间消耗是不可接受的。
高效的协作是敏捷开发的基石。
一个好的习惯的改进可能就可以拯救你的项目,但是不要一次性改变所有习惯,这也会带来失控。
不愧为技术人写的书,太有条例了。
一本系统性介绍管理之路的书,包含了管理认知、方向规划、团队建设、任务管理、管理沟通五个方面,其中有一些通用的不限定于管理层面的通用方法,如问题解决办法、沟通办法、情绪控制等
上级看了知如何带人做事。
下级看了知如何“投其所好”,是一颗双方都欢迎的妙药。
这些不同的道路,有一些共同的能力:规划、带人、沟通、执行等。虽然可能不做管理者,但管理作为一项综合能力,在职业发展和合作过程中是不可或缺的。
上述乃外驱力,不可长久。
服从让我们撑过白天,而投入才能让我们撑过夜晚。
适不适合做管理要看这个选择是否符合初衷,能否激发你的投入意愿。
你是否意识到了自己是一位管理者?多大比例从“管理者”视角来考虑问题并做出反应。
对于从事技术工作的新经理来说,带团队是一个全新领域下的挑战。
只关心眼前业绩的往往只是“项目经理”,他们只关注“做事”,而作为既对“事”负责又对人负责的管理者,团队的可持续性是其价值的集中体现。
一个好的团队是业绩好、效率高、可持续的。
所谓管理,就是协同多人并“假人之手”来完成工作,而所有的协同都要通过沟通来完成。
前文所提即管理方法论,方法论是方法的产生方法。是一种更本质、更体系化的方式,具有可迁移、传承的特性,是管理者的核心技能。
职场的核心法则是价值兑换,管理者的价值对话模式是能力价值加上组织价值(因为是管理团队的一员而产生的附加价值)
职位头衔不再能体现职责要求,从实际的工作需求去定义自己的职责和角色,着眼于价值输出最大化
相对于过程和技术,“人”才是对确保产品的长远扩展性最为关键的因素。
目的为了开发效率的面向对象脚本语言,性能是弱点。
原型语言,类型灵活。
基于协程、actor、future 的并发机制。
某种程度上和 JavaScript 很像:原型链 + 并发。
一种逻辑声明式的编程语言。
支持面向对象和函数式编程两种范式的语言。
基于 actor 和消息传递与消息模式匹配器机制的并发模型。
为并发量身打造的无线程基于轻量级进程的语言。
基于 send、receive、spawn 的并发机制,很有意思。
采用模式匹配的方式定义函数的行为,入参未必是型参,可以是一个实际的值,从而定义了函数在这个入参情况下的行为,从而更容易进行递归等逻辑的定义。
Lisp(List Processing)的方言,一种以“列表”模式组织代码的语言,其指令和数据都是这种结构。
函数式编程语言。
以原子、引用、代理等概念完成并发支持,采用 STM 模型(理解为一种基于内存的数据库,进行并发下的状态管理)。
强类型定义的静态类型毫无妥协的纯函数式语言。
其函数的模式匹配定义方式与 Erlang 相同。
柯里化、高阶函数、Monad 等函数式编程的模板定义。