解决 NLPIR (中科院分词) License 过期问题

时间:2022-06-10 17:28:44
因为学习需要,使用到了中文分词技术,网上搜索一番,最终选择了名气比较大的中科院分词器(NLPIR/ICTCLAS)。


用了几个月之后突然报错:

E:\code\URLClassifier\Data\NLPIR.user Not valid license or your license expired! Please feel free to contact pipy_zhang@msn.com!

手动更新License之后,过了一个月又过期了。才知道免费License的周期由三个月缩短为一个月了。

所以想能不能自动更新 License,免得时不时的过期,需要手动去更新。

首先想到做一个定时任务,隔断时间去下载最新的 License 不就行了吗。 最后发现这样不行,官方License的更新周期不固定,总不能隔一分钟去下载一次吧。

然后就想到另一种规避办法,每次初始化NLPIR时先检测 License 是否过期,如果过期就更新 License 。最后证明这种办法是可行的。但是要注意,不能在同一个 JVM 中初始化两次 NLPIR(会报 Other thread is under initialization )因为如果第一次初始化  NLPIR 失败,然后更新 License ,再次初始化时不会发现新下载的 License 文件!目前不清楚具体原因是什么(有知道的童鞋记得指教!),猜测应该是因为 NLPIR 用到了JNA 接口,JNA 在 load library 执行之后, filesystem cache 并没有在下载文件后及时更新。

所以只能让两次初始化处在两个独立的 JVM 中,很简单,写一个检测 License 程序打包后在另外一个程序中调用,检测到 License 过期后,更新 License 再初始化就不会出现 Other thread is under initialization 错误。

LicenseChecker.java

import com.sun.jna.Native;

/**
* check if NLPIR license is expired
*
*/
public class LicenseChecker {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("java -jar LicenseChecker.jar libPath [DataPath]");
System.exit(2);
}

System.exit(run(args[0], args.length == 1 ? "" : args[1]));
}

/**
* try initial NLPIR
*
* @param lib
* @param data
* @return 0 if license invalid or other exception happened else return 1
* represent initial NLPIR success
*/
public static int run(String lib, String data) {
int status = 0;
NlPIRLibrary instance = (NlPIRLibrary) Native.loadLibrary(lib,
NlPIRLibrary.class);
if (instance.NLPIR_Init(data, 1, "")) {
status = 1;
}
instance.NLPIR_Exit();
return status;
}
}


NlPIRIniter.java

/**
* get NLPIR Object
*
*
*/
class NlPIRIniter {
// license update url
public static final String latestLicenseUrl = "https://github.com/NLPIR-team/NLPIR/raw/master" +
<span style="white-space:pre"></span>"/License/license%20for%20a%20month/NLPIR-ICTCLAS%E5%88%86%E8%AF%8D%E7%B3%BB%E7%BB%9F%E6%8E%88%E6%9D%83/NLPIR.user";

/**
* initialization NLPIR (handle license expired problem)
*
* @param lib
* @param data
* @param licenseCheckerJarPath
* @return
* @throws Exception
*/
public static NlPIRLibrary getInstance(String lib, String data,String licenseCheckerJarPath)
throws Exception {
// call another jar to check if license is expired
Process p = Runtime.getRuntime().exec(
"java -jar " + licenseCheckerJarPath + " " + lib + " " + data);
p.waitFor(10, TimeUnit.SECONDS);
// return 0 when initial failed
if (p.exitValue() == 0) {
FileDownLoader.get(latestLicenseUrl,
Paths.get(data, "Data", "NLPIR.user").toString());
}
NlPIRLibrary instance = (NlPIRLibrary) Native.loadLibrary(lib,
NlPIRLibrary.class);

if (instance.NLPIR_Init(data, 1, "0")) {
return instance;
}
throw new Exception(instance.NLPIR_GetLastErrorMsg());
}
}


这样 NLPIR 分词的 License 问题算是解决了。