hadoop学习【8】——基于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、项目结构图:

    hadoop学习【8】——基于hadoop的分词程序二(ICTCLAS分词器)_第1张图片

    2.4、测试程序

    package test;
    import org.ictclas4j.bean.SegResult;
    import org.ictclas4j.segment.SegTag;
    /**
     * @author jonsen_hb
     */
    public class Test {
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		Long start = System.currentTimeMillis();//时间测试开始
    		
    		String src_line = "这个世界复杂,其实只是人心复杂;生活,慢慢地走,慢慢地过,在不经意间就串起了流年。总有些追逐会化成云烟,总有些故事会写成诗篇,总有些话语会留下悸动,总有些记忆会美在心间。";
    		SegTag segTag = new SegTag(1);// 分词路径的数目,
    		SegResult segResult = segTag.split(src_line.trim());//进行分词
    		String classifyContent = segResult.getFinalResult();
    		
    		Long end = System.currentTimeMillis();
    		System.out.println("分词时间花费:"+(end-start));
    		System.out.println(classifyContent);
    
    	}
    }

    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里面就可以了。

    程序如下:

    package test;
    
    import ICTCLAS.I3S.AC.ICTCLAS50;
    
    public class Test {
    	public static void main(String[] args) {
    		try {
    			long start = System.currentTimeMillis();
    			ICTCLAS50 testICTCLAS50 = new ICTCLAS50();
    			// 分词所需库(即Data文件夹)的路径
    			String argu = ".";
    			// 初始化
    			if (testICTCLAS50.ICTCLAS_Init(argu.getBytes("GB2312")) == false) {
    				System.out.println("Init Fail!");
    				return;
    			} else {
    				System.out.println("Init Succeed!");
    			}
    			String sInput = "这个世界复杂,其实只是人心复杂;生活,慢慢地走,慢慢地过,在不经意间就串起了流年。总有些追逐会化成云烟,总有些故事会写成诗篇,总有些话语会留下悸动,总有些记忆会美在心间。";
    			byte nativeBytes[] = testICTCLAS50.ICTCLAS_ParagraphProcess(
    					sInput.getBytes("GB2312"), 0, 0);
    			// System.out.println(nativeBytes.length);
    			String nativeStr = new String(nativeBytes, 0, nativeBytes.length,
    					"GB2312");
    			// System.out.println("The result is :" + nativeStr);
    			String[] rest = nativeStr.split("\\s+");
    			StringBuilder sb = new StringBuilder("");
    			for (int i = 0; i < rest.length; i++)
    				sb.append(rest[i]+" ");
    			System.out.println(sb.toString());
    			Long end = System.currentTimeMillis();
    			System.out.println("all time:" + (end-start));
    			testICTCLAS50.ICTCLAS_Exit();
    		} catch (Exception e) {
    		}
    	}
    }
    

    测试时间如下截图:

    hadoop学习【8】——基于hadoop的分词程序二(ICTCLAS分词器)_第2张图片

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

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

    4.1、开发环境

    hadoop1.1.2(伪分布式

    linux:centos 5.3  32位

    开发工具:eclipse

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

    4.3、程序:

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

    package test;
    
    import java.io.IOException;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.conf.Configured;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.Mapper;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    import org.apache.hadoop.util.Tool;
    import org.apache.hadoop.util.ToolRunner;
    
    import ICTCLAS.I3S.AC.ICTCLAS50;
    
    public class TestICTCLAS extends Configured implements Tool {
    
    	public static class Map extends Mapper<LongWritable, Text, Text, Text> {
    		public static void main(String[] args) throws Exception {
    			int res = ToolRunner.run(new Configuration(), new TestICTCLAS(),
    					args);
    			System.exit(res);
    		}
    		enum Counter {
    			LINESKIP,
    		}
    		public void map(LongWritable key, Text value, Context context)
    				throws IOException, InterruptedException {
    			String line = value.toString();
    			try {
    				String[] lineSplit = line.split("[\\s]+");
    				String anum = lineSplit[0];
    				String bnum = lineSplit[1];
    				ICTCLAS50 testICTCLAS50 = new ICTCLAS50();
    				// 分词所需库(即Data文件夹)的路径
    				String argu = ".";
    				// 初始化
    				if (testICTCLAS50.ICTCLAS_Init(argu.getBytes("GB2312")) == false) {
    					System.out.println("Init Fail!");
    					return;
    				} else {
    					System.out.println("Init Succeed!");
    				}
    				StringBuilder sb = new StringBuilder();
    				String resultString = "";
    				byte nativeBytes[] = testICTCLAS50.ICTCLAS_ParagraphProcess(
    						bnum.getBytes("GB2312"), 0, 0);
    				// System.out.println(nativeBytes.length);
    				String nativeStr = new String(nativeBytes, 0,
    						nativeBytes.length, "GB2312");
    				// System.out.println("The result is :" + nativeStr);
    				String[] rest = nativeStr.split("\\s+");
    				for (int i = 0; i < rest.length; i++)
    					sb.append(rest[i] + " ");
    				FileExcludeStopWord fileExcludeStopWord = new FileExcludeStopWord();
    				resultString = fileExcludeStopWord.fileExcludeStopWord(sb
    						.toString());
    				context.write(new Text(anum), new Text(resultString));
    			} catch (java.lang.ArrayIndexOutOfBoundsException e) {
    				context.getCounter(Counter.LINESKIP).increment(1);
    				return;
    			}
    		}
    	}
    	public int run(String[] args) throws Exception {
    		Configuration conf = getConf();
    		Job job = new Job(conf, "TestICTCLAS");
    		job.setJarByClass(TestICTCLAS.class);
    		FileInputFormat.addInputPath(job, new Path(args[0]));
    		FileOutputFormat.setOutputPath(job, new Path(args[1]));
    		job.setMapperClass(Map.class);
    		job.setOutputFormatClass(org.apache.hadoop.mapreduce.lib.output.TextOutputFormat.class);
    		job.setOutputKeyClass(Text.class);
    		job.setOutputValueClass(Text.class);
    		job.waitForCompletion(true);
    		System.out.println("job's name"+job.getJobName());
    		System.out.println("job status"+(job.isSuccessful()?"yes":"no"));
    		return job.isSuccessful()?0:1;
    	}
    
    }

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

    hadoop学习【8】——基于hadoop的分词程序二(ICTCLAS分词器)_第3张图片


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



    4.6、测试结果:

    hadoop学习【8】——基于hadoop的分词程序二(ICTCLAS分词器)_第4张图片

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

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

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

    六、总结:

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

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

    你可能感兴趣的:(数据挖掘,分布式,分词,HADOOP集群,hadoop中文分词)