最近学习NLP用HanLP进行分词,在python中通过pip安装pyhanlp正常,导入pyhanlp进行分词或使用hanlp命令都报FileNotFoundError: [Errno 2] No such file or directory: '/usr/lib/jvm',网上都没有查到类似的错误,只有靠自己了。
...
...
...
~/anaconda3/envs/tensorflow/lib/python3.7/site-packages/jpype/_jvmfinder.py in get_jvm_path(self)
160 jvm = method()
161
--> 162 # If found check the architecture
163 if jvm:
164 self.check(jvm)
~/anaconda3/envs/tensorflow/lib/python3.7/site-packages/jpype/_jvmfinder.py in _get_from_known_locations(self)
215 for home in self.find_possible_homes(self._locations):
216 jvm = self.find_libjvm(home)
--> 217 if jvm is not None:
218 return jvm
~/anaconda3/envs/tensorflow/lib/python3.7/site-packages/jpype/_jvmfinder.py in find_possible_homes(self, parents)
120 for childname in sorted(os.listdir(parent)):
121 # Compute the real path
--> 122 path = os.path.realpath(os.path.join(parent, childname))
123 if path in homes or not os.path.isdir(path):
124 # Already known path, or not a directory -> ignore
FileNotFoundError: [Errno 2] No such file or directory: '/usr/lib/jvm'
可以看到是在执行_jvmfinder.py文件的find_possible_homes遇到的问题,于是打开这个文件去看了报错文件的源代码。我们在调用hanlp时将运行_jvmfinder.py的get_jvm_path()函数来获取系统的java路径,get_jvm_path定义如下
# 第147行
def get_jvm_path(self):
"""
Retrieves the path to the default or first found JVM library
Returns:
The path to the JVM shared library file
Raises:
ValueError: No JVM library found or No Support JVM found
"""
jvm_notsupport_ext = None
for method in self._methods:
try:
jvm = method()
# If found check the architecture
if jvm:
self.check(jvm)
# 后面 略
而get_jvm_path()实际上是运行self._methods中的方法,我们再看self._methods的定义(__init__()中):
# 第62行左右
# Search methods
self._methods = (self._get_from_java_home,
self._get_from_known_locations)
_methods中存的是本文件的另外两个函数,先运行_get_from_java_home(),如果没找到再运行_get_from_known_locations()。前面我们报错的是_get_from_known_locations(),那也就是说_get_from_java_home()没有成功找到java,来看这个函数的定义:
# 第186行
def _get_from_java_home(self):
"""
Retrieves the Java library path according to the JAVA_HOME environment
variable
Returns:
The path to the JVM library, or None
"""
# Get the environment variable
java_home = os.getenv("JAVA_HOME")
if java_home and os.path.exists(java_home):
# Get the real installation path
java_home = os.path.realpath(java_home)
# Cygwin has a bug in realpath
if not os.path.exists(java_home):
java_home = os.getenv("JAVA_HOME")
# Look for the library file
return self.find_libjvm(java_home)
这个函数主要通过获取系统环境变量JAVA_HOME来得到java的地址。可是命令行中运行java正常,为什么没找到这个环境变量呢? 重新查看一下配置文件/etc/profile中java环境变量的配置,如下
# set java path
JAVA_HOME=/usr/local/java/latest
export PATH=${JAVA_HOME}/bin:${PATH}
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
平时在命令行中能直接运行java,是因为java所在的bin目录被添加到PATH,且由export PATH后作为环境变量生效。但是JAVA_HOME只是作为普通变量,使用os.getenv()的时候获取环境变量时找不到JAVA_HOME,所以推测应该只要将JAVA_HOME前面添加export,然后重新source或重新登录即可。
在全局配置文件/etc/profile或个人配置文件~/.bashrc或~/.bash_profile中添加export JAVA_HOME即可,如下是我的/etc/profile的设置:
# set java path
export JAVA_HOME=/usr/local/java/latest
export PATH=${JAVA_HOME}/bin:${PATH}
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
其他注意事项:如果使用PyCharm远程调试,若遇到同样报错,需要在导入pyhanlp前先设置环境变量,如下
# 设置环境变量
import os
os.environ['JAVA_HOME'] = '/usr/local/java/latest'
# 再导入hanlp 即可避免无法找到java的问题
import pyhanlp as hanlp
修改后重新source或重新开一个终端窗口,可以成功运行hanlp segment命令
也可以在jupyter-lab中正常运行: