svn co 时控制目录层次

发现很多地方的 svn 还是用 http://svn.corp.com/team/project/ 下同时挂 branch, release, tags, trunk 的目录结构, 如果想把整个 team 的所有 project 都 checkout 下来, 显然数据量会大的想哭, 事实上大多数情况只要 co trunk 就行了, 土法就是挨个挨个 co 对应的 trunk 来看, 不过这样似乎有点土鳖

好在 svn 在 checkout 和 update 的时候是可以带一个 –depth 或 –set-depth 的参数来控制下载的目录层级. 比较简单的记录如下

# 仅目录
--set-depth emtpy
# 一层
--set-depth immediates
# 无限
--set-depth infinity

具体应用例子如下

$ svn co --depth immediates http://svn.corp.com/team
$ for proj_name in $(ls) do; svn up ${proj_name}/trunk; done

这样就能把每个 project 下的 trunk 弄到本地了

碎碎念

0x00. 好久没唠唠叨叨这么瞎写, 刚好难得今天最后一天不上班, 叨叨下
0x01. 从离开北京开始说吧, 走的时候把台式机寄回家给老爸, 直接抱去邮局, 邮局说这个有易碎品我们不寄, 你去对面德邦物流看看他们给不给寄
0x02. 本来选邮局就是看上京东买的东西都是走邮局到的镇上, 要去市里自提我直接就能去早德邦了, 差评!
0x03. 在德邦问价格商量给显示器和主机打木架时进来一个大姐问能不能发个金属管, 说也是对面邮局不寄给撵来的, 这德邦的老板真的不是邮局的?
0x04. 离开北京时, 和人人同事一起打的去北京南, 走三环堵的要死, 司机也开的各种不讲究
0x05. 半路同行的 gaolei 问到哪了, 我看了下外面说应该快到国贸了, 你看那边那个楼, gaolei 说嗯还不错 (很满足的口气), 当时正喝水的司机听了后一口气没接上来, 差点没被呛死
0x06. 高铁路上碰到徐州大雨晚点一个多小时这事之前说过了, 当时我们是被摆在滕州东站, 因为我们的车那站要上下客, 所以运气还好被摆在有站台的那一道, 还一直开着门可以去站台溜达
0x07. 一路压在我们前面跑的 G225 被摁在正线上, 那快两个小时里没法开门不知道他们有没有被闷死
0x08. 我看了下我所在的车, 停摆后居然有很多大爷大妈在做类似跳操的锻炼, 站台和车上都有
0x09. 那天最后晚上十点半才到杭州东, 打车又等了一个半小时
0x0a. 等车期间有一个大箱子放在车道边上没人管, 我们一直在瞎扯那不是个炸弹吧, 过了好久有人拿走才安心
0x0b. 杭州的出租都是 浙A.T 开头, 同行的另一拨人在我们后面上车, 但是一路比我们快一点而先到酒店, 不知道 A380 这个车号是不是就是快一点
0x0c. 我们那个司机一路都在用微信对讲机跟人聊天, 看起来很高科技很时髦啊
0x0d. 我最近几天一直恶趣味想, 杭州的哥要开微博, 直接把车号最后四位当用户名就行了, 反正都是 浙@xxxx
0x0e. 新淘宝城真 **** 的偏, 从卫星图上看离城区老远就只能看到树了
0x0f. 我特意坐了一次比较快的公交过去探路, 终于找回当年武汉公交那种速度感了
0x10. 在同学 xubo 那借宿了几天, 每天陪他室友的猫玩一小会, 感觉 IT 民工养的猫太可怜了, 一天都没啥玩的, 我在的时候经常来挠门求抚摸
0x11. 仔细研究了下 offer 发现提供的缓冲住宿可以入职前就用, 再次跟 HR 确认后说之前弄错了, 于是果断搬去酒店住了
0x12. 毕竟借宿还是比较打搅别人, 而且作息时间不一致俩人都挺折腾, 我找完房子后天天窝家里开空调耗电这样好像也不好
0x13. 就我借宿那两天, 遇上洗手间灯坏过一次, 整个屋跳过一次大闸, 不由怀疑我这 RP debuff 光环是不是也忒强了点
0x14. 在酒店住的房号是 360… 这个, 总觉得不太对啊
0x15. 有人每天下午从门缝里塞两张卡片进来, 内容是大家都懂的那种
0x16. 我闲得无聊把每天收到的一字排开看都有多少不一样的, 结果今天打扫完后少了两张跟其他不一样的, 难道不是酒店官方的所以被清除了?
0x17. 昨天去杭州东站晃了下, 站名终于不是隶书了, 应该是手写的偏楷体的, 要漂亮很多
0x18. 感觉开了六个售票厅还是很不够用的样子, 人工售票窗口少, 按说杭州东也有很多普速车, 对自己客流这么没自信?
0x19. 回程试了下杭州地铁, 也不便宜, 另外杭州的公共交通刷卡 9.1 折这个奇葩的折扣是怎么得出来的
0x1a. 是说一般最后都要总结下? 碎叨在乎这个干啥, 瞎扯完了就行了

读书杂记

全球通史
http://book.douban.com/subject/10583099/

这书从买 kindle 开始看, 到最近两天才看完. 一句话感触: 历史大潮滚滚过, 你我其中或可知

感觉一直到现在, 历史的关键转折无外乎科技发展, 宗教冲突, 以及利益驱使. 科技发展没什么好说的, 攀科技树多一层, 对低级别的来说基本就是碾压. 宗教的问题在天朝似乎没那么夸张, 但是看整个欧洲和中东, 基本上都是因为宗教的原因, 基督教和伊斯兰教互相 PK, 以及内部各分支在互相 PK. 利益驱使是一个很好的去做改进的动机, 除了宗教这种太意识形态的事, 科技发展和扩张都是建立在利益驱使下, 天朝最近几百年科技发展不行, 就是没啥利益了, 天朝上国啥也不缺, 往外打也没啥好打的, 就慢慢耗死了

