项目总结

来源:互联网 发布:李白 知乎 编辑:程序博客网 时间:2024/06/01 09:28
  1. App专名后验强度更新

项目背景:

百度移动搜索有一些app的词典,这些词典是用来提供百度移动搜索app类目的垂直搜索,也就是当用户搜索跟app相关的query的时候,在结果页中插入app的框,比如用户搜索“百度手机助手”,会在结果框中给一个百度手机助手下载的框,每个app名都有一个需求强度值,这个值决定框的展现位置和框的大小,现有的强度值是先验的。先验的强度值经过用户反馈后有些是不准确的,这样导致的结果是展现的框的大小不符合预期,我需要对这些不准确的强度值用用户反馈的后验强度值进行更新。

具体做法:

由于百度结果页的展现是经过点击调权的,我们可以认为百度结果页中app框的位置可以反映app的强度,当时跟pm确定app框的展现位置在前三的则认为强,在前10的认为弱。百度保存了用户的展现日志,也就是每个用户搜索一个query所得到的页面结果信息,也就是结果项的列表,app的框有一个单独的标志。根据这个标志从结果项列表中找到app框,并确定其位置。由于结果项的展现位置是不断变化的,受点击调权控制的。因此不能根据一个结果页中的位置来确定app强度,需要根据过去一段时间的平均展现位置来确定。我计算过去几个小时的平均展现位置来确定其强度,但是这样有点不合理,因为存在一个时效性问题,用户的需求随着时间在变化的,比如过去用户对2048这个app需求不是大,但是突然有一天2048 app的需求突然暴涨。我们更信赖离当前时间点最近的平均展现位置。因此,最终决定算加权平均展现位置,离当前时间点越近,权重越大。

每个小时的平均展现位置,计算方法:

(位置1*位置1出现的次数+位置2*位置2出现的次数+…)/(位置1出现的次数+位置2出现的次数+…)

过去24个小时的平均展现位置,计算方法:

(第一个小时的平均展现位置*权重1+第二个小时的平均展现位置*权重2+…)/(权重1+权重2+…)

这样计算得到最终的平均展现位置,来确定app强度值。

更新任务有两种需求,一种是长线更新,一种是短线更新,长线更新处理为过去24小时的展现日志,大概20几G,而且要更新app词典中所有的专名。短线更新处理过去6个小时的展现日志,大概几G.,只更新app词典中的部分专名,这部分专名是具有爆发性的特性,在一定时间内Pv比较高。

这两个任务更新的逻辑都一样,可以用一份代码。用了两个ct任务,一个是每6小时跑一次,一个是每周跑一次。任务是要跑hadoop的,而hadoop的运行时间不确定,小时级任务大概一次两个小时,周级任务大概一次6个小时,这样可能能出现一个任务没跑完,另一个任务开始跑的情况。这样就会导致重叠问题,一个任务对另外一个任务的结果造成影响。为了避免这个问题,我当时的做法是用锁和队列的机制。一个定时任务开始启动的时候,先将这个任务的一些信息加到队列里面,就是在一个任务目录下面加上创建一个文件,并将当前任务的参数信息放进去。然后开始检查锁文件是否存在,并且锁文件里面的进程id还在跑,说明有任务在跑,直接退出。否则开始从队列里面取一个最新的任务开始跑,并将其他任务都删除(因为存在时效性问题,旧的任务结果不可靠)。这样还存在一个饥饿问题,周级任务由于启动周期为一周,很可能一直被小时级的任务抢占,可能永远都不能运行,因此设一个优先级,队列用两个目录存放,一个是周级任务目录,一个是小时级任务目录。每次跑任务的时候优先从周级任务目录里面跑。这样就不会存在周级任务永远执行不了的情况了。

还有一个问题,由于跑任务的时候需要将hadoop输出文件输出到本地机器,并且每跑一次任务保存一份数据,作为历史记录,这样积累的数据量会很多,并且这个机器还做其他任务,磁盘空间可能会出现不足的情况。如果磁盘空间不足而运行程序会导致程序出错或影响之前的结果,因此为了避免这个问题,在程序运行前,先检查磁盘空间是否充足,如果不充足退出。

