注:新版本NLPIR的JNI接口支持配置,可以将链接库和Data目录定义到配置文件中,但好像不支持UTF-8编码。
由于项目中要应用分词,因此前几天的时候了解了一下中文分词系统NLPIR(又叫ICTCLAS2013)的应用,并写了一篇学习笔记:
前面只是记录了一下在普通的Java工程中如何使用NLPIR,相对来说很简单,使用起来比较容易;但我们的项目是Web项目,因此从前天开始试着将NLPIR整合到Web工程下。还真是遇到了麻烦,主要也是因为第一次使用JNI,对其不够熟悉,折腾了许久才成功运行分词示例,这里记录一下。
起初以为跟普通项目一样,等我把东西都拷到项目中运行示例程序时,报了一个异常:
Caused by: java.lang.UnsatisfiedLinkError: no NLPIR_JNI in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1738)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1028)
at kevin.zhang.NLPIR.<clinit>(NLPIR.java:132)
说是异常,其实是个Error。很明显,程序无法加载NLPIR_JNI.dll动态链接库(起初我想当然地将它们放在了项目的WebRoot下)。这个好办,不就是找不到库文件吗?我挪到你能找到的地方还不行吗!!!挪到哪呢?我又想当然地将dll文件放到src下,不成功!与NLPIR.java放一个包中,仍然不成功!!
摆弄了很久都是UnsatisfiedLinkError,突然看到了“no NLPIR_JNI in java.library.path”这句话。不是说在java.library.path 中找不到吗?我把库文件移到 java.library.path 中总没什么可说的了吧!然后我就在Web项目中将 java.library.path 这个系统属性输出了一下,结果出来两个路径:
- %JAVA_HOME%/bin
- %TOMCAT_HOME%/bin
这么说java.library.path系统属性在Windows系统下由两个路径组成,第一个是JDK安装目录下的bin目录;第二个是Tomcat安装目录下的bin目录(我用的服务器是Tomcat,其它的服务器不确定是什么情况,请自行测试)。
这下就好办了,直接将 NLPIR.dll 和 NLPIR_JNI.dll 拷到这两个路径中的其中一个,运行,成功加载!!!
如果我们跟着代码去JDK源码查看一下,最终会追踪到ClassLoader的loadLibrary方法中,其代码如下(整理过):
static void loadLibrary(Class fromClass, String name, boolean isAbsolute) {
// 一些其它代码
ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader();
if (sys_paths == null) {
usr_paths = initializePath("java.library.path");
sys_paths = initializePath("sun.boot.library.path");
}
if (isAbsolute) {
if (loadLibrary0(fromClass, new File(name))) {
return;
}
throw new UnsatisfiedLinkError("Can't load library: " + name);
}
// 删除一些代码
for (int i = 0 ; i < sys_paths.length ; i++) {
File libfile = new File(sys_paths[i], System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
}
if (loader != null) {
for (int i = 0 ; i < usr_paths.length ; i++) {
File libfile = new File(usr_paths[i], System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
}
}
// Oops, it failed
throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
}
从上面的代码可以看到,两个String数组类型的成员变量对加载库文件有关:sys_paths 和 usr_paths,在这里打个断点就会发现,usr_paths 中就是我们在上面用System.getProperty("java.library.path") 获取的的两个路径,而sys_paths中有一个成员:%JRE_HOME%/bin,所以如果我们将库文件放在此处,应该也能成功加载(经过测试,确实如此)。
综上所述,在Windows系统上的Web项目中应用NLPIR分词系统至少有三个地方可以放置我们的dll文件(在本人机器环境上如此,不保证所有Windows系统都是如此,请自行测试):
- %JAVA_HOME%/bin
- %TOMCAT_HOME%/bin
- %JRE_HOME%/bin
在我的机器上就是:C:\Java\jdk1.6.0_45\bin 、 C:\Java\jdk1.6.0_45\jre\bin 和 E:\servers\apache-tomcat-6.0.37\bin 三个路径。
另外,JNI接口NLPIR静态块中的加载也可以换成System.load()方式,这里需要传递加载库的绝对路径,暂时没有测试!!!
Linux系统上Web项目应用NLPIR分词
我的开发环境是Windows,但项目最终会部署到Linux系统上,于是今天下午又在Linux上调试了一下,有了前面的经验,Linux上就轻车熟路了。项目不需改动,需要改动的就是NLPIR的库文件了。
Linux环境所需要的库文件是 libNLPIR.so 和 libNLPIR_JNI.so 两个(由于Linux系统和Linux上的JDK都是64位的,所以我下载的是64位的库),其它所需Data目录和Java接口与Windows一样。
首先在Linux上查看了一下 java.library.path 所包含的路径,结果如下所示:
于是我将两个库文件放到了 /usr/local/lib 目录下,启动Tomcat,访问,结果证明这样做是可以的!!!
按理说,上面图片中列出来的所有路径都应该可以的,但我没有挨个测试。
注:在Web项目中,NLPIR.NLPIR_Init初始化方法中的路径参数用的是绝对路径。