另一个感触就是越到现代, 历史发展速度越快, 最近一百年的发展可能超过了之前所有文明阶段总和, 而最近一二十年又还在加速前进. 回忆下我们的小时候和现在, 差异实在是太大了, 如果把一个古人放到现在, 他会不会因为完全无法适应这么快的变化而崩溃. 我们既然已经在这股汹涌的历史大潮中, 已经无法选择崩溃, 崩溃就挂了, 那剩下要考虑的就是怎么保证可以随波逐流, 有理想点的可以考虑怎么去成为弄潮的人. 计算机相关领域一直又是更大更猛的潮, 但是笨狗还是想闲着发呆怎么办… 希望能被推着走还在时代的尾巴上吧

量子物理史话
http://book.douban.com/subject/1467022/

这本书很早就听过, 但是一直没去看, 应该是今年年初跟阿牛提起来, 于是找了个周末花了大半天一口气看完, 里面不少章节应该在 BBS 上零零碎碎看过, 所以也没有触动到非常夸张的地步, 只是觉得: 物理真的好奇妙, 而且, 对于这个世界, 我们究竟知道多少?

在我的 Task List 上好像是很早就说要写个读书笔记, 不过拖了这么久, 好像也想不起来到底当时想说些啥. 只还是深深觉得对这个世界我们知道的还是太少了, 而且现在的所知未必是正确的, 不断有新的理论和证据来说明世界原来不是我们一开始认为的那样的. 科技大发展有时候也让人挺困惑的, 简单点大条点也好啊, 可惜人类就是这么的充满好奇心, 不知道到人类文明消亡之时, 是否能把奥秘探究完. 我一直认为时间和空间是无限的, 我们当前这个宇宙的时空间有限那是因为我们的宇宙只是更大尺度上的一小部分, 或者等我们弄明白了当前这个宇宙后, 就可以将文明升级一个大阶段, 去考虑上一层的问题了

deep learning 的 feature 问题

这个不是读书了, 只是对现在火的要死的 deep learning 做一点自己的理解笔记和记录点疑问

因为我没弄过神经网络, 所以对 DL 的很多基础都不了解, 只能以很傻的方式来理解. 最近听了 MSR 邓力和 Baidu 余凯两次讲座, 加上之前在人人小强给普及的, 大致说来我理解的 deep learning 就是这么回事: 把以前只有零次 (比如 LR 的直接特征到结果映射) 或一次 (比如 SVM 用核函数来做原特征和结果的映射) 的问题空间转换, 变成多层 (即更 deep), 从而在这个过程中自然筛选组合学习到对问题的更本质的特征描述

我理解 deep learning 最大的变化是把一层隐信息变成了多层, 那每一层是怎么映射的? 是已有特征的大杂烩? 还是有一些简单的人工 feature engineering 的工作在里面? 对这个问题一直没人给仔细讲讲, 像 SVM 的核函数, 也还是需要人工去选择, 按 http://deeplearning.net/tutorial/ 这个 tutor 上的简单例子, 就类似要找到某函数最终的表达式, 可以在每一层我们都提供基本运算, 然后看若干次组合后能匹配上那个多项式? 表示对学术界最大的抵触就像是 “怎样画马” 那个讽刺漫画, 最后那一步跳的忒大了…

抛开那个映射方法的问题, 我的另一个问题是: feature 是否会变得不可理解? 因为 DL 的过程中可能通过人无法理解的大量组合得到最终的特征, 那是否会导致人类无法理解或解释最终的特征? 那在某些应用场景下是否会有遗憾? 比如人脸识别现在能做的很好, 但是对于那些识别不出来的照片我们怎么去跟人解释怎样变得可识别, 告诉别人脸洗干净点? 或者正面一点会容易识别? 这些都可以让人类来理解, 也可以让人类配合优化, 但 DL 出来的 feature 如果没法理解会不会在用户愿意配合的情况下都无所适从? 特别是广告, 之前在度厂我们做个性化, 让广告主接受的最大障碍就是广告主表示 “换了这样的游戏规则后我们完全不知道怎么玩, 你好歹给点 guideline 让大家知道什么是好的什么是坏的, 然后对于极端 case 能跟我解释为什么, 以后怎么避免”. 现在度厂说已经在凤巢上了 DL 的 model, 我在 ADC 上问余凯可解释的问题, 他表示广告主的难处没反馈到他那, 所以他也不知道或没觉得是问题…

杭州印象

第一次来杭州是 05 年的冬天, 过来浙大参加区域赛, 只记得当时去的紫金港, 最后有一个下午组织游了下西湖, 那时很惊讶杭州的出租车居然都是帕萨特, 然后司机跟我们说房价时只觉得以后毕业了一年有 15w 应该就算混的很好了

第二次来杭州是面试, 一个人又去走了下苏堤, 想可能就要一直在这个以前自己只认为是旅游城市的地方呆下去, 感慨万千, 人生真奇妙, 确实永远不知道以后会变怎样

这次过来则基本算搬家了, 跟人人过来参加 ADC 的同事一起坐高铁, 居然还碰上强降雨导致徐州断电的大面积晚点这种事 (插句话, 我总共在京沪高铁上走过四次, 北京南-泰安, 泰安-北京南, 北京南-上海虹桥, 北京南-杭州东, 其中第二次和第四次都遇上超过一小时的大面积晚点, 以后想跟我一起坐车的注意检查自己的 RP 是否能扛住我的 debuff 光环). 杭州东作为一个典型新站, 很给力的让我们等了一个半小时的出租车, 这次发现怎么出租车档次都下降好多