后来还遇到一个问题,运行代码的机器生成最终词典文件是要被另外一台机器拿到的,但是运行代码的机器存在挂掉的风险,而这个词典本身很重要,为了保证这台机器挂掉的情况也能提供服务,我做了一个冗余,把相同的代码复制到另外一台机器,让另外一台机器也能提供服务。最终的设计是这样的:有一个需要词典的机器,这台机器控制着ct任务,当有ct任务执行时,首先通过socket方式询问任务机器1,如果任务机器1没有故障,会创建一个新的进程去执行app强度更新任务,成功或失败将结果以socket方式返回给ct任务机器,ct任务机器得知任务执行成功,则从任务机器1中取词典。如果任务机器1挂了,或者磁盘空间不足,或者任务失败,则先发邮件给管理员,并且将任务切换到任务机器2。这些都是通过socket方式完成的。

收获:很多时候完成程序功能不难,但是要让这个程序提供一个可靠稳定的服务就是一件不容易的事,这需要我们考虑问题要周全。

(进程调度、进程间的通信(socket)、hadoop)

股票专名词典挖掘:

这是我在移动搜索部做的第一个偏数据挖掘项目。这个项目的目的是挖掘股票这个垂直类目的专名词典和同义词词典。专名的意思就是某个具体类目的实体名,比如股票的专名有百度,腾讯,资金矿业。这些专名从哪儿挖呢,一种方法就是从垂直站点里抓取,但是从垂直站点里抓取就不叫方法了,而且垂直站点里面抓的毕竟有限,并且不能找到同义词。我当时想了一个方案,在前期调研的时候,我观察了一些有股票需求的query,发现这些query都有一个共性,用户搜股票的query有一些通用的模板,比如:XX股票,XX今日行情,XX停盘等等。假如把这些模板找出来,可以用这些模板去找股票专名。举个例子,我有模板XX股票,如果一个query为新浪股票,这样我可以把新浪抠出来作为候选专名。

那么我首先要找模板,找模板的方法是先选一些种子专名,比如“百度”、“腾讯”、“资金矿业”,选200个左右,然后用这些种子专名去找扫query日志,把query日志中包含了种子专名的部分替换成特定的格式,比如“百度股票多少钱”匹配了“百度”,这样经过替换后得到模板“[D:stock]股票多少钱”,对所有的模板的次数由高到底做一个排序,然后人工挑选出一些模板。

有了模板之后,我们可以用这个模板去从query日志中抠出候选专名,可以将模板写成正则的方式,比如“[D:stock]股票多少钱”写成“(.+?)股票多少钱$”。但是这样抠出来的候选专名存在很多噪音,比如有一个模板是“[D:stock]今日行情”,这样会抠出“黄金”,需要用一个分类器去过滤。

这个分类器的目的是从候选专名中挑出股票类目的专名。我当时没有学习过数据挖掘,因此用的方法比较直接。我当时的想法就是找出文章中与股票类目专名频繁共同出现的词(用wordsim工具),我们可以把这些词作为一个向量,称为标准向量,当判断一个词是否是股票专名,或者股票专名的需求强度有多大,我们可以找出它的共现词,也作为一个向量,与标准向量做一个cos计算,算得一个分值。这样每个候选的专名有一个分值,卡一个阈值就可以选出是股票的专名。但是后来遇到一个问题,核心向量不能区分公司名和股票名,后来又经过观察,股票名搜索的时候,在百度结果页title中会带上股票代码,并且有固定格式。我再结合这个特征来进行区分。

同义词挖掘:为了扩大召回,还需要做同义词召回,怎么去找同义词呢?一种方法是从session日志中找,另外一种方法是从query日志中找。

(字符串匹配,KMP,tf-idf,分词,垂直搜索,trie树)

0 0
原创粉丝点击