hadoop上利用JNI分词

虽然有streaming方式,但是碍于本人蹩脚的C++,还是决定由JNI方式来进行分词,下面是具体环境:

hadoop:0.201 

linux :2.6.16.60-0.21-TENCENT64-110923
jdk:Java(TM) SE Runtime Environment (build 1.6.0_17-b04),Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01, mixed mode)
 
TCWordSeg所必需的文件:
 
 
其中libTCWordSeg.so是分词的库文件,而TCWordSeg.jar中包含了所有的类和方法原型。
还有一个词典文件夹 data,其中包含了分词工具所必需的所有词典文件:
 
 
为了能更好更方便的使用分词,写了一个包装的类,在写代码之前,将TCWordSeg.jar添加到buildpath中。WordSeg4J 代码如下:
 
View Code
 1 import java.io.IOException;
 2 import org.mortbay.log.Log;
 3 import com.tencent.research.nlp.*;
 4  
 5 public class WordSeg4J {
 6  
 7 public static String dictDir = "data";
 8 public static int SEG_MODE =1; 
 9 static{
10 System.loadLibrary("TCWordSeg");
11 SEG_MODE = TCWordSeg.TC_POS | TCWordSeg.TC_S2D
12 | TCWordSeg.TC_U2L | TCWordSeg.TC_T2S | TCWordSeg.TC_ENGU
13 | TCWordSeg.TC_CN | TCWordSeg.TC_USR;
14  
15 try {
16 TCWordSeg.TCInitSeg(to_cstr_bytes(dictDir));
17 } catch (IOException e) {
18 // TODO Auto-generated catch block
19 System.out.println(e.getMessage());
20 Log.info(e.getMessage());
21 }
22 }
23  
24 public static String segString(String str) {
25 SWIGTYPE_p_void seghandle = TCWordSeg.TCCreateSegHandle(SEG_MODE);
26 //System.out.println(str);
27 String line_seg = "";
28 /* 以 GBK 字节流的方式提供待切分句子 */
29 try {
30 TCWordSeg.TCSegment(seghandle, to_cstr_bytes(str));
31 int rescount = TCWordSeg.TCGetResultCnt(seghandle);
32 for (int i = 0; i < rescount; i++) {
33 byte[] word_bytes = TCWordSeg.TCGetWordAt(seghandle, i);
34 String word = new String(word_bytes, "GBK");
35 line_seg += word + " ";
36 }
37 } catch (IOException e) {
38 // TODO Auto-generated catch block
39 System.out.println(e.getMessage());
40 }
41  
42 return line_seg;
43 }
44  
45 /*
46  * 注意: 在 C 接口中传入参数类型为 char * 的地方, Java 接口中全部 使用参数类型 byte[], 并且 byte[] 数组必须以
47  * '\0' 结束。 这是为了解决GBK 编码字符串在 C <-> Java 中转换的问题
48  */
49 public static byte[] to_cstr_bytes(String str) throws IOException {
50 String s = str + '\0';
51 return s.getBytes("GBK");
52 }
53 }

ps:如果您经常使用这个类,建议将其打包为jar,推荐使用eclipse的fatjar工具,将TCWordSeg.jar一起打包成一个jar,或者用ANT打包。

写完了包装类,就可以在Mapper或者Reducer中使用这个类的静态方法了。但是先别急着些驱动程序,还有两件事最好先完成:
1)分别将libTCWordSeg.so和data文件夹打包成lib.tar和data.tar,当然也可以打包成zip或者jar、gzippedtar等形式。
2)将上面两个tar文件上传到hdfs中,假设它们的hdfs路径分别为 /path/lib.tar 和/path/data.tar
好了,现在就可以写驱动程序了,在写驱动程序的时候,需要注意利用hadoop的一个重要特性:DistributedCache,关于这个东西的详细介绍,网络上一大堆,自己可以去看。
在驱动程序中,需要加入下面这么几行代码:
View Code
1 DistributedCache.createSymlink(conf); 
2             
3 Path filePath = new Path(" /path/lib.tar");
4 String uriWithLink = filePath.toUri().toString(); DistributedCache.addCacheArchive(new URI(uriWithLink), conf); 
5  
6 Path filePath2 = new Path("/path/data.tar");
7 String uriWithLink2 = filePath2.toUri().toString();
8 DistributedCache.addCacheArchive(new URI(uriWithLink2), conf);    

 好了,之后用fatjar将程序打包,将TCWord.jar也一起打入,之后就可以在hadoop上运行程序了。

posted @ 2012-09-21 12:57  ancientmoon  阅读(896)  评论(0编辑  收藏  举报