使用Ansj分词器+Pig来统计中文的词频

使用Ansj分词器+Pig来统计中文的词频,Pig的TOKENIZE只支持对英文句子的切分,为什么呢?因为英文的句子非常工整,都是以空格作为分割符的,而相当于中文来说,则不一样,中文的切分,需要有词库支持,才能分割出一个个词汇,或者比较暴力一点的,直接根据算法进行Ngram,也不需要词库支持,但这样切分出来的词汇,可能大部分时候都不太友好,意义也不太大,目前比较不错的开源的分词器有ansj,ik,meseg4j等,随便选一款就行,散仙在这里用的ansj的分词器,有对ansj感兴趣的朋友,可以参考此处


分词器选好了,分词功能也实现了,下一步就该考虑如何把这个功能与Pig集成起来,其实答案也很明显,仿照Pig官方TOKENIZE
源码,再写一个基于中文分词功能的UDF,就可以了,对Pig源码感兴趣的朋友可以参考这个链接,以Web的形式展示的源码,非常清晰直观。


关于如何在Pig中自定义UDF函数,可以参考散仙的这一篇文章:
http://qindongliang.iteye.com/blog/2171303


下面给出,散仙扩展的基于中文分词的UDF类:

package com.pigudf;  
  
import java.io.IOException;  
import java.util.List;  
  
import org.ansj.domain.Term;  
import org.ansj.splitWord.analysis.ToAnalysis;  
import org.apache.pig.EvalFunc;  
import org.apache.pig.backend.executionengine.ExecException;  
import org.apache.pig.data.BagFactory;  
import org.apache.pig.data.DataBag;  
import org.apache.pig.data.DataType;  
import org.apache.pig.data.Tuple;  
import org.apache.pig.data.TupleFactory;  
import org.apache.pig.impl.logicalLayer.schema.Schema;  
  
/** 
 * 自定义UDF,实现Pig与中文分词集成 
 * **/  
public class MyTokenize extends EvalFunc<DataBag> {  
    /**tuple实例**/  
     TupleFactory mTupleFactory = TupleFactory.getInstance();  
     /**Bag实例*/  
     BagFactory mBagFactory = BagFactory.getInstance();  
      
    @Override  
    public DataBag exec(Tuple input) throws IOException {  
          
           try {  
                DataBag output = mBagFactory.newDefaultBag();  
                Object o = input.get(0);  
                List<Term> terms=ToAnalysis.parse((String)o);//获取Ansj的分词  
                for(Term t:terms){  
                    output.add(mTupleFactory.newTuple(t.getName()));//获取分词token,放入tuple,然后以bag的形式组装tuple  
                }  
                return output;  
            } catch (ExecException ee) {  
                // error handling goes here  
                ee.printStackTrace();  
            }  
        return null;  
    }  
      
     /**描述scheaml形式*/  
      public Schema outputSchema(Schema input) {  
             try{  
                 Schema bagSchema = new Schema();  
                 bagSchema.add(new Schema.FieldSchema("token", DataType.CHARARRAY));  
  
                 return new Schema(new Schema.FieldSchema(getSchemaName(this.getClass().getName().toLowerCase(), input),  
                                                        bagSchema, DataType.BAG));  
             }catch (Exception e){  
                return null;  
             }  
        }  
    }  
package com.pigudf;

import java.io.IOException;
import java.util.List;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.apache.pig.EvalFunc;
import org.apache.pig.backend.executionengine.ExecException;
import org.apache.pig.data.BagFactory;
import org.apache.pig.data.DataBag;
import org.apache.pig.data.DataType;
import org.apache.pig.data.Tuple;
import org.apache.pig.data.TupleFactory;
import org.apache.pig.impl.logicalLayer.schema.Schema;

/**
 * 自定义UDF,实现Pig与中文分词集成
 * **/
public class MyTokenize extends EvalFunc<DataBag> {
	/**tuple实例**/
	 TupleFactory mTupleFactory = TupleFactory.getInstance();
	 /**Bag实例*/
	 BagFactory mBagFactory = BagFactory.getInstance();
	