到杭州那天说是要来台风, 最后只是擦了过去, 南方闷热的天气, 但是会有风, 好多年没重新体验这种感觉. 整个城市的绿化率, 以及随处可见的小河港带来的水气, 空气中也还是典型的江南水乡的味道, 喜欢这样

在杭州这几天似乎也没遇上传闻中那么可怕的堵车, 或者是这边太敏感了, 要在北京天天看东三环堵的那样应该就完全没脾气了吧. 很多没有红绿灯的道口, 路过的车会很自觉的停下等行人通过, 我第一次碰到时扭头找了半天红绿灯在哪, 后来发现只是这个城市很友好的一部分

找房的过程发现, 杭州房价是要比帝都低, 不过好像也没有低到明显差一个 level 的情况

这几天找吃的过程中, 感觉杭州的小吃馆更本土化一点? 而不像北京遍地改良过的成都小吃, 最近两天恍惚间觉得收银妹子们说话都很有台湾腔 (或者应该就是东南沿海软甜的腔调吧)

习惯了帝都便宜的要死的公交, 在杭州找房和蛋疼瞎逛的两天里, 轻松把公交卡刷掉十几块钱, 这还是近距离我都骑公共自行车的情况下, 相比较而言杭州公交车上会觉得更暗一些, 窗户小, 而且现在太阳大一般都拉了窗帘. 公共自行车是个好东西, 虽然部分车况实在不行, 前几天都是上班期间在用, 感觉借和还都很方便, 昨天赶在下班时间想去弄下, 结果走了两个点都没有车, 果然真的要长期使用, 还是自备靠谱

三年又三年

