前段时间使用了HanLP一个纯JAVA分词工具包,后来老大说分词效果不是很好,须要换一个分词工具。因而推荐了一个分词工具——NLPIR,它是中科院XXX研发的一个分词工具。这个分词工具只用C/C++写的,可是它提供了JAVA,C#等调用接口。因而我但愿是的经过java来调用。使用java调用C/C++的代码须要用到JNA,因此工程须要添加JNA的依赖包。java
这里面官网上介绍的不是特别清楚,里面有些坑,第一次使用的人还真须要一段时间解决,下面将我踩的坑记录一下:linux
一、首先进官网:http://ictclas.nlpir.org/ 下载相应的安装包,我下载的是:git
20160907102816_ICTCLAS2016分词系统下载包.zipgithub
解压以后会出现以下文件目录:安全
其中,主要的几个目录是:函数
(1)Data,这个目录是放了license(NLPIR.user)在里面,这个若是你配置成功,初始化失败,通常都是license过时了。这个license目前是一个月更新一次。工具
(2)lib ,这个目录存放了linux和window下,运行须要的dll文件和.so文件。其中分别有对应的位数:spa
(3)sample,这个目录下面有多个语言实现的example。因为我这里使用的是java,因此就选择java,选择JNA,在选择JnaTest_NLPIR。在这个java工程就是提供的一个例子。操作系统
能够将例子导入工程中,代码以下:scala
package code; import java.io.UnsupportedEncodingException; import utils.SystemParas; import com.sun.jna.Library; import com.sun.jna.Native; public class NlpirTest { // 定义接口CLibrary,继承自com.sun.jna.Library public interface CLibrary extends Library { // 定义并初始化接口的静态变量 CLibrary Instance = (CLibrary) Native.loadLibrary( "NLPIR", CLibrary.class); //这里须要注意,这个位置就设置为NLPIR是不可以改变,这里折腾我很久了,原来是这个NLPIR文件是不能改变。 // printf函数声明 public int NLPIR_Init(byte[] sDataPath, int encoding, byte[] sLicenceCode); public String NLPIR_ParagraphProcess(String sSrc, int bPOSTagged); public String NLPIR_GetKeyWords(String sLine, int nMaxKeyLimit, boolean bWeightOut); public void NLPIR_Exit(); } public static String transString(String aidString, String ori_encoding, String new_encoding) { try { return new String(aidString.getBytes(ori_encoding), new_encoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } public static void main(String[] args) throws Exception { String argu = ""; // String system_charset = "GBK";//GBK----0 String system_charset = "GBK"; int charset_type = 1; // int charset_type = 0; // 调用printf打印信息 int init_flag = CLibrary.Instance.NLPIR_Init(argu .getBytes(system_charset), charset_type, "0" .getBytes(system_charset)); if (0 == init_flag) { System.err.println("初始化失败!"); return; } String sInput = "据悉,质检总局已将最新有关状况再次通报美方,要求美方增强对输华玉米的产地来源、运输及仓储等环节的管控措施,有效避免输华玉米被未经我国农业部安全评估并批准的转基因品系污染。"; String nativeBytes = null; try { nativeBytes = CLibrary.Instance.NLPIR_ParagraphProcess(sInput, 3); System.out.println("分词结果为: " + nativeBytes); int nCountKey = 0; String nativeByte = CLibrary.Instance.NLPIR_GetKeyWords(sInput, 10,false); System.out.print("关键词提取结果是:" + nativeByte); CLibrary.Instance.NLPIR_Exit(); } catch (Exception ex) { // TODO Auto-generated catch block ex.printStackTrace(); } } }
此时这样设置以后,接下来须要区分window和linux:
(1)如果在window下,只须要将NLPIR.dll文件拷贝到工程目录下便可,就能够在IDE里面运行。如果在控制台的话,一样须要将NLPIR.dll文件拷贝到jar包同目录下便可。
(2)如果在linux下,只须要将libNLPIR.so文件拷贝到当前jar包的目录下便可。
下面说说我踩得坑:
坑一、如上述描述,很是简单的使用,硬是给我搞了一天才搞定,这说明什么?刚开始我所遇到的是CLibrary Instance = (CLibrary) Native.loadLibrary( "NLPIR", CLibrary.class);这句究竟是加载什么路径下的库文件。费了很大的劲,最后采用的是使用相对路径。只须要填写“NLPIR”便可。而且这个名字是不能够改变的。
坑二、当你将NLPIR.dll文件添加到工程后,觉得应该是能够了,可是仍是报错,报以下错误:
这个错误主要缘由是dll文件位数与操做系统的位数不一致所形成的。因为我是64位的操做系统,因此讲NLPIR.dll文件换成64位的便可。
坑三、当你上面都搞定了,运行以后,会报"初始化失败"的错误,这个错误刚开始搞了很久,没弄明白,由于以为本身都配置好了,为何仍是初始化失败,这也是我花费时间最长的地方。后来网上一查发现,原来是有一个license。它是有时间的限制的。因而须要更换最新的license。去哪里更换呢?我在网上找到一我的的电话,直接打电话过去问的,听过那人介绍,原来在下载的时候,有标明license下载的地方。以下所示:https://github.com/NLPIR-team/NLPIR/tree/master/License
license原来是在这里下载。搞了半天,license放到了这么隐蔽的位置。
坑四、如上所示,也更换了最新的license,能够运行了。可是接下来,个人想法是将这个东西打jar包,在linux上运行,搞了半天不知道怎么回事,总是报错,最后的缘由是在设置坑1的时候路径问题。由于一开始我设置的是绝对路径,老是报错,后来直接用相对路径。就不报错了。
坑五、本地是能够运行ICTCLAS了,可是因为NLP处理的预料都是比较大的数据,想法是提交到集群上去运行。那么如何实现呢?这里须要解决两个问题:
(1)libNLPIR.so文件的问题,因为ICTCLAS是C/C++写的代码,利用java/scala调用相应的API的时候,都是经过JNA调用.so里面的库函数来实现的。因此要想提交到集群上去运行,首先要解决的是各个节点如何能读取到libNLPIR.so文件?
解决的办法:将libNLPIR.so文件放在全部的节点的同一个目录下:/lib64/libNLPIR.so ,而且修改该.so文件的权限为777.
(2)Data中的配置文件和license文件在集群中如何加载?
解决的办法:再次查看ICTCLAS的参考手册,发现函数NLPIR_Init是有一个参数能够指定Data的路径的。因而借鉴上面的思路,即将Data目录放到全部的节点相同的目录下/dic/Data。这里须要注意点,函数NLPIR_Init的表示形式是:
bool NLPIR_Init(const char * sInitDirPath=0,int encoding=GBK_CODE,const char*sLicenceCode=0);
这里的参数sInitDirPath只须要传递Data的父目录便可。即:/dic 便可。(一开始我传入的参数是/dic/Data,最后结果仍是报“初始化失败”的错误。)
至此,就能够在集群上运行ICTCLAS分词了。
坑六、利用ICTCLAS在集群上分词,为了提升运行速度,咱们一般是考虑增长运行集群资源,如CPU,内存。但这样形成以下错误:
在datanote节点上出现以下两个错误:
形成以上两个错误的缘由是:当咱们在增长运行资源的同时,集群会在同个节点上分配两个或者两个以上的executor,而在程序运行的过程当中,当一个executor释放资源时,会致使另一个executor的资源也释放了。从而引起上面的错误。
解决的办法是:减小运行的资源,从而保证每一个节点只运行一个executor。