	@Override
	public DataBag exec(Tuple input) throws IOException {
		
		   try {
	            DataBag output = mBagFactory.newDefaultBag();
	            Object o = input.get(0);
	            List<Term> terms=ToAnalysis.parse((String)o);//获取Ansj的分词
	            for(Term t:terms){
	            	output.add(mTupleFactory.newTuple(t.getName()));//获取分词token,放入tuple,然后以bag的形式组装tuple
	            }
	            return output;
	        } catch (ExecException ee) {
	            // error handling goes here
	        	ee.printStackTrace();
	        }
		return null;
	}
	
	 /**描述scheaml形式*/
	  public Schema outputSchema(Schema input) {
	         try{
	             Schema bagSchema = new Schema();
	             bagSchema.add(new Schema.FieldSchema("token", DataType.CHARARRAY));

	             return new Schema(new Schema.FieldSchema(getSchemaName(this.getClass().getName().toLowerCase(), input),
	                                                    bagSchema, DataType.BAG));
	         }catch (Exception e){
	            return null;
	         }
	    }
	}



UDF写完后,需打成一个jar包,然后在Pig脚本里注册jar包(依赖的jar包也需要注册,例如本例中的ansj的jar),关于如何打包,注册,请参考散仙上篇文章,不要问我上篇文章在哪里,就在这文章里。


最后,我们来看下一个实际例子的效果,,散仙本打算把此篇博客给分析一下,统计下词频,看看能不能,通过高频词,直接看出本文的主题,后来立马否决了,因为此刻还没写完,不理解的就跳过,最后,从网上找了篇新闻,感兴趣的可以阅读下,原内容如下:

原标题:南水北调办主任回应境外抹黑:没什么可藏着掖着  
【环球时报综合报道】1月14日,2015年南水北调工作会议在河南南阳召开,安排部署2015年南水北调工作。在媒体通气会上,国务院南水北调办主任鄂竟平对境外一些媒体对南水北调工程的抹黑作出了回应,南水北调办主要领导就移民补偿、国际交流等问题接受了《环球时报》记者的采访。  
环球时报:关于丹江口移民率先的16倍补偿,这个标准是如何制定出来的?  
国务院南水北调办征地移民司司长袁松龄:这个16倍的补偿措施是我们南水北调工程率先在全国范围内实行的,在南水北调之前,水利工程的补偿基本是8倍到10倍。然而在整个迁区规划工作来看,8倍10倍标准显然是太低。我们的规划也是以人为本,不让被征迁的移民吃亏,所以按照当时国家标准作参考,南水北调率先实施16倍补偿。东、中线移民工程永久征地是96万亩,临时用地45万亩,总体来讲,被征迁的群众对国家的政策是理解和支持的。  
环球时报:资料中提到,南水北调移民过程中河南、湖北两省有18名干部因为过度劳累,牺牲在移民搬迁第一线,可否介绍下具体情况?  
国务院南水北调办征地移民司司长袁松龄:我们34.5万移民的整体搬迁过程中,有近十万干部投入到组织工作上。在这十多年以来,先后有18名干部倒在工作岗位上。比如说,湖北有一个叫刘峙清的干部,就是由于工作劳累心脏病突发,倒在了工作岗位上。还有比如河南南阳淅川的干部也是这样。整个村的移民,在搬迁前的一个晚上,基本都是行李拉起来,车装好之后,点燃篝火,干部们就陪着,第二天把大家送走。基层的干部基本上每天都和移民们朝夕相处,在搬迁过程中得不到休息,而且很闹心。我们有很多这样的事迹。  
环球时报:在南水北调工程中,我们是否借鉴过国外的一些经验,与其他国家的交流情况是怎样的?  
国务院南水北调办主任鄂竟平:国外的工程,我们考察了几个,比如美国、德国、加拿大、西班牙等等。总的来说,引水工程中的过程管理有一些可以借鉴,比如说国外有的工程是以公益性地来管理,由政府托管,只按照成本来收取水费,即按照建设和维护这个工程花多少钱来收水费,让工程自身能良性运行,但不盈利。  
咱们国家基本也是按照这个套路来弄的。  
再有就是调水的生态问题,也是值得借鉴的,国外在调出区和调入区的生态上,都有一些说法。德国对一些生态方面的规定蛮具体的,比如这条河流,流量到什么数值就要调水了,到什么数字就不能调水了,规定得很具体,管理很精细。这方面咱们应该特别需要注意,尤其是北方一些地区,水资源特别珍贵,如果没有一个量的概念,就不是很好管。  
对于境外一些媒体针对南水北调工程的抹黑,鄂竟平给予了回应,他表示,南水北调工程没有什么可藏着掖着的,为什么呢?因为它是一个积德的事儿。“北方一些地区的水资源已经紧缺到那样一个程度了,咱们把宝贵的水资源调来,叫老百姓能喝上好水,让生态环境不再恶化,大家生活在一个优美的环境里,这不是积德吗?一个积德的事有什么可藏着掖着的?”  
鄂竟平强调,国务院的政策都是透明的,有多少钱、干多少事,达到什么目标都是透明的,媒体什么问题都可以问,都可以讨论。“一些境外的媒体,话说的让人真的不好理解,英国有家媒体,大致意思说‘南水北调是祸国殃民的,引的都是脏水,比如中线,想把水引到东北工业基地,还没到天津就不能用了’。我们从来就没有过‘把水引到东北老工业基地’的方案,有些境外媒体说这些话的时候,连事情都搞不清楚,不知道到底是什么居心。” (环球时报记者范凌志)  
  原标题:南水北调办主任回应境外抹黑:没什么可藏着掖着
  【环球时报综合报道】1月14日,2015年南水北调工作会议在河南南阳召开,安排部署2015年南水北调工作。在媒体通气会上,国务院南水北调办主任鄂竟平对境外一些媒体对南水北调工程的抹黑作出了回应,南水北调办主要领导就移民补偿、国际交流等问题接受了《环球时报》记者的采访。
  环球时报:关于丹江口移民率先的16倍补偿,这个标准是如何制定出来的?
  国务院南水北调办征地移民司司长袁松龄:这个16倍的补偿措施是我们南水北调工程率先在全国范围内实行的,在南水北调之前,水利工程的补偿基本是8倍到10倍。然而在整个迁区规划工作来看,8倍10倍标准显然是太低。我们的规划也是以人为本,不让被征迁的移民吃亏,所以按照当时国家标准作参考,南水北调率先实施16倍补偿。东、中线移民工程永久征地是96万亩,临时用地45万亩,总体来讲,被征迁的群众对国家的政策是理解和支持的。
  环球时报:资料中提到,南水北调移民过程中河南、湖北两省有18名干部因为过度劳累,牺牲在移民搬迁第一线,可否介绍下具体情况?
  国务院南水北调办征地移民司司长袁松龄:我们34.5万移民的整体搬迁过程中,有近十万干部投入到组织工作上。在这十多年以来,先后有18名干部倒在工作岗位上。比如说,湖北有一个叫刘峙清的干部,就是由于工作劳累心脏病突发,倒在了工作岗位上。还有比如河南南阳淅川的干部也是这样。整个村的移民,在搬迁前的一个晚上,基本都是行李拉起来,车装好之后,点燃篝火,干部们就陪着,第二天把大家送走。基层的干部基本上每天都和移民们朝夕相处,在搬迁过程中得不到休息,而且很闹心。我们有很多这样的事迹。
  环球时报:在南水北调工程中,我们是否借鉴过国外的一些经验,与其他国家的交流情况是怎样的?
  国务院南水北调办主任鄂竟平:国外的工程,我们考察了几个,比如美国、德国、加拿大、西班牙等等。总的来说,引水工程中的过程管理有一些可以借鉴,比如说国外有的工程是以公益性地来管理,由政府托管,只按照成本来收取水费,即按照建设和维护这个工程花多少钱来收水费,让工程自身能良性运行,但不盈利。
  咱们国家基本也是按照这个套路来弄的。
  再有就是调水的生态问题,也是值得借鉴的,国外在调出区和调入区的生态上,都有一些说法。德国对一些生态方面的规定蛮具体的,比如这条河流,流量到什么数值就要调水了,到什么数字就不能调水了,规定得很具体,管理很精细。这方面咱们应该特别需要注意,尤其是北方一些地区,水资源特别珍贵,如果没有一个量的概念,就不是很好管。
  对于境外一些媒体针对南水北调工程的抹黑,鄂竟平给予了回应,他表示,南水北调工程没有什么可藏着掖着的,为什么呢?因为它是一个积德的事儿。“北方一些地区的水资源已经紧缺到那样一个程度了,咱们把宝贵的水资源调来,叫老百姓能喝上好水,让生态环境不再恶化,大家生活在一个优美的环境里,这不是积德吗?一个积德的事有什么可藏着掖着的?”
  鄂竟平强调,国务院的政策都是透明的,有多少钱、干多少事,达到什么目标都是透明的,媒体什么问题都可以问,都可以讨论。“一些境外的媒体,话说的让人真的不好理解,英国有家媒体,大致意思说‘南水北调是祸国殃民的,引的都是脏水,比如中线,想把水引到东北工业基地,还没到天津就不能用了’。我们从来就没有过‘把水引到东北老工业基地’的方案,有些境外媒体说这些话的时候,连事情都搞不清楚,不知道到底是什么居心。” (环球时报记者范凌志)