之所以想起这个题目, 一是受无间道里梁朝伟跟黄秋生吐槽 “说好的三年, 结果三年又三年, 三年又三年” 和 “再见警察” 那个悲凉的音乐影响 (只是无厘头的觉得三年确实可以算一个比较合适的 checkpoint 而已, 相关曲目请见 http://www.xiami.com/song/1769154348), 二是的确最近的每个三年都是大阶段变化, 三年前的三年前的三年前, 离家上大学, 三年前的三年前, 第一次出来实习, 后面也基本没太多在学校混, 三年前, 毕业工作, 现在的这个三年, 离开北京到杭州, 基本上又是一个全新的开始

上一次确实也写了一篇三年 http://www.yewen.us/blog/2010/07/%E4%B8%89%E5%B9%B4/, 那这次也还是对比着写写看

2007.7.18 星期三 北京 晴
2010.7.18 星期天 北京 晴
2013.7.18 星期四 杭州 晴
*
2007.7.18 百度实习入职, 第一次实习
2010.7.18 在百度工作, 第一份工作
2013.7.18 已从人人离职但还没在阿里入职, 换了个城市
*
2007.7.18 百度网盟, 第一次接触互联网广告, 从此一条路走到黑
2010.7.18 百度凤巢, 那段时间比较顺手, 后面有两次被坑到不行, 感觉自己的离开也还是跟这有关系
2013.7.18 未知的方向, 重装上阵的阿里妈妈? 当年的友商, 现在自己也混迹其中, 而前东家是友商了
*
2013.7.18 过去的三年, 在西二旗十六个月, 在柳芳二十个月
2013.7.18 看起来会在杭州呆很久, 很可能就一直在这了?
*
2007.7.18 在学校阿排还是被叫的最多的名字
2010.7.18 更多扮演的角色是恶趣味无聊理工男
2013.7.18 可能又要回到天天被叫阿排的日子?
*
2013.7.18 过去的三年, 搞过搜索广告, 也搞过展示广告, 也从广告退出来去折腾用户产品相关的, 最后绕了一大圈, 还是回到广告, 在赚钱的部门, 有压力有动力倒也不是坏事
2013.7.18 在百度被希望转 manager, 结果好像 tech/manager 都没做好
2013.7.18 在人人倒是因为下面挂了一堆人而被动变成了 manager, 也被各种培训, 换个角度看问题思路会开拓很多
2013.7.18 离开一线心里还是发慌, 自己这种闲散的心态去带人没法给小弟抢地盘, 人再好也还是白搭, 还是走技术线吧, 能管好自己已经很不错了
2013.7.18 很感谢这些年碰到的各位导师, 同事, 都很赞, 只是可惜自己不够成器
*
2010.7.18 想尽办法跟妹子在一块
2013.7.18 还是想尽办法跟妹子在一块
*
2013.7.18 Good Luck

django 入门小试

对 django 这个框架早有耳闻, 最近因为想给组内写个饭团系统, 想是不是可以刚好学习用下这样的框架

先按官方教程学了下基本的内容, 很简单: https://docs.djangoproject.com/en/1.5/intro/

然后就自己操练了下, 记几个小细节或坑

1. 简单应用时, 数据库辅助表不要自己建, 否则维护关系很麻烦
2. 用 shell 来做本地测试, 用 dbshell 来修复数据库问题
3. 对不同的模块, 功能, 善用辅助字段, 各种 Google 查询就是了
4. 调试完成关闭 DEBUG 模式发布后如果还有错, 那就在 setting.py 里配好管理员邮件等着收邮件看报告分析错误

过程中还经常参考的是 The Django Book, 不过没找到哪里有比较好的全本或翻译版下, 我都是从新浪爱问等地方找到的半成品

目前已经完成饭团, 架在内网的一台台式机上, 源码和说明在
https://github.com/whusnoopy/fantuan

这个系统在我们组内已经用了好几个月, 目前看来工作良好 :P 我是用的 fastcgi 模式在跑, 使用 unix socket 通信, 配好 nginx 的转发规则就可以了, 注意对应 socket 文件的读写权限, 我一开始被这个坑了半天, 其他的看上面那个 github 工程的 README 应该都说清楚了

补一句, 关于饭团, 之前支付宝有 AA 收账其实就能满足需求, 只是没法回溯查看, 对我们团队的问题则是不知道大家的支付宝帐号, 统计收集也麻烦, 加上我们还想记录下来做点 data mining 玩, 比如偏好餐厅等, 就还是有单独饭团的需求. 另外, 最新版的 QQ 客户端里, 群也有 AA 收账功能, 看了下, 跟支付宝类似, 发起会更方便, 但考虑到财付通的覆盖面远不如支付宝, 估计也够呛, 另外一些我们想要的记录似乎也是没有的 (比如餐厅, 付款人等)

伪需求之员工考勤统计自动化

早两周偶然听的某公司发工资还是 HR 人肉拿 excel 计算的, 当时就觉得非常不可思议, 既然都有刷卡系统, 还有 OA 系统管漏打卡和请假, 难道最后不应该是自动生成工资单才对, 这也太浪费人力了

后来自己简单想了下, 生成工资单这个事, 应该绝大多数企业都会遇到, 除了像 Google 之流不打卡纯靠自我驱动自觉的, 那如果能有办法优化生成流程, 应该可以为企业节省相当的人力, 如果自己去做这样的服务, 是不是可以赚得盆满钵溢 (此处请脑补一个 2B 青年留着口水发白日梦的场景)

简单想了下对普通企业来说, 只要统计打卡, 然后处理公休假和员工请假的情况就搞定了, 公休假由管理员指定, 请假的事通过 OA 走, 小企业可以找个管理员, 大家去他那登记就行. 每月发工资前把大家的出勤情况公示出来让大家看是否有问题, 管理员做点微调修正. 这样不就可以把传统模式下的人肉统计解放出来, 根据不同人的说法, 每月耗这上面至少要 2 个人/天, 我如果能搞定 500 个小企业, 对每个企业收 200 每月的服务费, 就能月入十万 (此处请继续脑补一个中二青年打算拯救世界的傻缺场景)

但是这事情要真这么简单, 那也不应该只有我想到了, 于是我去找了青年企业家汤汤问他们现在的情况, 汤汤现在在浙江管一个家族里的厂, 我印象中规模是 50~100 人. 汤汤直接说我们不像你们大公司, 我们很土的用 excel 算的. 我吐槽说据我所知某公司也是这么干的, 那说明很多人这么土鳖的搞, 你们现在的人力和成本都花哪去了, 看看有没有优化可能. 以下省略废话若干, 直接列现状:

1. 因为是工厂, 所以计算工资单很简单, 就是统计每个人的出勤时间和加班时间
2. 需要一个人事专员来做统计和协调, 一般每月需要花两三天
3. 有打卡设备, 一次性投入 1K+ RMB (三主一备), 打卡设备可以导出原始记录
4. 两三天的人力中, 绝大部分时间花在跟人确认和调整上

列到这, 基本可以断定前面的白日梦是不太可能成真了, 因为:

1. 能自动化一点就是导打卡记录更快, 这个已经被解决了
2. 另一个之前 YY 的可以自动化一点的是能让确认调整更方便省时, 但是直观看好像也没省太多

再细说下之前想的确认调整过程的省时, 主要希望能工人自动化完成调整, 或有管理员简单高效完成, 但是这个的前期成本太高了, 还是有好多问题:

1. 工人需要培训怎么使用这个系统, 这在人员流动比较频繁的生产领域, 也是增加了人力成本
2. 一线工人不一定有设备完成, 那还是需要一个管理员, 而管理员的时间也还是没省下了
3. 另外招一个会这样自动化系统的人对沿海小工厂来说也还是过高的要求

最终结论就是他们的人力成本比我们想的便宜很多, 节省下来的钱绝对不够付服务费的. 需求证伪

一些 YY 中和实际情况不符的地方是伪需求的关键
1. 当前的打卡设备的成本没有我想的那么高, 而且自动化程度也不低
2. 对工人或管理员的要求太高, 培训成本还不够节省下来的成本支出的

小白日梦插曲, 随手小记一下, 欢迎讨论

为什么要预估点击率

背景

想到这个题目是因为 @lijiefei 某天跟我说他有师弟面淘宝时被问到 “点击率预估的目标到底是什么”, 笨狗当时胡乱扯了一通, 发现要把这个似乎已经是真理的事情掰清楚还没那么容易, 于是有此念想写文一篇详细分析下原因

我和 jiefei 认识是在百度做搜索广告的时候, 那就从搜索广告开始说为什么要预估点击率, 以及预估点击率的目标. 先申明一些名词和假定:
1) 每个广告 (Ad) 有一个出价 (Bid), 并有其在某情形下实际的点击率 (Click-Through-Rate, CTR)
2) 广告按点击收费 (Charge per Click, CPC), 下面我们会分别讨论一价计费 (First-Price, FP, 即广告出价多少则一次点击计费多少) 和二价计费 (Second-Price, SP, 即广告按下一位出价来支付点击价格, 更普遍的是 GSP)
3) 千次展现收费 (Cost Per Mille, CPM, 或 RPM, R for Revenue), 即对点击付费广告其展示一千次情况下的收入 (一价计费下等价于 1000*CTR*Bid), 或是展示广告的千次展现固定价格
4) 预估点击率 (predict CTR, pCTR) 是指对某个广告将要在某个情形下展现前, 系统预估其可能的点击概率

目标分类

