美文网首页
如何使jieba自定义词典持久化

如何使jieba自定义词典持久化

作者: 菜菜鑫 | 来源:发表于2019-11-11 12:12 被阅读0次

    jieba分词是利用python进行自然语言处理中必不可少的常用工具,添加自定义词典也是jieba分词中的的常用功能。

    然而每次运行程序,jieba自定义词典都需要重新加载,添加的自定义词典只对当前程序生效。如果自定义词典的数量比较巨大(百万级及以上),每次重新加载这一步将会耗费很长的时间。

    网上找不到相关的持久化解决方案,只会告诉你如何使用jieba.load_userdict,所以我的这个完整的持久化方案也算是全网首发了。

    事先准备好自定义词典:

    创建一个txt文件,然后写入你的分词,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。类似于如下形式:

    沈孟良 360 nr
    富民理财睿盈 360 nfp
    广发多添富 360 nfp
    

    方案分析:

    • 整体的解决方案是将加载了自定义词典的jieba模型存储到本地,每次不用再次加载词典而是直接调用模型。每次启动jieba都可以看到会输出以下信息,说明jieba还是会从缓存中读取一些信息的。
    Building prefix dict from the default dictionary ...
    Loading model from cache /tmp/jieba.cache
    Loading model cost 0.474 seconds.
    Prefix dict has been built succesfully.
    
    • 可以明确的一点是,我们要查看并修改部分的jieba源码,因为目前的jieba功能不能完全满足我们的需求,所以,把jieba项目clone到本地:
    git clone https://github.com/fxsjy/jieba.git
    

    为了防止和系统中已安装的jieba重名,可以把这个文件重命名为jieba_local

    • jieba源码中已经定义了一个dict.txt,存放jieba分词的词典,这个词典在init.py的第350行的get_dict_file函数中被调用。而从下面的代码中,我们看到了熟悉的’Loading model from cache‘,另外,可以看出,调用词典的前提是 load_from_cache_fail。
     load_from_cache_fail = True
                if os.path.isfile(cache_file) and (abs_path == DEFAULT_DICT or
                    os.path.getmtime(cache_file) > os.path.getmtime(abs_path)):
                    default_logger.debug(
                        "Loading model from cache %s" % cache_file)
                    try:
                        with open(cache_file, 'rb') as cf:
                            self.FREQ, self.total = marshal.load(cf)
                        load_from_cache_fail = False
                    except Exception:
                        load_from_cache_fail = True
    
                if load_from_cache_fail:
                    wlock = DICT_WRITING.get(abs_path, threading.RLock())
                    DICT_WRITING[abs_path] = wlock
                    with wlock:
                        self.FREQ, self.total = self.gen_pfdict(self.get_dict_file())
                        default_logger.debug(
                            "Dumping model to file cache %s" % cache_file)
                        try:
                            # prevent moving across different filesystems
                            fd, fpath = tempfile.mkstemp(dir=tmpdir)
                            with os.fdopen(fd, 'wb') as temp_cache_file:
                                marshal.dump(
                                    (self.FREQ, self.total), temp_cache_file)
                            _replace_file(fpath, cache_file)
                        except Exception:
                            default_logger.exception("Dump cache file failed.")
    
                    try:
                        del DICT_WRITING[abs_path]
                    except KeyError:
                        pass
    

    所以要把我们的自定义词典添加到dict.txt中,并且让之后的每次都成功调用缓存文件,就不会再次加载词典了。Nice!

    • jieba的github里面的Readme.txt中给出了:
    更改分词器(默认为 jieba.dt)的 tmp_dir 和 cache_file 属性,可分别指定缓存文件所在的文件夹及其文件名,用于受限的文件系统。
    

    这样我们就可以指定jieba缓存的文件夹的文件名了。

    方案实施

    分析了修改的思路和原理,下面开始实施方案:

    • 首先把所有的自定义词典复制,粘贴到jieba_local中的dict.txt文件夹内
    • 接着,另外new一个.py文件,随意命名,写入
    import jieba_local
    
    jieba_local.dt.tmp_dir = './'
    jieba_local.dt.cache_file = 'jieba.temp'
    for i in jieba_local.cut('恭喜FPX夺冠啦啦啦啦'):
        print(i)
    
    • 运行该代码之后,加载了新的词典,本地文件夹下应该已经生成了名为jieba.temp的缓存文件
    • 以后再次运行只需把jieba_local拷贝到项目中,在调用的程序中指定缓存文件的文件夹和路径即可:
    jieba_local.dt.tmp_dir = './'
    jieba_local.dt.cache_file = 'jieba.temp'
    
    • 可以看到指定路径过后能成功导入缓存模型。模型本身占用比较大的存储空间(我的将近1G),另外加载的速度也比之前要慢,用了28秒多的时间,但是无需再次加载自定义词典,相比于之前的40多秒的加载自定义词典的时间还是缩短了将近一半,算是用空间换时间的方法。
    Building prefix dict from the default dictionary ...
    Loading model from cache ./jieba.temp
    Loading model cost 28.665 seconds.
    Prefix dict has been built succesfully.
    

    \color{red}{(涉及公司机密,完整代码和数据无法提供,请见谅,纯原创,转载请注明来源)}

    相关文章

      网友评论

          本文标题:如何使jieba自定义词典持久化

          本文链接:https://www.haomeiwen.com/subject/mtttictx.html