基于hadoop的分词程序(ICTCLAS分词器)

0、【前言今天下午坑了我一下午,总算在Hadoop上把ICTCLAS分词器跑起来了,其实不是mapreduce化困难,而是一个很小的问题,我是很早就完过ICTCLAS分词器的,因为现在需要分词的内容太多,所以才想这把Java程序mapreduce化的,但是这就意味着要在Linux下的eclipse跑ICTCLAS分词系统,我一直没发现在windows下和linux下用的包不一样,就这样坑了我一下午,一直报一个纠结的错误空指针异常,看了良久源代码也没解决,最终百度了一下,还不少人跟我犯过同样的错误,不过最终百经周折算是解决了,分词速度还可以,等会会跟庖丁的分词作下比较的。


一、ICTCLAS分词器简介

  • 全球最受欢迎的汉语分词开源系统
  • 获得首届国际分词大赛综合排名第一,国家973评测第一名
  • 人名识别、地名识别、组织机构名识别
  • 支持行业词典、用户自定义词典
  • 多级词性标注
  • 关键词提取、指纹提取

                                     ——摘自官方的介绍

二、windows下开发基于ICTCLAS分词器的分词程序

2.1、环境准备

        eclipse开发环境

        相关的包:

         ICTCLAS:http://pan.baidu.com/s/1mg2vbny

         commons.lang2.4:http://pan.baidu.com/s/1tlWWu

2.2、开发java项目

          首先把ICTCLAS解压,然后把Data文件夹整个拷贝到eclipse项目的文件夹下,而bin目录下的org文件整个拷贝到你eclipse项目的src目录下。

2.3、项目结构图:


2.4、测试程序

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package test;  
  2. import org.ictclas4j.bean.SegResult;  
  3. import org.ictclas4j.segment.SegTag;  
  4. /** 
  5.  * @author jonsen_hb 
  6.  */  
  7. public class Test {  
  8.     /** 
  9.      * @param args 
  10.      */  
  11.     public static void main(String[] args) {  
  12.         Long start = System.currentTimeMillis();//时间测试开始  
  13.           
  14.         String src_line = "这个世界复杂,其实只是人心复杂;生活,慢慢地走,慢慢地过,在不经意间就串起了流年。总有些追逐会化成云烟,总有些故事会写成诗篇,总有些话语会留下悸动,总有些记忆会美在心间。";  
  15.         SegTag segTag = new SegTag(1);// 分词路径的数目,  
  16.         SegResult segResult = segTag.split(src_line.trim());//进行分词  
  17.         String classifyContent = segResult.getFinalResult();  
  18.           
  19.         Long end = System.currentTimeMillis();  
  20.         System.out.println("分词时间花费:"+(end-start));  
  21.         System.out.println(classifyContent);  
  22.   
  23.     }  
  24. }  

2.5、结果:(注意这里句子太长,图没有截取完)


三、linux下开发基于ICTCLAS分词器的分词程序

3.1、直接把windows下用的一套东西照搬到linux下的痛苦:(就一直报这个错)

3.2、在官网下下载linux 32版后就没问题了

相关包下载:http://www.ictclas.org/ictclas_download.aspx

3.3、linux下的eclipse中开发基于ICTCLAS分词器的分词程序

首先下载ICTCLAS2011_Linux_32_jni ,解压后是ICTCLAS50_Linux_RHAS_32_JNI文件夹。

在Eclipse里面新建一个Java Project,把ICTCLAS50_Linux_RHAS_32_JNI/API下的ICTCLAS放到Java Project的src目录下,把ICTCLAS50_Linux_RHAS_32_JNI/API下的其他所有内容放到Java Project的根目录下,新建一下java class,取名Test。在ICTCLAS50_Linux_RHAS_32_JNI/Doc下有个ICTCLAS50的API使用说明,第22页是第一个JNI示例程序,把该程序的见容拷贝到我们的Test.java里面就可以了。

程序如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package test;  
  2.   
  3. import ICTCLAS.I3S.AC.ICTCLAS50;  
  4.   
  5. public class Test {  
  6.     public static void main(String[] args) {  
  7.         try {  
  8.             long start = System.currentTimeMillis();  
  9.             ICTCLAS50 testICTCLAS50 = new ICTCLAS50();  
  10.             // 分词所需库(即Data文件夹)的路径  
  11.             String argu = ".";  
  12.             // 初始化  
  13.             if (testICTCLAS50.ICTCLAS_Init(argu.getBytes("GB2312")) == false) {  
  14.                 System.out.println("Init Fail!");  
  15.                 return;  
  16.             } else {  
  17.                 System.out.println("Init Succeed!");  
  18.             }  
  19.             String sInput = "这个世界复杂,其实只是人心复杂;生活,慢慢地走,慢慢地过,在不经意间就串起了流年。总有些追逐会化成云烟,总有些故事会写成诗篇,总有些话语会留下悸动,总有些记忆会美在心间。";  
  20.             byte nativeBytes[] = testICTCLAS50.ICTCLAS_ParagraphProcess(  
  21.                     sInput.getBytes("GB2312"), 00);  
  22.             // System.out.println(nativeBytes.length);  
  23.             String nativeStr = new String(nativeBytes, 0, nativeBytes.length,  
  24.                     "GB2312");  
  25.             // System.out.println("The result is :" + nativeStr);  
  26.             String[] rest = nativeStr.split("\\s+");  
  27.             StringBuilder sb = new StringBuilder("");  
  28.             for (int i = 0; i < rest.length; i++)  
  29.                 sb.append(rest[i]+" ");  
  30.             System.out.println(sb.toString());  
  31.             Long end = System.currentTimeMillis();  
  32.             System.out.println("all time:" + (end-start));  
  33.             testICTCLAS50.ICTCLAS_Exit();  
  34.         } catch (Exception e) {  
  35.         }  
  36.     }  
  37. }  