搜索广告跟自然结果一个很大的区别就是自然结果只要有一点相关就应该放到所有结果里去, 至于先后位置那个再说, 而广告, 是有个相关性的准入门槛的, 不相关的广告出价再高, 丢出来还是会被骂死. 那怎么判断相关? 用户会用鼠标点击来对结果投票, 相关的广告会被点击, 不相关的广告不会被点击, 那很自然就能得出 “点击率和相关性正相关” 这个结论 (至于描述里写 “二十五岁以下免进” 但实际是钢材广告的这种诱骗行为后面再说怎么处理). 那对于这种相关性准入的场景, 预估点击率就是预估广告是否相关, 最朴素情况下这是个二分类问题, 那不管预估成怎样, 只要有一种分割方法能分开是否相关就行了. 此时预估点击率的目标是能对广告按相关与否分类 (或说按相关性排序并给出一个截断值). 评估分类问题好坏, 一般都是看准确和召回两个指标, 用人工打分的记录来做回归验证就行

目标排序

判断相关与否只是点击率预估对广告的一个小辅助, 我们来看看广告的目标是什么? 没错, 是赚钱. (我曾经在其他场合说过广告的目标是维持用户体验下持续赚钱, 不过跟赚钱这一简化目标这不冲突, 前面相关性上已经保证了维持用户体验, 那只要能让广告主还有的赚, 就能持续赚钱) 我们再把问题简化下, 如果广告都是一样的固定价格, 且就以这个价格按点击计费, 那在 PV 一定且预算充分的情况下, 更高的点击率则意味着更赚钱. 这样目标可以等价于怎么挑出更赚钱的广告, 就是那些点击率最高的广告, 我们只要能弄明白广告实际点击率的高低关系就能取得收益最大化, 预估点击率在这时候又是个排序问题, 我们只要弄对广告之间的序关系, 就可以收益最大. 评估排序问题的好坏, 一个经典方法是对 pCTR 的 ROC 曲线算 AUC (曲线下面积), 实际上我见过的做法也都是通过评估 AUC 的高低来判断点击率预估模型的好坏

目标带权排序

上一段里对广告这个业务做了很多简化, 比如大家价格都是一样的, 如果我们考虑价格不一样的情况, 那预期收益就会变成 (价格Bid*点击率CTR), 这个值很多地方也叫 CPM 或 RPM. 如果是对 CPM 排序, 那就需要我们预估的点击率在维持序关系正确的前提下, 还要保证相互之间的缩放比是一样的. 比如有广告 A, B, C, 实际点击率是 5%, 3%, 1%, 那在价格一致的情况下, 我预估成 5-3-1 还是 5-4-3 是没关系的, 但在价格不一样的情况下, 比如 1, 1.5, 3, 这时候 5-4-3 的预估点击率值会让他们的预估排名和实际排名刚好颠倒过来, 不过预估 5-3-1 或 10-6-2 (放大一倍) 倒没关系. 为了评估这个结果, 可以在描 ROC 曲线时把价格乘上去, 那最后还是判断排序问题的好坏, 加了价格的 AUC 我们可以叫 wAUC (weighted-AUC), 这个离线评估和在线效果依然可以对等

目标准确

从准确召回到 AUC 再到 wAUC, 看起来对已有问题可以完美解决了? 不过广告计费显然不是 FP 这么简单, 在 Google 的带领下几乎所有的搜索引擎都使用了 GSP (Generalized Second Price) 来对广告点击进行计费, 这里再简单解释下最简版 GSP 是怎么回事:
1) 所有广告按 CPM 排序 (即 CTR*Bid)
2) 排最后的广告收底价 (Reserved Price, RP)
3) 其他广告按他的下一位 CPM_i+1 除以他的 CTR_i 并加一个偏移量来计费, 并保证比底价高, 即 Price_i = max(CPM_i+1/CTR_i + delta_price, RP)

至于 GSP 的细节和为什么这么做能保证收入和体验的平衡等可以详见相关论文, 我们只讨论在 GSP 模式下, 点击率预估的作用和关键点. 根据介绍 GSP 时最后那个公式, 如果把 CPM_i+1 拆成 CTR_i+1*Bid_i+1, 看起来只要保证同比缩放还是会没问题? 但是, 凡事怕但是, 在搜索广告里, 不同的展现位置对点击率还有影响, 比如广告 A, B 在第一位点击率是 5%, 3%, 而在第二位是 3%, 2%, 那只是同比缩放就很难保证最终比较是一致的问题了, 所以最好还是保证预估值跟实际值尽可能接近的好, 这样才能在预估时获得更实际用时完全一样的场景. 评估准确度, 我们有 MAE 和 MSE 等一堆指标, 也是现成的工作的比较好的东西

扩展和吐槽

有行家可能会吐槽说我刚那个不同广告在不同位置的衰减不一致这个说法, 跟公开论文说的不一样, Yahoo 的 paper 里说不同广告在同位置的衰减是一样的. 我只能说, 骚年, 你太天真了… 衰减因子怎么可能只是 f(pos) 这样一个简单函数, 从实际情况来看, 衰减函数和广告是有关的, 但我们又不能对每个广告都去估一个 f(pos, ad), 好在, 我们发现可以把不同的广告做聚类后得到一个 f(pos, type) 的函数簇, 事实上, 最后的衰减函数不仅仅有 pos 和 type 两个因子, 而且里面的因子可以极度简化, 最后的衰减用简单函数就能很好拟合, 我说的够多了, 再说估计要被前东家找麻烦, 你们来感受一下就好

前面也提到介绍的 GSP 是最简版的, 那如果是正常版会有什么不一样? 那就是排序时用的是 Quality*Bid, 这个 Quality 百度叫质量度, 也就是广大广告主望眼欲穿的那几颗星. Quality 和 CTR 有什么不一样? 最简情况下这两个当然是一样的, 但是我们可能还要考虑广告主的信誉度, 目标网页的质量等因素 (比如前面提到过的那种描述欺诈或诱导的广告在这个 Quality 因子里被调整掉), 最后这个 Quality 就会是包含了 CTR 的一个多因子复合值, 那要准确估计这个复合值, 当然也要求其中的每个因子的值尽可能准确. 这里在炒冷饭说准确度, 以及 MAE/MSE 的作用

