背景
我们团队负责对策略开发的功能进行工程化实现。策略研发用Python的jieba包实现了一个对用户传入query词进行中文分词的功能。我们后端服务是Go,为了实现jieba的分词能力,引入了gojieba包
问题
在开发环境中可以良好运行的代码,打包后在线上部署时发现报错:
2023/07/25 14:08:35 set.go:45: [gdp][automaxprocs] auto set skipped, maxProcs=0.6000000238418579, err=
2023/07/25 14:08:35 set.go:40: [gdp][automaxprocs] current GOMAXPROCS=48, last GOMAXPROCS=48
2023-07-25 14:08:35 /root/go/pkg/mod/github.com/yanyiwu/gojieba@v1.3.0/deps/cppjieba/DictTrie.hpp:212 FATAL exp: [ifs.is_open()] false. open /root/go/pkg/mod/github.com/yanyiwu/gojieba@v1.3.0/dict/jieba.dict.utf8 failed.
SIGABRT: abort
PC=0x7f0223950a48 m=0 sigcode=18446744073709551610
signal arrived during cgo execution
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x1197720, 0xc00063f800)
排查
问题分析
根据报错信息进行分析
- 首先
signal arrived during cgo execution
提示可能与CGO配置有关 - 其次
open /root/go/pkg/mod/github.com/yanyiwu/gojieba@v1.3.0/dict/jieba.dict.utf8 failed.
提示可能与文件路径错误有关
为了验证上面的猜想,增加CGO_ENABLED=1
配置重新打包,并在开发环境运行编译产出。发现依然报错。可以认为错误原因应该是:文件路径问题
此时产生了一个疑问,为什么开发环境没有报错? 下面是当时源码:
var Jieba *gojieba.Jieba
func init() {
Jieba = gojieba.NewJieba()
for w := range TagMap {
Jieba.AddWord(w)
}
}
问题确认
查阅了前人的解决方案 【gojieba在linux系统编译及运行问题总结_rgc_520_zyl的博客-CSDN博客 】后,找到了原因:
gojieba.NewJieba
不传参数时,会从默认的包里面读取utf8字典文件。开发环境直接读取下载的 github.com/yanyiwu/gojieba 包的dict文件夹里面读取utf8文件。打包编译之后,线上没有对应的go包,所以找不到对应文件
解决
找到了原因,对症下药即可:
将utf8文件copy到本地文件夹,并在代码里指定,就可以保证线上服务也能找到对应的文件了
var Jieba *gojieba.Jieba
func init() {
// 指定本地字典路径
dir := path.Join(env.DataDir(), "static_dict")
dpath := path.Join(dir, "jieba.dict.utf8")
hpath := path.Join(dir, "hmm_model.utf8")
upath := path.Join(dir, "user.dict.utf8")
ipath := path.Join(dir, "idf.utf8")
spath := path.Join(dir, "stop_words.utf8")
Jieba = gojieba.NewJieba(dpath, hpath, upath, ipath, spath)
for w := range TagMap {
Jieba.AddWord(w)
}
}
问题顺利解决!