使用Pig分析完的部分topN结果如下:

(,,77)  
(的,50)  
( ,24)  
(是,24)  
(。,23)  
(南水北调,18)  
(在,14)  
(:,12)  
(工程,12)  
(移民,11)  
(有,11)  
(一些,9)  
(都,9)  
(了,9)  
(到,8)  
(水,8)  
( ,8)  
(干部,7)  
(一个,7)  
(时报,7)  
(、,7)  
(工作,7)  
(中,7)  
(我们,7)  
(就,7)  
(着,7)  
(什么,7)  
(环球,7)  
(媒体,7)  
(不,6)  
(来,6)  
(?,6)  
(办,6)  
(境外,5)  
(补偿,5)  
(国务院,5)  
(很,5)  
(上,5)  
(过程,4)  
(引,4)  
(搬迁,4)  
(按照,4)  
(,,77)
(的,50)
( ,24)
(是,24)
(。,23)
(南水北调,18)
(在,14)
(:,12)
(工程,12)
(移民,11)
(有,11)
(一些,9)
(都,9)
(了,9)
(到,8)
(水,8)
( ,8)
(干部,7)
(一个,7)
(时报,7)
(、,7)
(工作,7)
(中,7)
(我们,7)
(就,7)
(着,7)
(什么,7)
(环球,7)
(媒体,7)
(不,6)
(来,6)
(?,6)
(办,6)
(境外,5)
(补偿,5)
(国务院,5)
(很,5)
(上,5)
(过程,4)
(引,4)
(搬迁,4)
(按照,4)


最后来解释下,在一篇文章里,最多的词无疑是标点符号,和一些副词了,这不仅在中文里是这样,在英文里同样是这样的,最多的词往往是a,the,an,this之类的,副词什么的,所以统计词频前,一般会过滤掉一些无意义的词,这些散仙就不细说了,相信搞过搜索和自然语言处理的人,都很清楚,从结果前几个结果来看,确实证明了标点和一些连词与副词的频率最高,终于在结果的第六行,出现了第一个有意义的高频词,南水北调,频率是18次,这直接反映了本文的主题,并与之相关,有意义的高频词,一般就是本文的重点介绍内容,这一点在我们的数据挖掘,关键词提取,自然语言处理中用的比较多。

最后总结一下重点:

(1)测试的文本,在使用前是需要传到HDFS上的。
(2)注册jar包时,如果有依赖,也需要将依赖jar包注册在pig里。
(3)在真实的应用中,统计分析前,最好将一些无用的数据给过滤掉。