实际上据我所知各搜索广告平台用的是比正常版的 GSP 还加强或改造过的版本, 里面的因子, 公式, 逻辑更复杂. 在这种情况下还是需要继续强调 CTR 预估的准, 才能做更精确的预估, 从而带来更大的收益

广告之外

呼~ 说完了搜索广告, 我们再简单说下内容广告. 搜索广告几乎都是点击付费, 而内容广告同时存在按点击付费和按展现付费, 那怎么比较一个按点击付费的广告和一个按展现付费的广告哪个预期收益更高? 同样是 CPM, 按展现付费的广告给的是确定值, 而按点击付费的是一个预估值, 通过 Bid*pCTR 得到, 如果 pCTR 不准, 就会导致点击付费广告的预期收益计算不准, 则不一定受益最大. 继续强调预估的准的好处

说完广告我们就能说说其他的, 比如搜索, 比如推荐, 这几个的优化目标如果是带来的量, 因为总体 PV 我们没法人工干预, 且每个点击是等价的, 那最后的优化就变成了点击率, 预估的序关系越接近真实, 可获得的收益更高. 如果不同的点击价值不一样, 那就可以把这个点击换做价格代入广告的模型, 因为没有二价计费那么讨厌的变换, 所以就按一价计费来考虑, 保证序正确且等比缩放就能保证收益最大. 如果再激进一点, 评估收益时还加入更复杂的因子而不仅仅是价格这个独立因素, 那自然就要求点击率预估准确, 从而保证做决策时和实际情况一致, 继而保证最终的优化目标最大化

总结

1) 点击率预估是为产品的最终目标服务的, 最终目标可以是广告的收入, 广告的相关性, 推荐的接受率等, 看具体场景
2) 点击率预估的直接目标根据需求场景不同, 分别是保证预估值和实际值分类正确, 预估序和实际序正确, 预估值和实际值是等比缩放的, 预估值等于实际值
3) 要保证离线评估点击率预估的效果, 分别可用分类的准确率和召回率, 排序的 AUC, 带权排序的 wAUC, 相似度 MAE/MSE 来评估

奇怪流量的终结

曾经有爆流量记这一篇博文提到之前租的空间被下 Win7 的请求爆流量, 在迁到自己的 VPS 后发现还是有对 Win7 的请求, 还附加了一个奇怪的隔一小会就发个 HEAD 请求, UA 中带 QQDownload 的奇怪来源 (BuyVM VPS 安装优化记)

