一、使用的分词包——庖丁分词器介绍
1.1、简介:
庖丁系统是个完全基于lucene的中文分词系统,它就是重新建了一个analyzer,叫做PaodingAnalyzer,这个analyer的核心任务就是生成一个可以切词TokenStream。
1.2、优点:
这里之所以使用庖丁主要考虑到庖丁的分词效率比其他的分词器要高,
1.3、缺点:
其分词有一个缺点:
例如下面一段文字:
“发展社区老年活动场所和服务设施”
如果想搜索日本的和服相关资料,输入关键字“和服”的时候,上面的资料也会被搜索出来
搜索引擎是第一步搜索:
在浩瀚的信息中,快速集结最后可能是所想要的结果, 按照可能是最好的顺序展现出来。
人的眼睛是第二步搜索:
找寻最符合要求的结果,同时将机器无法轻易识别的少数“无效”结果过滤
“和服”问题,涉及了汉语语义的问题,几乎不可完全解决(可作为“特例”解决,或通过排序方法,将他排到相对靠后等价解决)。
但是这同时也是庖丁分词的一个有点,因为对于一般的分词而言要确定出到底是怎样的一种组合也只是选择概率较大的,将可能的组合全部给出给了我们选择的机会。
——摘自百度百科
这里我把我用的版本和词典文件共享到网盘欢迎下载:http://pan.baidu.com/s/1eQekI9k
二、分词程序单机测试:
2.1、导入相应的分词包、词典
需要的包:
字典:将整个dic文件拷贝到src目录下
2.2、java分词程序:(注意:这里并没有去除噪音和停用词,只是简单的测试庖丁分词的可用性)
- public class TestPaoding {
- public static void main(String[] args) {
- String line = "亚洲:中华人民共和国";
- PaodingAnalyzer analyzer = new PaodingAnalyzer();
- StringReader sr = new StringReader(line);
- TokenStream ts = analyzer.tokenStream("", sr);
- try{
- while(ts.incrementToken()){
- CharTermAttribute ta = ts.getAttribute(CharTermAttribute.class);
- System.out.println(ta.toString());
- }
- }catch(Exception e){
-
- }
- }
- }
2.3、单机程序测试结果:
三、单机程序mapreduce化:
3.1、开发环境:
伪分布式系统
hadoop1.1.2平台
开发环境eclipse
需要的包跟上面写的一样,这里就不赘余了
3.2、mapreduce程序:
mapreduce计算框架浅析:
这里因为只是进行简单的分词,没有必要多个mapper,也不需要reducer。
这里的inputformat没有加控制,如果文件很多时,就一定要对inputformat进行控制,控制分片的大小,这样才能保证mapreduce的计算效率最高
- package test;
-
- import java.io.IOException;
- import java.io.StringReader;
-
- import net.paoding.analysis.analyzer.PaodingAnalyzer;
-
- 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 org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
-
- public class TestTOkenizer 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 TestTOkenizer(), 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];
-
- PaodingAnalyzer analyzer = new PaodingAnalyzer();
-
- StringReader sr = new StringReader(bnum);
-
- StringBuilder sb = new StringBuilder();
-
- String resultString="";
-
- org.apache.lucene.analysis.TokenStream ts = analyzer.tokenStream("", sr);
- try{
- while(ts.incrementToken()){
- CharTermAttribute ta = ts.getAttribute(CharTermAttribute.class);
- sb.append(ta.toString()+" ");
- }
-
- FileExcludeStopWord fileExcludeStopWord = new FileExcludeStopWord();
-
- resultString = fileExcludeStopWord.fileExcludeStopWord(sb.toString());
- }catch(Exception e){
-
- }
-
- 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, "TestTOkenizer");
- job.setJarByClass(TestTOkenizer.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;
- }
- }
3.3、去停用词类(这个类写的还不是很完美,停用词表也还不够完善,微博数据中,有一些没包含在停用词表中)
- package test;
- import java.io.BufferedReader;
- import java.io.FileInputStream;
- import java.io.InputStreamReader;
- import java.util.HashSet;
- import java.util.Set;
-
- public class FileExcludeStopWord {
- public static final String stopWordFile = "/home/jonsen/workspace/testPaoding/src/test/stopword.txt";
- public String fileExcludeStopWord(String splitResultStr) {
- try {
- BufferedReader stopWordFileBR = new BufferedReader(
- new InputStreamReader(new FileInputStream(stopWordFile)));
-
- Set<String> stopWordSet = new HashSet<String>();
-
- String stopWord = null;
- while ((stopWord = stopWordFileBR.readLine()) != null) {
- stopWordSet.add(stopWord);
- }
- if(stopWordFileBR!=null){
- stopWordFileBR.close();
- }
-
- String[] resultArray = splitResultStr.split("[\\s]+");
-
- for (int i = 0; i < resultArray.length; i++) {
- if (stopWordSet.contains(resultArray[i])) {
- resultArray[i] = null;
- }
- }
-
- StringBuilder finalStr = new StringBuilder();
- for (int j = 0; j < resultArray.length; j++) {
- if (resultArray[j] != null) {
- finalStr = finalStr.append(resultArray[j]).append(" ");
- }
- }
- return finalStr.toString();
-
- } catch (Exception e) {
- e.printStackTrace();
- return "";
- }
- }
- }
3.4、上传文件到hdfs中:(直接右键上传文件即可)
文本文件内容:
3.5、配置输入输出路径运行程序:
注意:如果输出路径已经存在,一定要预先删除,否则会报错:
3.6、分词结果:
四、总结
到这里整个基于分布式的分词程序就完成了,但是只能处理文件数量不多的文本,大文件处理是没有问题的,如果都是单个的小文件,就需要自定义inputformat了,自己控制分片大小,才能提高效率!从分词的结果来看,很显然很多停用词是没有去掉的,很多没有意义的词语,噪音较大,还有一个问题就是庖丁的分词器,给出的所有可能的组合,这个虽好但是还需要花精力去分辨哪些是无用的,一般情况下,最长的是可能的组合的可能性比较大!