博客年龄:17年6个月
访问:?
文章:291篇

个人描述

姓名:丹臣 职业:DBA 公司:TAOBAO Mail:zhaolinjnu(at)163.com MSN:echo_lin@hotmail.com 微博http://twitter.com/zhaolinjnu

在Hadoop上使用庖丁解牛

2013-05-23 13:51 阅读(?)评论(0)
背景
在淘宝,卖家发布商品,或者淘宝会员发布二手,都有一个重要的操作,选择商品所在的类目。例如如下的发布二手页面示例:

对于不太熟悉淘宝的会员,选择这个类目肯定会有点头痛,我在想,在基于淘宝海量商品数据的情况,能否根据用户输入的商品标题,自动定位到此商品可能存在的类目。

技术准备
Hadoop 计算淘宝的商品标题数据
庖丁解牛 对标题进行分词
在hadoop上使用庖丁解牛,用google搜索,发现很多人都在问这个问题,没有找到一篇比较全面解决此问题的文章,所以这也是我写此篇文章的目的。

目标可行性验证
为了快速验证目标可行性,我先采用单字拆分的方式,没有使用庖丁解牛,将淘宝所有在线商品的标题进行了分析,形成了一个库。并随机用淘宝上一些商品标题进行了测试,发现根据商品标题预测类目是可行的。

Hadoop上使用庖丁解牛
下载庖丁解牛源码包,里面也包括字典库
# Non-members may check out a read-only working copy anonymously over HTTP.
svn checkout http://paoding.googlecode.com/svn/trunk/ paoding-read-only
庖丁解牛有一个字典库dic,这是一个目录,里面有很多的文件,这个字典库如何在hadoop环境上使用,是一个问题.

hadoop有一个东西,叫DistributedCache,可以把一些配置数据分发到真正执行map reduce的机器上.对于DistributedCache,可以参见文章:

自己写的map or reduce的程序中的
public void configure(JobConf conf) {
     //就可以读取DistributedCache中的数据
}

具体步骤:
1. 将字典目录打包成dic.zip or dic.tar都可以,上传到hdfs上
2. 在map reduce java program中的main函数中添加如下的代码:
    DistributedCache.addCacheArchive(new URI("/group/test/danchen/hive/category/dic.tar"), conf);
   注:添加CacheArchive方式,分发到执行任务的机器上时,hadoop执行框架会帮你自动解压成一个文件目录
3. 在map类的configure(JobConf conf)中通过如下的方法来读取:
              
Path[] localArchives;
Path real_hadoop_dic_home=null;
try {
localArchives = DistributedCache.getLocalCacheArchives(conf);
for(int i=0;i<localArchives.length;i++){
String fileName = localArchives[i].toUri().toString();
if(fileName.indexOf("dic.tar")>-1){
real_hadoop_dic_home = localArchives[i];
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
           我刚开始以为这样可以获取到字典的真正目录了,实际上没有,后来打印了dic.tar所在目录下的所有目录和文件后,才发现hadoop解压后的真正目录是:
  String hadoop_dic_home = real_hadoop_dic_home.toUri().toString()+"/"+"dic";
  把hadoop_dic_home打印出来是这样的(这个目录格式,网上没有找到相应的文章介绍):                /disk4/mapred/local/taskTracker/archive/-1294301082447095161/hdpnn/group/test/danchen/h
ive/category/dic.tar/dic

hadoop上dic目录的问题解决了,但接下来,如何把这个真实的目录传给庖丁解牛,需要修改一点配置与代码。
打开配置文件
paoding\paoding-analysis\src\paoding-dic-home.properties
写入paoding.dic.home=/tmp/dic   这个配置项是虚假的,这个路径是不对的,如果不配置,庖丁解牛会去读环境变量。

修改源代码:
paoding-analysis\src\net\paoding\analysis\knife\PaodingMaker.java
增加一个定义:
public static String hadoop_dic_home = "";

修改一个函数private static void setDicHomeProperties(Properties p):
        // 规范化dicHome,并设置到属性文件对象中
dicHome = hadoop_dic_home;
dicHome = dicHome.replace('\\', '/');
if (!dicHome.endsWith("/")) {
dicHome = dicHome + "/";
}
p.setProperty(Constants.DIC_HOME, dicHome);// writer to the properites

退出到paoding-analysis目录下,执行build.bat重新打包,将会生成新的paoding-analysis.jar包

将这个修改后的paoding-analysis.jar,以及lucene-core-3.6.2.jar 打包到自己的项目jar里就可以了。
初始化庖丁解牛字典的代码,hadoop_dic_home即上面动态获取的路径:
PaodingMaker.hadoop_dic_home = hadoop_dic_home;
analyzer =  new PaodingAnalyzer(); 

过程有点折腾,不知道有没有更好的方法没?

效果
原来分词是单字的,在使用庖丁解牛后,现在既有单字,也有一些词。看了一下跑出来的结果数据,比原来好。后面也可以不断往这个词库里,添加新的词,维护方便一些。
  最后修改于 2013-05-23 15:02    阅读(?)评论(0)
 
表  情:
加载中...
 

请各位遵纪守法并注意语言文明