作为日志洁癖者看着 nginx 的 access.log 里都是这种请求那自然是各种不爽, 之前一直怀疑 Win7 的请求来自旋风或迅雷, 但苦于木有证据, 这次特意又去查了下旋风和迅雷的离线服务器列表 (比如百度空间上用于 eMule 避免吸血的这篇: http://hi.baidu.com/asp502010/item/44ac169b289dd2d91a49df6d), 对比了下 IP 范围, 还是不在里面, 有点失望

不过这次有意外发现, 那就是 UA 里带 QQDownload 的那个, 虽然我知道这个 UA 串未必就是旋风发来的, 可能也只是老版本旋风 (这次 UA 是里版本号是 713, 我看了下最新的旋风应该是 783) 安装后改了系统的 UA 串, 但不管怎样总是有可以胡搅蛮缠的由头, 于是通过之前在旋风实习过的 momodi 联系上旋风的工程师, 直接吐槽

叶文/Snoopy阿排 15:43:29
hi, 非常抱歉冒昧打扰

我碰到的问题是这样的:
我自己有一个域名 yewen.us, 曾经指向我前公司内网里的一台机器, 提供前公司可激活的 windows 7 iso 文件下载, 可能被前同事用不同的下载工具 (如旋风, 迅雷等) 下载过, 并被计入链接库, 于是一直有外部请求来下这个文件
但是我一年多前就移除了这个文件, 对应的下载请求都返回 404, 但一直还在被抓 (后来没办法还改过 302, 416 等错误返回码, 都无效)

最近我仔细看了下我 nginx 的日志, 最近有大量带 QQDownload 标识的请求, 同时请求那个 win7 iso 的量也很大, 所以怀疑是不是 QQ 旋风没有正确处理错误返回码, 一直没把这个已失效的地址去除

之前写过一篇 blog 来分析: http://www.yewen.us/blog/2012/02/overflow/

从昨天晚上到今天上午的 nginx 日志分析:
$ grep “QQDownload” vyewenus.access.log | awk ‘{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}’ | sort
101.226.68.137 196
140.207.54.139 195
183.195.232.138 196
$ grep “cn_windows_7_professional_x86_dvd_x15-65790” vyewenus.access.log | awk ‘{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}’ | sort
122.141.67.50 329
123.185.52.73 54
14.114.226.18 150
14.114.226.194 14677
14.115.129.55 4040
180.117.68.185 361
59.33.63.137 1476

抽几条完整日志如下:
101.226.68.137 – – [21/Apr/2013:19:44:18 +0800] “HEAD / HTTP/1.1” 200 0 “-” “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; QQDownload 713; .NET CLR 2.0.50727; InfoPath.2)”
14.115.129.55 – – [21/Apr/2013:19:44:18 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows
NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”
14.115.129.55 – – [21/Apr/2013:19:44:22 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows
NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”
14.115.129.55 – – [21/Apr/2013:19:44:25 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows
NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”
叶文/Snoopy阿排 15:44:00

请帮验证下那几个大量请求的 IP 地址是否是旋风离线服务器发起的

QQ旋风 15:44:19
你能否自己屏蔽了?

叶文/Snoopy阿排 15:46:01
我现在已经返回 416 错误码了, 流量也不是太大问题, 只是很奇怪为什么我都返回错误码一年多了还在被抓, 而且 IP 不一定固定 (我怀疑可能存在 “某下载工具的地址库存了这个链接, 用户可能会直接请求” 的情况)

后面的沟通基本就是礼节性的再提供点证据, 旋风的工程师没直说这几个请求是否是旋风自己的, 只说可能库里确实有脏数据, 给我看看, 至于老版本如果有缓存了这个信息, 那就没办法了. 隔天早上联系我说确实从库里找到这么一条记录, 已经删除, 让我再看看日志, 这次过去看了下, 果然对 win7 的所有请求都没了

这个事应该就算解决了, 之前虽然有怀疑但一直没去付诸行动, 果然有问题直接找到工程师才算比较快的解决方法, 像我这种 “刁民” 应该也会给他们带来计划外工作量, 不过确实是自家 bug 那也没什么好说的, 上次提到那个多说评论显示错误的问题, 最后也是找多说工程师直接解决. 旋风的哥们帮解决这个问题后还很好奇的问了句, 你还关注日志啊, er, 可以说这已经成职业病了么, 互相呵呵了下也就结了

过了两天发现那个奇怪的 UA 串发来的 HEAD 请求还有, 这次再问旋风那边他们就也不知道怎么回事了, 放 Google 搜了下找到 http://www.postsila.com/thread-193359-1-1.html 这么一篇, 跟我遇到一样的问题, 也不明所以, 不过还好这个请求来源比较固定, 从 access.log 里搜了下对应 IP 除了发 HEAD 请求没有任何正常用户行为, 那就开 iptables 屏蔽掉就行了

$ sudo /sbin/iptables -I INPUT -s 101.226.68.137 -j DROP

封了几天再看日志, 还在请求, 本来还想 ws 的通过 dnspod 能不能直接拒绝掉, 研究了下 dns 真干不了这事. 算了算了, 自己都屏蔽掉了那就这样吧, 看下日志还在涨

$ sudo /sbin/iptables -L -n -v --line-numbers
Chain INPUT (policy ACCEPT 529K packets, 835M bytes)
num   pkts bytes target     prot opt in     out     source               destination
1     3311  199K DROP       all  --  *      *       183.195.232.138      0.0.0.0/0
2     3229  194K DROP       all  --  *      *       140.207.54.139       0.0.0.0/0
3     3304  198K DROP       all  --  *      *       101.226.68.137       0.0.0.0/0

除掉这俩后再看日志, 最大的来源就是 dnspod 的定时监控和各搜索引擎和 Feed 订阅器的抓站. 想了下小破站挂就挂, 没那么严苛的可用时间要求, 去 dnspod 把监控间隔调到最长, 搞定

最后, 看了下之前租的空间还有流量, 再打开日志, 发现都是来自 youdao 爬虫的数据, 话说我都换了域名 IP 指向一周了, 怎么你们还在抓以前 IP 啊, DNS 不更新么

BuyVM VPS 安装优化记

BuyVM 的 VPS

早两周忘了是谁提醒了下, 说 buyvm 家 15$/yr 的 VPS 有货, 非常值得去抢, 当时估算了下这个价格确实算良心价, 虽然只有 128M 内存, 但作为一台自己的 vps 折腾点东西完全都够了的, 果断下手一台

这台机器打算拿来放一些自己玩的小程序, 同时把个人的空间和 blog 迁过来, 本还想拿这个机器做自己私有的翻墙中继, 不过试了下到本地的速度最高也没超过 30KB/s 过, 遂放弃, 等啥时候有烧包需要时去买 linode 在日本的节点好了

系统选择和基本设置

之前自己用 debian-server 做纯服务端的东西感觉很爽, 占资源少文档丰富, 出点问题也能很容易在 Google 帮助下搞定, 所以系统也选的 debian, 然后因为只有 128M 内存, 上 64bit 没意义, 而且会更耗内存一点, 所以选了 32bit 的版本

debian 有几个比较坑爹的地方, 首先就是新建用户默认不建 home 目录, 非要在 useradd 的时候强加 -m 参数指定, 不然还要人肉新建 home 目录兵把 /etc/skel/ 下的几个隐藏文件拷过来做初始化

然后就是如果不是 root 用户, /sbin 和 /usr/sbin 默认是不在 PATH 里的, 需要手动将这些路径打开, 不然连 ifconfig 什么的都用不了. 修改 /etc/profile 里, 将 PATH 设成全用户一致 (此处参考: http://techpoet.blogspot.jp/2010/01/add-sbin-to-user-path-in-debian.html)

自己有一堆常用的配置库放在 github 上, 直接 git 取下来放到 home 目录, 把一堆 rc 结尾的文件前面加点让对应的程序能读到. 特别的是 vimrc, 最好还是放到 /etc/vim/vimrc.local 下, 不然 sudo 的时候碰上的还是没配过的 vim, 挺不爽的

系统自带应用内存优化

因为只有 128M 的内存, 要做很多勒紧腰带过日子的准备, 先就是卸载一堆自带的服务, 释放宝贵的内存, 此处参考了 http://www.yyphs.com/post/475.html, 不过我只去掉了会启动的组件, 即如下操作

# 系统升级
apt-get update && apt-get upgrade

# 去除多余软件
apt-get -y purge apache2-* bind9-* xinetd samba-* nscd-* portmap sendmail-* sasl2-bin

# 清理软件包
apt-get autoremove && apt-get clean

LEMP 环境安装

Web 应用从早两年的 LAMP 现在都在转 LEMP, 主要还是把 Apache 这个巨无霸换成了相对小巧又耐操的 nginx, 自己之前用 nginx 感觉也相当好, 这次也把系统默认的 Apache 干掉换这个

一开始参考的 http://www.howtoforge.com/installing-nginx-with-php5-and-mysql-support-on-debian-squeeze, 安装 mysql, nginx, php 都很正常, 但是这里面提到 debian 没有 php-fpm, 所以用 lighttpd, 不过我装 lighttpd 后内存爆掉, 随便搜了下优化方案都搞不定, 卸掉, 还是用习惯的 php-fpm 方式跑 fastcgi

http://www.webhostingtalk.com/showthread.php?t=1025286 这个提示装上 php5-fpm, 从装 nginx 开始就用不上了, 后面的优化也先不用管, 一会一起处理 (wordpress 似乎还依赖一个叫 php5-apc 的包, 装的时候一起带上)

内存优化

上面那一堆装好后如果不做优化, 坨坨的爆内存, 所以该关的功能要关, 该调的参要调. mysql 的一个优化关键是要关 innodb, 然后 nginx/php-fpm/mysql 都要做的事就是降低同时运行的实例数, 减少连接数, 同时严格控制各处内存大小. 具体怎么配的也忘了, 主要参考的是搜到的这两篇里关于参数的配置

http://blog.log4d.com/2011/11/vps-lnmp-setup-config/ (主要参考其参数配置)

http://keithscode.com/blog/23-running-mysql-on-a-small-128mb-vps.html (主要参考其参数配置)

最后的内存占用如下 (目前运行状态, 装了 wordpress)

$ free
             total       used       free     shared    buffers     cached
Mem:        262144      88972     173172          0          0          0
-/+ buffers/cache:      88972     173172
Swap:            0          0          0

安装迁移 wordpress

先在 mysql 里建对应的数据库, 这个随便都能搜到, 自己碰到个坑是 mysql 分配数据库权限时用已有用户无法登陆, 最后还是删掉用户在分配权限时再新建用户, 用 identify 来设置密码

mysql> create database wp;
mysql> grant all privileges on wp.* to wp_user@localhost identified by 'wp_pass';

装 wordpress, 一切正常, 用老的文件, 改名备份 wp-config.php 直接访问 wp-admin/install.php
用导出的文件再导入 (大于 2M 的话需要修改 php 的上传限制: 修改 /etc/php5/fpm/php.ini 文件修改 upload_max_filesize 项)

之前用的是多说的评论系统, 把插件重新启用, 并绑定原来注册过的站点就能将评论恢复, 一切搞定

奇怪的问题

上面写的好像很容易, 实际上对一个新手 OP 来说还是非常磕磕碰碰的, 最后在 OP 之外还有些奇怪的问题

先是多说, 绑定站点时临时性卡死, 然后再导数据时有延迟, 再后面就有重复的评论出现, 但是又不是所有的评论都被重复一遍, 研究了半天没弄明白, 自己手动删掉了重复的

然后删重复数据时发现有一条奇葩的回复显示在了另一篇文章下, 还是一条二级评论, 但是在后台看对应的又是正确的文章, 而且文章下的评论数是对的, 就是不显示, 自己折腾半天都没弄好, 无奈去联系多说的技术客服, 周末不在线, 留言后觉得不放心, 又去 dev.duoshuo.com/wordpress-plugin 报了一遍才安心

今天终于找上人, 帮着看了下, 先让我把评论模式从嵌套改成盖楼, 发现果然显示在正确的文章下了, 但是错误的引用了一条另一篇文章下的评论, 而且引用的那条评论还在此评论后好几个月才发出来, 顺手看了下 HTML 源码, 发现多说也是按 评论(post-id), 文章(thread-id), 引用(root-id) 来组织的数据 (这跟 BBS 上的 pid, gid, rid 一样一样啊), 然后这条出错的评论应该是两边哪里没同步好, 导致其 root-id 出错, 而 root-id 对应的评论在另一篇文章下, 所以嵌套模式时就显示到那边去了, 而正确的文章下因为找不到对应的父评论所以也没显示, 而盖楼模式下不判断父评论所以能显示, 但是存在错误引用关系, 最后让帮忙手动将出错评论的 root-id 置零, 总算搞定

第二件事是一个陈年老问题还在, 一年多前就写过一篇爆流量记, 里面提到有人抓 win7.iso, 但是当时找不到证据说是谁, 迁到新站后还在被抓, 期间 404/302/416 轮着报了一年多错居然还抓, 怒了去看看到底都哪来的请求, 意外发现有很多标识 QQDownload 的请求, 从 momodi 那联系上 QQ 旋风的人, 跟他们 blabla 说了一堆, 结果估计他们也从来没碰到过这样的事, 说要不你先自己屏蔽掉? 我哭笑不得说现在对我倒没啥影响了, 反正就算屏蔽也耗系统资源, 而且现在每次给个 416 也费不了我多少流量, 只是觉得很不爽而已. 不过后来自己去找了下迅雷和旋风离线下载的 IP 段, 这几个好像又都不在里面, 贴下原始日志, 大家看看有啥想法没:

$ awk '/QQDownload/{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}' access.log
101.226.68.137 196
140.207.54.139 195
183.195.232.138 196
$ awk '/cn_windows_7/{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}' access.log
122.141.67.50 329
123.185.52.73 54
14.114.226.18 150
14.114.226.194 14677
14.115.129.55 4040
180.117.68.185 361
59.33.63.137 1476

抽几条完整日志如下:

101.226.68.137 – – [21/Apr/2013:19:44:18 +0800] “HEAD / HTTP/1.1” 200 0 “-” “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; QQDownload 713; .NET CLR 2.0.50727; InfoPath.2)”
14.115.129.55 – – [21/Apr/2013:19:44:18 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”
14.115.129.55 – – [21/Apr/2013:19:44:22 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”
14.115.129.55 – – [21/Apr/2013:19:44:25 +0800] “GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1” 416 615 “http://yewen.us/” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)”