测试时间如下截图:

对比来看,windows下跑一句的时间已经远远甩出了在linux下跑的时间了!!!

四、hadoop平台下开发基于ICTCLAS分词器的mapreduce分词程序

4.1、开发环境

hadoop1.1.2(伪分布式

linux:centos 5.3  32位

开发工具:eclipse

4.2、所需要的包,上面已经提到了,或者参考官网给的说明

4.3、程序:

主要程序,其中调用的一个类见我的上一篇文章中,给出了源代码了已经。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package test;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.hadoop.conf.Configuration;  
  6. import org.apache.hadoop.conf.Configured;  
  7. import org.apache.hadoop.fs.Path;  
  8. import org.apache.hadoop.io.LongWritable;  
  9. import org.apache.hadoop.io.Text;  
  10. import org.apache.hadoop.mapreduce.Job;  
  11. import org.apache.hadoop.mapreduce.Mapper;  
  12. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  13. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  14. import org.apache.hadoop.util.Tool;  
  15. import org.apache.hadoop.util.ToolRunner;  
  16.   
  17. import ICTCLAS.I3S.AC.ICTCLAS50;  
  18.   
  19. public class TestICTCLAS extends Configured implements Tool {  
  20.   
  21.     public static class Map extends Mapper<LongWritable, Text, Text, Text> {  
  22.         public static void main(String[] args) throws Exception {  
  23.             int res = ToolRunner.run(new Configuration(), new TestICTCLAS(),  
  24.                     args);  
  25.             System.exit(res);  
  26.         }  
  27.         enum Counter {  
  28.             LINESKIP,  
  29.         }  
  30.         public void map(LongWritable key, Text value, Context context)  
  31.                 throws IOException, InterruptedException {  
  32.             String line = value.toString();  
  33.             try {  
  34.                 String[] lineSplit = line.split("[\\s]+");  
  35.                 String anum = lineSplit[0];  
  36.                 String bnum = lineSplit[1];  
  37.                 ICTCLAS50 testICTCLAS50 = new ICTCLAS50();  
  38.                 // 分词所需库(即Data文件夹)的路径  
  39.                 String argu = ".";  
  40.                 // 初始化  
  41.                 if (testICTCLAS50.ICTCLAS_Init(argu.getBytes("GB2312")) == false) {  
  42.                     System.out.println("Init Fail!");  
  43.                     return;  
  44.                 } else {  
  45.                     System.out.println("Init Succeed!");  
  46.                 }  
  47.                 StringBuilder sb = new StringBuilder();  
  48.                 String resultString = "";  
  49.                 byte nativeBytes[] = testICTCLAS50.ICTCLAS_ParagraphProcess(  
  50.                         bnum.getBytes("GB2312"), 00);  
  51.                 // System.out.println(nativeBytes.length);  
  52.                 String nativeStr = new String(nativeBytes, 0,  
  53.                         nativeBytes.length, "GB2312");  
  54.                 // System.out.println("The result is :" + nativeStr);  
  55.                 String[] rest = nativeStr.split("\\s+");  
  56.                 for (int i = 0; i < rest.length; i++)  
  57.                     sb.append(rest[i] + " ");  
  58.                 FileExcludeStopWord fileExcludeStopWord = new FileExcludeStopWord();  
  59.                 resultString = fileExcludeStopWord.fileExcludeStopWord(sb  
  60.                         .toString());  
  61.                 context.write(new Text(anum), new Text(resultString));  
  62.             } catch (java.lang.ArrayIndexOutOfBoundsException e) {  
  63.                 context.getCounter(Counter.LINESKIP).increment(1);  
  64.                 return;  
  65.             }  
  66.         }  
  67.     }  
  68.     public int run(String[] args) throws Exception {  
  69.         Configuration conf = getConf();  
  70.         Job job = new Job(conf, "TestICTCLAS");  
  71.         job.setJarByClass(TestICTCLAS.class);  
  72.         FileInputFormat.addInputPath(job, new Path(args[0]));  
  73.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  
  74.         job.setMapperClass(Map.class);  
  75.         job.setOutputFormatClass(org.apache.hadoop.mapreduce.lib.output.TextOutputFormat.class);  
  76.         job.setOutputKeyClass(Text.class);  
  77.         job.setOutputValueClass(Text.class);  
  78.         job.waitForCompletion(true);  
  79.         System.out.println("job's name"+job.getJobName());  
  80.         System.out.println("job status"+(job.isSuccessful()?"yes":"no"));  
  81.         return job.isSuccessful()?0:1;  
  82.     }  
  83.   
  84. }  

4.4、上传数据:这里跑了10条数据



4.5、分词结果:(已去除部分停用词,这里的停用词表不是太好,有待改进)



4.6、测试结果:

4.7、对比来看,hadoop对于小文件其实是没有什么优势的,但对于大文件(上TB/PB级别)来说就是优势明显了!

五、和庖丁分词器简单对比:

庖丁在hadoop上跑的速度比ICTCLAS略好一点点!!!

六、总结:

5.1、从性能上来看,其实ICTCLAS的效率还是不错的,在windows上可能是我用的不是官网的包,感觉慢好多,在linux下的确是速度很快,应该在庖丁之上。如果用hadoop分布式平台来跑这两个分词程序的话还不好说,毕竟没有真正的测试过,后面测试了再写。

5.2、庖丁的分词器缺点明显,给出的各种可能的词好是好,但是增加了程序员的负担。而且问题是,人也除了手工分出来,准确率高一些外,用写程序的方式分其实准确率还是不高的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值