ARCHIVE: 数据挖掘
Dump Plugin并行化实践
2012-09-03 11:11 叶重 Comments (2)
先简单介绍下Dump Plugin的由来,在搜索Dump中心服务化的项目中,我们把Dump中心的增量数据产出分为2个阶段,Loader阶段和Join阶段,Loader阶段把数据准备成Key-Values形式,Join阶段将数据取出,计算各种业务逻辑并产出最终数据。业务逻辑的计算是相当繁琐且易出错,这类事情做一遍足以,所以设计了一个接口,按照业务自身划分成一个个小块逻辑实现接口。这些个小业务逻辑模块即构成Dump的业务Plugin。
这样做的好处:
1, 按业务本身划分,结构相对清晰,容易维护。
2, 架构和业务通过接口交互,重构架构将尽可能少的影响业务代码
3, 每个业务模块的耗时能准确统计出并能做针对性的优化。
在最初的版本中,先根据依赖关系计算好plugin的执行顺序,然后顺序执行,是一个串行的过程,如下图:
此种方式,计算耗时与业务的复杂程度成正比。而目前Dump中心已经有十几个个业务逻辑Plugin,并且plugin之间有复杂的依赖关系。所以我们尝试用更高效的并发方式去运行这些plugin。这个项目用的开发语言是Java,Java的多线程有多种成熟的设计模式,结合现有框架,我们设计了两种方案并分别尝试。
方案1,以单条数据为粒度,在一条数据的运行内部实现并行化,如下图:
简单的来说,就是起一个工作线程组来运行plugin,来一条数据后,工作线程根据依赖关系获取当前可运行的plugin,当所有plugin都运行完毕后,输出数据。类似于Work Thread模式,工作线程没数据就等着,来了数据就做。主要代码流程如下:
public class Main { private Semaphore mainSemaphore, workSemaphore; private Data data; private int workThreadNum; public Data run(Data data) {
…
HBase在淘宝主搜索的Dump中的性能调优
2012-08-03 16:16 道凡 Comments (7)
目前HBase已经运用于淘宝主搜索的全量和增量的数据存储,有效的减低的数据库的压力,增强了业务扩展的能力。Dump系统的特点是要求在短时间内处理大量数据,对延时要求高。在实施这个项目过程中,我们积累了一些优化的实践,抛砖引玉,供大家参考。
环境:Hadoop CDH3U4 + HBase 0.92.1
1、 尽可能用LZO
数据使用LZO,不仅可以节省存储空间尤其是可以提高传输的效率,因为数据是在regionserver端作解压的。通过测试,可以明显提高HBASE从HDFS的读的性能。尽量不用GZ的方式,GZ的方式在bulkload时有线程安全问题。
2、 根据场景调整Block size
由于使用我们非常关注随机读的性能,一条记录的长度较小,通过设置blocksize=8k,可以提高随机读的性能。
3、 在系统空闲的时候,启动major compaction
在实际中,我们发现随着region不停的flush,hfile的增多会影响scan的性能,为了能控制影响,我们设置了hbase.hregion.majorcompaction为一个比较大的时间,通过另外的定时脚本在空闲的时候集中做各表的major compaction。这样可以保证scan的性能是平稳的。
4、 调整balance策略
我们采用了表级别的balance,但是上线后依旧发现有时scan,会抛timeout的异常。通过hmaster的日志,发现当hbase的表多并且当有regionserver挂掉的时候,表级别balance的策略会导致大面积的region移动。后来通过增加阈值控制,每次balance的时候,每张表的region移动的数量不超过整张表region数量的5%。
5、 关注HDFS的问题
当有regionserver挂掉后,有时split log会很慢,会超时导致master不停的重新resubmit split task,最终导致某些scan任务抛timeout异常。原因是datanode的连接数太多,具体原因是https://issues.apache.org/jira/browse/HDFS-3359 通过升级hdfs到HADOOP CDH3U4之后,问题解决。
6、 注重rowkey设计
使用hash值+具体的key,并且设置一个巨大的MAX_FILESIZE。固定每个region的范围,防止做split,防止split带来的隐患。
7、 尽可能的用batch操作
通过使用batch的方式,能提高近10倍的性能,使原本单条记录的随机读从20ms左右降至2ms左右,因为batch的内部是按regionserver来发送数据的,所以每次batch的List<Row>的大小,应设置成regionserver的若干倍。
8、 如果可以的话,减少数据的versions
由于我们业务只需要一个版本,设置version=1,可以有效的控制hfile的大小,从而控制scan的性能。
中文商品的标题信息分析
2012-05-18 17:17 方证 Comments (1)
当用户在一个网站浏览或者搜索商品时,在大多数时间他所面对的都是商品标题+商品图片的商品信息形式。只有当这种简要的信息抓住了用户的眼球时或者达到用户的心理预期时才能引导用户进入更详细的商品详情页。这就对其中唯一的文本信息载体:商品标题包含的信息内容质量提出了要求。
我们来看两个商品标题的例子,这是分别来自淘宝网和京东商城的两条普通商品标题:
冲三冠 腾龙AF 17-50mm VC F2.8(B005)送uv包顺丰8折 大陆行货
这条Title里包含了唯一确定商品的关键属性(品牌和型号)、商品性质(行货),商品促销信息(冲三冠折扣、赠品)
能率(NORITZ)GQ-1680CAFE 天然气(12T)16升家用燃气快速热水器 白色
这条Title包含了商品的中英文品牌、型号、产品类型、容量、颜色等信息。
可以看到:作为用户了解商品信息的第一道入口,商品标题包含有丰富而优质的商品信息,能够在第一时间向用户传达商品最重要的特征。有鉴于此, 在一淘网对商品信息的处理过程中,我们对部分商品的标题进行分析分解,将其中包含的语义信息归类。然后提取出需要的语义信息,再进行进一步的产品逻辑处理。为此,我们开发了中文商品的标题信息分析(以下简称Title分析)程序。
Title中商品信息类别
要对Title信息分类,首先需要知道Title中都可能包含哪些类别的信息。我们把Title中的商品信息类别归纳如图1:
图1
Title分析的基本处理思路:
处理的基本单元是词,我们使用了阿里巴巴自己的分词工具AliWS将商品Title切词并获取词的长度、词性、属性等信息。 每一种语义类各自的识别方法包括两种基本类型:词典和特征模式。
词典:
某些语义类并没有复杂的组成形式,当某个词在title中出现就可以认为这个词属于该语义类。以品牌词为例,无论在何种情况下,当title中出现了”阿迪达斯”这个词,就可以认为它代表品牌。(当然也有例外情形,如“苹果”有可能是品牌也可能是产品类型。这就需要一些消除歧义的逻辑来补充)。对于这种语义类,我们采用离线挖掘的方式整理出词典,然后在处理过程中按照词典匹配分析。
特征模式:
语义类一般存在有特别的特征模式。包括组成词的词性,词形式,上下文等都满足一定的规则。利用这种模式就可以做基本的语义判断。例如
…
HBase中如何开发LoadBalance插件
2012-05-16 17:17 莫问 Comments (0)
HBase 中的LoadBalancer策略控制了如何在集群启动时Assign所有用户Region到各个RegionServer上,以及如何定期检查Region分布情况并重新调整Region位置的。这些工作在0.92之前的版本中都是在HBase Master内核中实现的,开发人员如果希望扩展自己的LoadBalancer插件,只能Hack源码,但这随着社区版本的升级,Hack工作必须移植到新的版本中。幸好在0.92版本中,HBase将LoadBalancer策略从Master内核中抽取了出来,开放了LoadBalancer Interface,允许开发者根据自己的业务特定扩展自己的LoadBalancer插件。
定制LoadBalancer插件需要两个步骤:
继承org.apache.hadoop.hbase.master.LoadBalancer Interface,实现自己的LoadBalancer Class 在hbase-site.xml中增加配置项,使得定制的LoadBalancer生效
<property>
<name>hbase.master.loadbalancer.class</name>
<value>{your custom loadbalancer class name}</value>
<description></description>
</property>
因此,开发LoadBalancer插件的前提准备工作便是清楚了解org.apache.hadoop.hbase.master.LoadBalancer这个Interface:
public interface LoadBalancer extends Configurable { /** * Set
…
如何预测用户query意图
2011-01-10 13:13 renzhong Comments (10)
有一个朋友问,一个用户搜索一个query是“百度”,怎么知道用户真正是想找什么呢。
我回答说,分析之前搜索这个query的用户点了些什么结果啊。
朋友继续问,如果没有用户点击呢。
呃,如果没有点击,这个问题就比较复杂了。整理了下思路,于是写成了本文。主要描述了关于如何预测用户query意图。希望会有所帮助。
首先我们的明确一个标准,如何判断我们对用户意图的猜测是正确的?
用户的思维是很发散的,也许今天搜索“葛优”,是想找“让子弹飞”,明天搜索相同的query,就是想找“非诚勿扰”。 我们确定了要在某个方面的query预测上做一个改进,那么我们首先的把标准定下来,依照这个标准来进行改进。
现在有很多对搜索系统的评价指标,如pv,ipv,ctr,搜索引导的后续转化率等可以量化的指标,这些指标是对搜索系统总体的评价。具体到用户意图预测上,标准很难确定,对于排序比较直观的就是进行side by side的评测,比较原有的效果和改进的效果,看是否会排序更优;对于导航,那我们可以看我们预测的类目和用户实际点的类目的占比,是否能有效降低用户点击非推荐类目的比率。
接下来,我们从2种情况下来回答这个问题,
如果我们已经有了一套完整的系统,有大量的用户访问
先从简单的说起,假设我们已经有了一个完整的搜索系统,有大量的用户访问,我们希望通过对用户query的预测来提高搜索体验。这样的系统的大概架构如下。
包括图所示的几个部分,
1 前端(f2e)
前端负责直接和用户进行交换,当收到用户搜索请求之后,往后端系统传递请求,并接收搜索引擎返回的结果,组织到网页上,展示给用户。
前端还肩负着一个重要的记录日志的工作,这个日志的记录,并不是apache的访问日志,这样的日志内容过于简单。如果要前端记录过多的日志,又会给服务器带来不小的压力。所以目前主要的手段是通过用户在页面上进行搜索或点击等行为时,调用javascript向指定的日志服务器,发送特征url来记录,这种url不会返回内容,仅仅为了给日志服务器添加记录。发送的url会包括从cookie中解析出的用户特有的数据。
2 Query处理
Query处理是线上服务系统,它是对用户意图进行预测后,对用户的搜索结果进行改进。在接收到前端的请求之后,会利用线下对query分析得到的数据,对用户的query和上下文环境进行分析,附加更多的条件到搜索引擎的请求命令之中。常见的Query处理,会有以下的一些类容,query改写,query分类预测,query的导航等。
Query处理这部分主要的意义在于,将用户的搜索query,翻译为对搜索引擎更适合查询串。在大多数情况下,用户使用搜索引擎是为了解决自己的问题,如果能直接获得答案,用户是不大愿意进行搜索的。
用户也许的问题是,“非诚勿扰2里面说的廖凡是谁”这样的一个问题,这样的问题直接搜索是不太会有会令用户比较满意的答案,(除非有向百度知道这样的系统已经存在了类似的问题)。有些用户就会考虑换个关键词试试,搜索下“廖凡”,看是否会有一些答案可以让自己满意。所以很大程度上是搜索引擎在教用户如何使用自己。但是并非所有的用户都对搜索系统如此的熟悉,那我们就需要考虑看看在我们搜索的结果里面效果不太好的query,分析它是怎么构成的。我们也许无法准确回答“非诚勿扰2里面说的廖凡是谁”,但是可以把其中最关键的信息抽取出来“非诚勿扰2”“廖凡”,并且,我们需要回答“是谁”这样的疑问问题。把这些信息传递给引擎,才会有更好的结果。
再例如,用户想找,“1000元左右的手机”,那么对于淘宝来说,可以把搜索的条件转化为800-1200价格限制范围的,手机类目下的宝贝,或者更进一步,把各种型号的手机,列在一起,进行参数的比较。
再深入一步,用户想找“舒淇在非诚勿扰2中用的手机”,如果我们可以把这个问题转化为对“朵唯S920”的搜索,那就是非常非常好的效果了,至于这个query如何对应到这个结果,也许后面的一些分析,能提供一些线索。
具体的实现,可以参考下面几点,
对query的线上处理,如果是较为hot的query,可以以查表为主,可以用hash表,trie树等进行查表,把在线下计算好的数据,通过查表的方式找到对应的结果,附加到给引擎的搜索条件上,并返回。
另外,可以把线下训练好的模型,在线上进行预测,一般的分类算法预测速度都比较快。可以对长尾的query,进行及时的预测。
也可以做一些规则,如我们上面举的例子,“1000元左右”,可以通过正则表达式进行识别,将其转为对应的搜索条件。这些规则如何来定呢,这是比较麻烦的一点,像这类的query,肯定是pv比较低的,属于长尾的query,这些query效果提升可能比较明显,但是对总体搜索系统效果影响会较小。这个问题比较尴尬,如果我们这类query处理的效果好的话,那用户会使用的更多;用户知道了这样的query效果不好,所以就换成了效果好的query。如果要做好规则,那就把长尾的这些query都拿出来,多看看,分下类,再结合实际的问题分类,总结出一些通用的规则,来进行优化。
3 搜索引擎
搜索引擎主要负责检索和排序,一般由一些倒排表和正排表组成。倒排表用于查找对应的文档id,能快速的检索出命中query的文档,在根据正排表来查对应id的数据。
一般将需要字符串类型的文档字段作为倒排表来进行检索,字符型的字段可以放在正排表中,在通过倒排表找到了满足条件的文档,再在正排表中进行过滤。
找到满足条件的文档后,再进行过滤,统计,并根据排序参数进行排序。
排序分为2个部分,一部分是文档自身的静态分,每个文档会有类似pagerank这样分数,另外一部分是还有和query相关的部分,会计算文档和query的关系,例如,query中出现的词的在文档中是否距离较近,query是否为文档的中心词。
4 日志存储
日志存储系统收集前端记录的日志,存储在数据仓库中,解析后用分布式文件系统来存放。有几类日志比较重要,
A、…
轻松写出优雅的Java代码之CheckStyle
2011-01-04 14:14 西铭 Comments (0)
轻松写出优雅的Java代码之check style
View more presentations from Zhen Li.
下载:taobao-checker-1.0.2
Mllib机器学习工具包在Hadoop上的使用
2010-12-22 16:16 元涵 Comments (1)
Hadoop是基于Java的数据计算平台,在我们公司得到了广泛应用。同样mllib也是我们算法组同学经常使用的一个机器学习工具包。但目前mllib工具包只提供了供C++程序调用的so链接库,没有可供java程序调用的jar包。由于这个需求有一定的普遍性,作者将mllib做了进一步封装,并通过jni的方式把其封装成了可供java程序调用的接口。
1 结构示意图
2 对mllib的二次封装
原始的mllib开发包对模型的处理(训练,加载,预测)都是per model的,对于每一个模型都需要写一些重复类似的代码。实际应用中我们的模型也一般都是多个的(分行业,或分类目来做),不太会只是用一个大而泛的模型。mllib没有提供一个类似于Manager的类来管理多个模型。所以笔者对mllib进行了二次封装,能够让大家比较方便的通过配置来管理多个模型,也让大家从需要了解mlllib最底层的接口中解放出来。
封装的Manager类:
class MlrManager { public: MlrManager(); virtual ~MlrManager(); //提供的两个接口 //初始化函数,输入为配置文件,以配置文件为驱动来加载模型 bool Init(const char* pConf); //预测函数,输入为特征数组和模型编号,输出为预测分数 feature_t CalMlrScore(std::vector<feature_t>& vecFeatures,int nModel); private: feature_t GetMlrScore(std::vector<feature_t>& vecFeatures,mllib::MlModel* pModel,ENUM_MODEL_TYPE enumModelType);
…
几个随机算法
2010-12-22 16:16 天铎 Comments (21)
在日常工作中,经常需要使用随机算法。比如面对大量的数据, 需要从其中随机选取一些数据来做分析。 又如在得到某个分数后, 为了增加随机性, 需要在该分数的基础上, 添加一个扰动, 并使该扰动服从特定的概率分布。本文主要从这两个方面出发, 介绍一些算法, 供大家参考。
首先假设我们有一个使用的随机函数float frand(), 返回值在(0, 1)上均匀分布。大多数的程序语言库提供这样的函数。 在其他的语言如C/C++中, 可以通过间接方法得到。如 frand()= ((float)rand() ) / RAND_MAX;
1, 随机选取数据
假设我们有一个集合A(a_1,…,a_n), 对于数m,0≤m≤n, 如何从集合A中等概率地选取m个元素呢?
通过计算古典概率公式可以得到, 每个元素被选取的概率为m/n。 如果集合A里面的元素本来就具有随机性, 每个元素在各个位置上出现的概率相等, 并且只在A上选取一次数据,那么直接返回A的前面m个元素就可以了, 或者可以采取每隔k个元素取一个等类似的方法。这样的算法局限很大, 对集合A的要求很高, 因此下面介绍两种其他的算法。
1.1 假设集合A中的元素在各个位置上不具有随机性,…
Treelink算法介绍
2010-12-21 18:18 元涵 Comments (6)
“机器学习”这个名词对大家来说想必不是一个陌生的词汇,特别对算法组的同学来说,工作中或多或少接触使用过这种“高科技“。对于我来说,刚来淘宝工作一个月就开始接触了机器学习,当时做主搜索功夫熊猫项目,和小致飘雪一起做交易模型,正是使用了机器学习的方法,也首次接触了treelink模型。做完那个项目后对机器学习解决问题的流程有了一定的了解,但对其内部的工作原理和实现机制还是完全不知道,基本也就是在黑盒使用机器学习工具。后面也多多少少听了一些机器学习的讲座,但都是一些比较宽泛的基本概念,没有深入的原理性的介绍。也自己尝试过专研一下,但生硬晦涩的E文让人望而生畏。一直到今年做导购搜索的项目,又再次需要使用机器学习,“怀揣着对科学真理的向往”,主动请缨做模型方面的工作。经过一个多月的学习实践,算是对treelink模型有了一定的了解。下面做一些对treelink模型通俗版的介绍。都是自己的一些理解,如果有误,多指教。
在介绍treelink之前首先不得不简单介绍一下决策树算法,决策树相信大家都有所了解,任何一本机器学习书籍都会介绍这种算法,也是应用最广的归纳推理算法之一。该模型学习的结果是一棵决策树,这棵决策树可以被表示成多个if-else的规则。下图是一个典型的学习得到决策树。这棵决策树根据两个特征因素来分类“元涵今天的心情好坏”。长方形的表示特征,椭圆型的表示特征的取值,最下面的叶子节点就是最后的分类结果了。
学习得到如上这棵决策树之后,当输入一个待预测的样本实例的时候,我们就可以根据这个样本的两个特征的取值来把这个样本划分到某一个叶子节点,得到分类结果了,这就是决策树模型的预测过程,决策树的学习构建过程这里就不介绍了,大家看书吧,比较经典的有ID3算法和C4.5算法。
切入正题下面开始说treelink算法,treelink这个名字其实只是我们阿里集团内部的叫法,学术上的名称叫GBDT(Gradient boost decision tree)。treelink模型不像决策树模型那样仅由一棵决策树构成,而是由多棵决策树构成,通常都是上百棵树,而且每棵树规模都较小(即树的深度会比较浅)。模型预测的时候,对于输入的一个样本实例,首先会赋予一个初值,然后会遍历每一棵决策树,每棵树都会对预测值进行调整修正,最后得到预测的结果。
F0是设置的初值, Ti是一棵一棵的决策树。对于不同的问题(回归问题或者分类问题)和选择不同的损失函数,初值的设定是不同的。比如回归问题并且选择高斯损失函数,那么这个初值就是训练样本的目标的均值。
下面是一个简单的treelink模型示意图。模型的目标是上海一套普通商品房的价格,特征有三个:房子的面积(连续特征),是否在内环(分类特征),是否学区房(分类特征)。模型由四棵决策树构成,每棵决策树只进行了一次分裂,即树的深度为一(这种树被称为Decision Stump)。实际应用中通常较复杂,深度不会为一。
初值设定为上海普通商品房价格的均值150万,每经过一棵决策树,都会对根据相应特征的取值对预测价格进行调整。比如一个面积为120平的内环非学区房的价格预测值为:150+20-10+30-10=180万。
那为什么要用多棵决策树,一棵决策树为什么不好呢?使用单棵决策树,最大的问题就是会因为过度分裂,而造成过拟合,失去泛化能力。试想一下,对于给定的一批训练数据,完全可以只构造一棵树,不断分裂下去,直到每个叶子节点包含的样本的目标值都一样,然后把这节点的预测值设定成这个目标值,这样构造出来的这棵树就可以在这批训练数据上达到100%的准确性。但这样一棵过度分裂的决策树,对于新的样本基本没有什么预测能力。而如果分裂太少,又会造成学习不够充分。Treelink使用多棵决策树正是希望能够在训练精度和泛化能力两个方面都能达到较好的效果。作为一种boosting算法,Treelink自然包含了boosting的思想:将一系列弱分类器组合起来,构成一个强分类器。它不要求每棵树学到太多的东西,每颗树都学一点点知识,然后将这些学到的知识累加起来构成一个强大的模型。举个现实生活中的例子,电视里的那种益智类节目,如开心词典,答题者有三次请求帮组的机会,其中一个就是请求现场所有观众,通过他们的选择来给出答案。我们可以把每个观众当做一个弱的分类器,他们各个单独的准确率都不高,但把他们的知识综合起来这个准确率会大大提升。也许上面这个例子不太能说服你,我们来把这个例子量化。假如我们有三个观众,他们各自的准确率为60%(非常弱的分类器,只比随机分类器好一点点),如果这三位观众中有大于等于两位的答案是正确的,那么则认为我们正确了,反之则错误。那么我们正确的概率是多少呢?preciseness = p(三个人都正确) + p(三个人中有两个人正确) = 0.6*0.6*0.6 +…
如何在Hadoop集群运行JNI程序
2010-12-13 7:07 家逸 Comments (14)
hadoop是基于java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力。 阿里巴巴内部使用的分词软件(用c++实现的,以下简称WS包)是日常工作中最基本的软件包,通过java的jni机制,笔者将WS包成功的运行在hadoop上,深受很多部门的欢迎。下面借这个例子介绍hadoop上jni程序的开发过程。
首先,简单介绍一下WS包中的调用接口和基本结构。 WS包包括词典文件A.dict,对外提供静态链接库文件libWS.a。WS.h如下:
Class WS{ int init(const char* name); int segment(char* dest, char* src, int len,int kind); }
我们的方案是首先生成jni的原型定义,然后根据原型定义,来包装WS类的接口,最后生成可在tasknode上运行的jni程序包。结构如下图所示
第一步,我们先使用java的jni技术,生成C的原型接口(prototype),然后编写Wsjni.java 文件,这是为云梯程序提供的类文件,其中libwsjni.so 就是wrapper类的动态链接库:
Class Wsjni{ Public Native int init(String conf); Public Native String segment(String src,int kind); Public Native void close(); //用于显示的释放内存 Static{
…
Dump Plugin并行化实践
2012-09-03 11:11 叶重 Comments (2)
先简单介绍下Dump Plugin的由来,在搜索Dump中心服务化的项目中,我们把Dump中心的增量数据产出分为2个阶段,Loader阶段和Join阶段,Loader阶段把数据准备成Key-Values形式,Join阶段将数据取出,计算各种业务逻辑并产出最终数据。业务逻辑的计算是相当繁琐且易出错,这类事情做一遍足以,所以设计了一个接口,按照业务自身划分成一个个小块逻辑实现接口。这些个小业务逻辑模块即构成Dump的业务Plugin。
这样做的好处:
1, 按业务本身划分,结构相对清晰,容易维护。
2, 架构和业务通过接口交互,重构架构将尽可能少的影响业务代码
3, 每个业务模块的耗时能准确统计出并能做针对性的优化。
在最初的版本中,先根据依赖关系计算好plugin的执行顺序,然后顺序执行,是一个串行的过程,如下图:
此种方式,计算耗时与业务的复杂程度成正比。而目前Dump中心已经有十几个个业务逻辑Plugin,并且plugin之间有复杂的依赖关系。所以我们尝试用更高效的并发方式去运行这些plugin。这个项目用的开发语言是Java,Java的多线程有多种成熟的设计模式,结合现有框架,我们设计了两种方案并分别尝试。
方案1,以单条数据为粒度,在一条数据的运行内部实现并行化,如下图:
简单的来说,就是起一个工作线程组来运行plugin,来一条数据后,工作线程根据依赖关系获取当前可运行的plugin,当所有plugin都运行完毕后,输出数据。类似于Work Thread模式,工作线程没数据就等着,来了数据就做。主要代码流程如下:
public class Main { private Semaphore mainSemaphore, workSemaphore; private Data data; private int workThreadNum; public Data run(Data data) {
…
HBase在淘宝主搜索的Dump中的性能调优
2012-08-03 16:16 道凡 Comments (7)
目前HBase已经运用于淘宝主搜索的全量和增量的数据存储,有效的减低的数据库的压力,增强了业务扩展的能力。Dump系统的特点是要求在短时间内处理大量数据,对延时要求高。在实施这个项目过程中,我们积累了一些优化的实践,抛砖引玉,供大家参考。
环境:Hadoop CDH3U4 + HBase 0.92.1
1、 尽可能用LZO
数据使用LZO,不仅可以节省存储空间尤其是可以提高传输的效率,因为数据是在regionserver端作解压的。通过测试,可以明显提高HBASE从HDFS的读的性能。尽量不用GZ的方式,GZ的方式在bulkload时有线程安全问题。
2、 根据场景调整Block size
由于使用我们非常关注随机读的性能,一条记录的长度较小,通过设置blocksize=8k,可以提高随机读的性能。
3、 在系统空闲的时候,启动major compaction
在实际中,我们发现随着region不停的flush,hfile的增多会影响scan的性能,为了能控制影响,我们设置了hbase.hregion.majorcompaction为一个比较大的时间,通过另外的定时脚本在空闲的时候集中做各表的major compaction。这样可以保证scan的性能是平稳的。
4、 调整balance策略
我们采用了表级别的balance,但是上线后依旧发现有时scan,会抛timeout的异常。通过hmaster的日志,发现当hbase的表多并且当有regionserver挂掉的时候,表级别balance的策略会导致大面积的region移动。后来通过增加阈值控制,每次balance的时候,每张表的region移动的数量不超过整张表region数量的5%。
5、 关注HDFS的问题
当有regionserver挂掉后,有时split log会很慢,会超时导致master不停的重新resubmit split task,最终导致某些scan任务抛timeout异常。原因是datanode的连接数太多,具体原因是https://issues.apache.org/jira/browse/HDFS-3359 通过升级hdfs到HADOOP CDH3U4之后,问题解决。
6、 注重rowkey设计
使用hash值+具体的key,并且设置一个巨大的MAX_FILESIZE。固定每个region的范围,防止做split,防止split带来的隐患。
7、 尽可能的用batch操作
通过使用batch的方式,能提高近10倍的性能,使原本单条记录的随机读从20ms左右降至2ms左右,因为batch的内部是按regionserver来发送数据的,所以每次batch的List<Row>的大小,应设置成regionserver的若干倍。
8、 如果可以的话,减少数据的versions
由于我们业务只需要一个版本,设置version=1,可以有效的控制hfile的大小,从而控制scan的性能。
中文商品的标题信息分析
2012-05-18 17:17 方证 Comments (1)
当用户在一个网站浏览或者搜索商品时,在大多数时间他所面对的都是商品标题+商品图片的商品信息形式。只有当这种简要的信息抓住了用户的眼球时或者达到用户的心理预期时才能引导用户进入更详细的商品详情页。这就对其中唯一的文本信息载体:商品标题包含的信息内容质量提出了要求。
我们来看两个商品标题的例子,这是分别来自淘宝网和京东商城的两条普通商品标题:
冲三冠 腾龙AF 17-50mm VC F2.8(B005)送uv包顺丰8折 大陆行货
这条Title里包含了唯一确定商品的关键属性(品牌和型号)、商品性质(行货),商品促销信息(冲三冠折扣、赠品)
能率(NORITZ)GQ-1680CAFE 天然气(12T)16升家用燃气快速热水器 白色
这条Title包含了商品的中英文品牌、型号、产品类型、容量、颜色等信息。
可以看到:作为用户了解商品信息的第一道入口,商品标题包含有丰富而优质的商品信息,能够在第一时间向用户传达商品最重要的特征。有鉴于此, 在一淘网对商品信息的处理过程中,我们对部分商品的标题进行分析分解,将其中包含的语义信息归类。然后提取出需要的语义信息,再进行进一步的产品逻辑处理。为此,我们开发了中文商品的标题信息分析(以下简称Title分析)程序。
Title中商品信息类别
要对Title信息分类,首先需要知道Title中都可能包含哪些类别的信息。我们把Title中的商品信息类别归纳如图1:
图1
Title分析的基本处理思路:
处理的基本单元是词,我们使用了阿里巴巴自己的分词工具AliWS将商品Title切词并获取词的长度、词性、属性等信息。 每一种语义类各自的识别方法包括两种基本类型:词典和特征模式。
词典:
某些语义类并没有复杂的组成形式,当某个词在title中出现就可以认为这个词属于该语义类。以品牌词为例,无论在何种情况下,当title中出现了”阿迪达斯”这个词,就可以认为它代表品牌。(当然也有例外情形,如“苹果”有可能是品牌也可能是产品类型。这就需要一些消除歧义的逻辑来补充)。对于这种语义类,我们采用离线挖掘的方式整理出词典,然后在处理过程中按照词典匹配分析。
特征模式:
语义类一般存在有特别的特征模式。包括组成词的词性,词形式,上下文等都满足一定的规则。利用这种模式就可以做基本的语义判断。例如
…
HBase中如何开发LoadBalance插件
2012-05-16 17:17 莫问 Comments (0)
HBase 中的LoadBalancer策略控制了如何在集群启动时Assign所有用户Region到各个RegionServer上,以及如何定期检查Region分布情况并重新调整Region位置的。这些工作在0.92之前的版本中都是在HBase Master内核中实现的,开发人员如果希望扩展自己的LoadBalancer插件,只能Hack源码,但这随着社区版本的升级,Hack工作必须移植到新的版本中。幸好在0.92版本中,HBase将LoadBalancer策略从Master内核中抽取了出来,开放了LoadBalancer Interface,允许开发者根据自己的业务特定扩展自己的LoadBalancer插件。
定制LoadBalancer插件需要两个步骤:
继承org.apache.hadoop.hbase.master.LoadBalancer Interface,实现自己的LoadBalancer Class 在hbase-site.xml中增加配置项,使得定制的LoadBalancer生效
<property>
<name>hbase.master.loadbalancer.class</name>
<value>{your custom loadbalancer class name}</value>
<description></description>
</property>
因此,开发LoadBalancer插件的前提准备工作便是清楚了解org.apache.hadoop.hbase.master.LoadBalancer这个Interface:
public interface LoadBalancer extends Configurable { /** * Set
…
如何预测用户query意图
2011-01-10 13:13 renzhong Comments (10)
有一个朋友问,一个用户搜索一个query是“百度”,怎么知道用户真正是想找什么呢。
我回答说,分析之前搜索这个query的用户点了些什么结果啊。
朋友继续问,如果没有用户点击呢。
呃,如果没有点击,这个问题就比较复杂了。整理了下思路,于是写成了本文。主要描述了关于如何预测用户query意图。希望会有所帮助。
首先我们的明确一个标准,如何判断我们对用户意图的猜测是正确的?
用户的思维是很发散的,也许今天搜索“葛优”,是想找“让子弹飞”,明天搜索相同的query,就是想找“非诚勿扰”。 我们确定了要在某个方面的query预测上做一个改进,那么我们首先的把标准定下来,依照这个标准来进行改进。
现在有很多对搜索系统的评价指标,如pv,ipv,ctr,搜索引导的后续转化率等可以量化的指标,这些指标是对搜索系统总体的评价。具体到用户意图预测上,标准很难确定,对于排序比较直观的就是进行side by side的评测,比较原有的效果和改进的效果,看是否会排序更优;对于导航,那我们可以看我们预测的类目和用户实际点的类目的占比,是否能有效降低用户点击非推荐类目的比率。
接下来,我们从2种情况下来回答这个问题,
如果我们已经有了一套完整的系统,有大量的用户访问
先从简单的说起,假设我们已经有了一个完整的搜索系统,有大量的用户访问,我们希望通过对用户query的预测来提高搜索体验。这样的系统的大概架构如下。
包括图所示的几个部分,
1 前端(f2e)
前端负责直接和用户进行交换,当收到用户搜索请求之后,往后端系统传递请求,并接收搜索引擎返回的结果,组织到网页上,展示给用户。
前端还肩负着一个重要的记录日志的工作,这个日志的记录,并不是apache的访问日志,这样的日志内容过于简单。如果要前端记录过多的日志,又会给服务器带来不小的压力。所以目前主要的手段是通过用户在页面上进行搜索或点击等行为时,调用javascript向指定的日志服务器,发送特征url来记录,这种url不会返回内容,仅仅为了给日志服务器添加记录。发送的url会包括从cookie中解析出的用户特有的数据。
2 Query处理
Query处理是线上服务系统,它是对用户意图进行预测后,对用户的搜索结果进行改进。在接收到前端的请求之后,会利用线下对query分析得到的数据,对用户的query和上下文环境进行分析,附加更多的条件到搜索引擎的请求命令之中。常见的Query处理,会有以下的一些类容,query改写,query分类预测,query的导航等。
Query处理这部分主要的意义在于,将用户的搜索query,翻译为对搜索引擎更适合查询串。在大多数情况下,用户使用搜索引擎是为了解决自己的问题,如果能直接获得答案,用户是不大愿意进行搜索的。
用户也许的问题是,“非诚勿扰2里面说的廖凡是谁”这样的一个问题,这样的问题直接搜索是不太会有会令用户比较满意的答案,(除非有向百度知道这样的系统已经存在了类似的问题)。有些用户就会考虑换个关键词试试,搜索下“廖凡”,看是否会有一些答案可以让自己满意。所以很大程度上是搜索引擎在教用户如何使用自己。但是并非所有的用户都对搜索系统如此的熟悉,那我们就需要考虑看看在我们搜索的结果里面效果不太好的query,分析它是怎么构成的。我们也许无法准确回答“非诚勿扰2里面说的廖凡是谁”,但是可以把其中最关键的信息抽取出来“非诚勿扰2”“廖凡”,并且,我们需要回答“是谁”这样的疑问问题。把这些信息传递给引擎,才会有更好的结果。
再例如,用户想找,“1000元左右的手机”,那么对于淘宝来说,可以把搜索的条件转化为800-1200价格限制范围的,手机类目下的宝贝,或者更进一步,把各种型号的手机,列在一起,进行参数的比较。
再深入一步,用户想找“舒淇在非诚勿扰2中用的手机”,如果我们可以把这个问题转化为对“朵唯S920”的搜索,那就是非常非常好的效果了,至于这个query如何对应到这个结果,也许后面的一些分析,能提供一些线索。
具体的实现,可以参考下面几点,
对query的线上处理,如果是较为hot的query,可以以查表为主,可以用hash表,trie树等进行查表,把在线下计算好的数据,通过查表的方式找到对应的结果,附加到给引擎的搜索条件上,并返回。
另外,可以把线下训练好的模型,在线上进行预测,一般的分类算法预测速度都比较快。可以对长尾的query,进行及时的预测。
也可以做一些规则,如我们上面举的例子,“1000元左右”,可以通过正则表达式进行识别,将其转为对应的搜索条件。这些规则如何来定呢,这是比较麻烦的一点,像这类的query,肯定是pv比较低的,属于长尾的query,这些query效果提升可能比较明显,但是对总体搜索系统效果影响会较小。这个问题比较尴尬,如果我们这类query处理的效果好的话,那用户会使用的更多;用户知道了这样的query效果不好,所以就换成了效果好的query。如果要做好规则,那就把长尾的这些query都拿出来,多看看,分下类,再结合实际的问题分类,总结出一些通用的规则,来进行优化。
3 搜索引擎
搜索引擎主要负责检索和排序,一般由一些倒排表和正排表组成。倒排表用于查找对应的文档id,能快速的检索出命中query的文档,在根据正排表来查对应id的数据。
一般将需要字符串类型的文档字段作为倒排表来进行检索,字符型的字段可以放在正排表中,在通过倒排表找到了满足条件的文档,再在正排表中进行过滤。
找到满足条件的文档后,再进行过滤,统计,并根据排序参数进行排序。
排序分为2个部分,一部分是文档自身的静态分,每个文档会有类似pagerank这样分数,另外一部分是还有和query相关的部分,会计算文档和query的关系,例如,query中出现的词的在文档中是否距离较近,query是否为文档的中心词。
4 日志存储
日志存储系统收集前端记录的日志,存储在数据仓库中,解析后用分布式文件系统来存放。有几类日志比较重要,
A、…
轻松写出优雅的Java代码之CheckStyle
2011-01-04 14:14 西铭 Comments (0)
轻松写出优雅的Java代码之check style
View more presentations from Zhen Li.
下载:taobao-checker-1.0.2
Mllib机器学习工具包在Hadoop上的使用
2010-12-22 16:16 元涵 Comments (1)
Hadoop是基于Java的数据计算平台,在我们公司得到了广泛应用。同样mllib也是我们算法组同学经常使用的一个机器学习工具包。但目前mllib工具包只提供了供C++程序调用的so链接库,没有可供java程序调用的jar包。由于这个需求有一定的普遍性,作者将mllib做了进一步封装,并通过jni的方式把其封装成了可供java程序调用的接口。
1 结构示意图
2 对mllib的二次封装
原始的mllib开发包对模型的处理(训练,加载,预测)都是per model的,对于每一个模型都需要写一些重复类似的代码。实际应用中我们的模型也一般都是多个的(分行业,或分类目来做),不太会只是用一个大而泛的模型。mllib没有提供一个类似于Manager的类来管理多个模型。所以笔者对mllib进行了二次封装,能够让大家比较方便的通过配置来管理多个模型,也让大家从需要了解mlllib最底层的接口中解放出来。
封装的Manager类:
class MlrManager { public: MlrManager(); virtual ~MlrManager(); //提供的两个接口 //初始化函数,输入为配置文件,以配置文件为驱动来加载模型 bool Init(const char* pConf); //预测函数,输入为特征数组和模型编号,输出为预测分数 feature_t CalMlrScore(std::vector<feature_t>& vecFeatures,int nModel); private: feature_t GetMlrScore(std::vector<feature_t>& vecFeatures,mllib::MlModel* pModel,ENUM_MODEL_TYPE enumModelType);
…
几个随机算法
2010-12-22 16:16 天铎 Comments (21)
在日常工作中,经常需要使用随机算法。比如面对大量的数据, 需要从其中随机选取一些数据来做分析。 又如在得到某个分数后, 为了增加随机性, 需要在该分数的基础上, 添加一个扰动, 并使该扰动服从特定的概率分布。本文主要从这两个方面出发, 介绍一些算法, 供大家参考。
首先假设我们有一个使用的随机函数float frand(), 返回值在(0, 1)上均匀分布。大多数的程序语言库提供这样的函数。 在其他的语言如C/C++中, 可以通过间接方法得到。如 frand()= ((float)rand() ) / RAND_MAX;
1, 随机选取数据
假设我们有一个集合A(a_1,…,a_n), 对于数m,0≤m≤n, 如何从集合A中等概率地选取m个元素呢?
通过计算古典概率公式可以得到, 每个元素被选取的概率为m/n。 如果集合A里面的元素本来就具有随机性, 每个元素在各个位置上出现的概率相等, 并且只在A上选取一次数据,那么直接返回A的前面m个元素就可以了, 或者可以采取每隔k个元素取一个等类似的方法。这样的算法局限很大, 对集合A的要求很高, 因此下面介绍两种其他的算法。
1.1 假设集合A中的元素在各个位置上不具有随机性,…
Treelink算法介绍
2010-12-21 18:18 元涵 Comments (6)
“机器学习”这个名词对大家来说想必不是一个陌生的词汇,特别对算法组的同学来说,工作中或多或少接触使用过这种“高科技“。对于我来说,刚来淘宝工作一个月就开始接触了机器学习,当时做主搜索功夫熊猫项目,和小致飘雪一起做交易模型,正是使用了机器学习的方法,也首次接触了treelink模型。做完那个项目后对机器学习解决问题的流程有了一定的了解,但对其内部的工作原理和实现机制还是完全不知道,基本也就是在黑盒使用机器学习工具。后面也多多少少听了一些机器学习的讲座,但都是一些比较宽泛的基本概念,没有深入的原理性的介绍。也自己尝试过专研一下,但生硬晦涩的E文让人望而生畏。一直到今年做导购搜索的项目,又再次需要使用机器学习,“怀揣着对科学真理的向往”,主动请缨做模型方面的工作。经过一个多月的学习实践,算是对treelink模型有了一定的了解。下面做一些对treelink模型通俗版的介绍。都是自己的一些理解,如果有误,多指教。
在介绍treelink之前首先不得不简单介绍一下决策树算法,决策树相信大家都有所了解,任何一本机器学习书籍都会介绍这种算法,也是应用最广的归纳推理算法之一。该模型学习的结果是一棵决策树,这棵决策树可以被表示成多个if-else的规则。下图是一个典型的学习得到决策树。这棵决策树根据两个特征因素来分类“元涵今天的心情好坏”。长方形的表示特征,椭圆型的表示特征的取值,最下面的叶子节点就是最后的分类结果了。
学习得到如上这棵决策树之后,当输入一个待预测的样本实例的时候,我们就可以根据这个样本的两个特征的取值来把这个样本划分到某一个叶子节点,得到分类结果了,这就是决策树模型的预测过程,决策树的学习构建过程这里就不介绍了,大家看书吧,比较经典的有ID3算法和C4.5算法。
切入正题下面开始说treelink算法,treelink这个名字其实只是我们阿里集团内部的叫法,学术上的名称叫GBDT(Gradient boost decision tree)。treelink模型不像决策树模型那样仅由一棵决策树构成,而是由多棵决策树构成,通常都是上百棵树,而且每棵树规模都较小(即树的深度会比较浅)。模型预测的时候,对于输入的一个样本实例,首先会赋予一个初值,然后会遍历每一棵决策树,每棵树都会对预测值进行调整修正,最后得到预测的结果。
F0是设置的初值, Ti是一棵一棵的决策树。对于不同的问题(回归问题或者分类问题)和选择不同的损失函数,初值的设定是不同的。比如回归问题并且选择高斯损失函数,那么这个初值就是训练样本的目标的均值。
下面是一个简单的treelink模型示意图。模型的目标是上海一套普通商品房的价格,特征有三个:房子的面积(连续特征),是否在内环(分类特征),是否学区房(分类特征)。模型由四棵决策树构成,每棵决策树只进行了一次分裂,即树的深度为一(这种树被称为Decision Stump)。实际应用中通常较复杂,深度不会为一。
初值设定为上海普通商品房价格的均值150万,每经过一棵决策树,都会对根据相应特征的取值对预测价格进行调整。比如一个面积为120平的内环非学区房的价格预测值为:150+20-10+30-10=180万。
那为什么要用多棵决策树,一棵决策树为什么不好呢?使用单棵决策树,最大的问题就是会因为过度分裂,而造成过拟合,失去泛化能力。试想一下,对于给定的一批训练数据,完全可以只构造一棵树,不断分裂下去,直到每个叶子节点包含的样本的目标值都一样,然后把这节点的预测值设定成这个目标值,这样构造出来的这棵树就可以在这批训练数据上达到100%的准确性。但这样一棵过度分裂的决策树,对于新的样本基本没有什么预测能力。而如果分裂太少,又会造成学习不够充分。Treelink使用多棵决策树正是希望能够在训练精度和泛化能力两个方面都能达到较好的效果。作为一种boosting算法,Treelink自然包含了boosting的思想:将一系列弱分类器组合起来,构成一个强分类器。它不要求每棵树学到太多的东西,每颗树都学一点点知识,然后将这些学到的知识累加起来构成一个强大的模型。举个现实生活中的例子,电视里的那种益智类节目,如开心词典,答题者有三次请求帮组的机会,其中一个就是请求现场所有观众,通过他们的选择来给出答案。我们可以把每个观众当做一个弱的分类器,他们各个单独的准确率都不高,但把他们的知识综合起来这个准确率会大大提升。也许上面这个例子不太能说服你,我们来把这个例子量化。假如我们有三个观众,他们各自的准确率为60%(非常弱的分类器,只比随机分类器好一点点),如果这三位观众中有大于等于两位的答案是正确的,那么则认为我们正确了,反之则错误。那么我们正确的概率是多少呢?preciseness = p(三个人都正确) + p(三个人中有两个人正确) = 0.6*0.6*0.6 +…
如何在Hadoop集群运行JNI程序
2010-12-13 7:07 家逸 Comments (14)
hadoop是基于java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力。 阿里巴巴内部使用的分词软件(用c++实现的,以下简称WS包)是日常工作中最基本的软件包,通过java的jni机制,笔者将WS包成功的运行在hadoop上,深受很多部门的欢迎。下面借这个例子介绍hadoop上jni程序的开发过程。
首先,简单介绍一下WS包中的调用接口和基本结构。 WS包包括词典文件A.dict,对外提供静态链接库文件libWS.a。WS.h如下:
Class WS{ int init(const char* name); int segment(char* dest, char* src, int len,int kind); }
我们的方案是首先生成jni的原型定义,然后根据原型定义,来包装WS类的接口,最后生成可在tasknode上运行的jni程序包。结构如下图所示
第一步,我们先使用java的jni技术,生成C的原型接口(prototype),然后编写Wsjni.java 文件,这是为云梯程序提供的类文件,其中libwsjni.so 就是wrapper类的动态链接库:
Class Wsjni{ Public Native int init(String conf); Public Native String segment(String src,int kind); Public Native void close(); //用于显示的释放内存 Static{
…