Golang版结巴中文分词『GoJieba』

前言

是时候正式写一篇文章专门介绍一下 GoJieba 了, 因为之后有打算基于 GoJieba 对于 nlp / 搜索引擎等领域好好做一些 Go语言的轮子开发。 Go语言目前来说,轮子还是偏少。 毕竟,轮子越多,社区才能越繁荣。 也欢迎对此也感兴趣的朋友能联系,互通有无。

本文基于 GoJieba v0.13.0 版本。

GoJieba是"结巴"中文分词的Golang语言版本。

关键字

Go(golang), 中文分词, 结巴(Jieba)中文分词, GoJieba

简介

  • 支持多种分词方式,包括: 最大概率模式, HMM新词发现模式, 搜索引擎模式, 全模式
  • 核心算法底层由C++实现,性能高效。
  • 无缝集成到 bleve 到进行搜索引擎的中文分词功能。
  • 字典路径可配置,NewJieba(…string), NewExtractor(…string) 可变形参,当参数为空时使用默认词典(推荐方式)

用法

go get github.com/yanyiwu/gojieba

分词示例

package main

import (
    "fmt"
    "strings"

    "github.com/yanyiwu/gojieba"
)

func main() {
    var s string
    var words []string
    use_hmm := true
    x := gojieba.NewJieba()
    defer x.Free()

    s = "我来到北京清华大学"
    words = x.CutAll(s)
    fmt.Println(s)
    fmt.Println("全模式:", strings.Join(words, "/"))

    words = x.Cut(s, use_hmm)
    fmt.Println(s)
    fmt.Println("精确模式:", strings.Join(words, "/"))

    s = "他来到了网易杭研大厦"
    words = x.Cut(s, use_hmm)
    fmt.Println(s)
    fmt.Println("新词识别:", strings.Join(words, "/"))

    s = "小明硕士毕业于中国科学院计算所,后在日本京都大学深造"
    words = x.CutForSearch(s, use_hmm)
    fmt.Println(s)
    fmt.Println("搜索引擎模式:", strings.Join(words, "/"))

    s = "长春市长春药店"
    words = x.Tag(s)
    fmt.Println(s)
    fmt.Println("词性标注:", strings.Join(words, ","))
}

运行结果:

我来到北京清华大学
全模式: 我/来到/北京/清华/清华大学/华大/大学
我来到北京清华大学
精确模式: 我/来到/北京/清华大学
他来到了网易杭研大厦
新词识别: 他/来到/了/网易/杭研/大厦
小明硕士毕业于中国科学院计算所,后在日本京都大学深造
搜索引擎模式: 小明/硕士/毕业/于/中国/中国科学院/科学/科学院/学院/计算所/,/后/在/日本/日本京都大学/京都/京都大学/大学/深造
长春市长春药店
词性标注: 长春市/ns,长春/ns,药店/n

Bleve 中文分词插件用法

package main

import (
    "fmt"
    "os"

    "github.com/blevesearch/bleve"
    "github.com/yanyiwu/gojieba"
    _ "github.com/yanyiwu/gojieba/bleve"
)

func Example() {
    INDEX_DIR := "gojieba.bleve"
    messages := []struct {
        Id   string
        Body string
    }{
        {
            Id:   "1",
            Body: "你好",
        },
        {
            Id:   "2",
            Body: "世界",
        },
        {
            Id:   "3",
            Body: "亲口",
        },
        {
            Id:   "4",
            Body: "交代",
        },
    }

    indexMapping := bleve.NewIndexMapping()
    os.RemoveAll(INDEX_DIR)
    // clean index when example finished
    defer os.RemoveAll(INDEX_DIR)

    err := indexMapping.AddCustomTokenizer("gojieba",
        map[string]interface{}{
            "dictpath":     gojieba.DICT_PATH,
            "hmmpath":      gojieba.HMM_PATH,
            "userdictpath": gojieba.USER_DICT_PATH,
            "type":         "gojieba",
        },
    )
    if err != nil {
        panic(err)
    }
    err = indexMapping.AddCustomAnalyzer("gojieba",
        map[string]interface{}{
            "type":      "gojieba",
            "tokenizer": "gojieba",
        },
    )
    if err != nil {
        panic(err)
    }
    indexMapping.DefaultAnalyzer = "gojieba"

    index, err := bleve.New(INDEX_DIR, indexMapping)
    if err != nil {
        panic(err)
    }
    for _, msg := range messages {
        if err := index.Index(msg.Id, msg); err != nil {
            panic(err)
        }
    }

    querys := []string{
        "你好世界",
        "亲口交代",
    }

    for _, q := range querys {
        req := bleve.NewSearchRequest(bleve.NewQueryStringQuery(q))
        req.Highlight = bleve.NewHighlight()
        res, err := index.Search(req)
        if err != nil {
            panic(err)
        }
        fmt.Println(res)
    }
}

func main() {
    Example()
}

运行结果:

2 matches, showing 1 through 2, took 360.584µs
    1. 2 (0.423287)
    Body
        <mark>世界</mark>
    2. 1 (0.423287)
    Body
        <mark>你好</mark>

2 matches, showing 1 through 2, took 131.055µs
    1. 4 (0.423287)
    Body
        <mark>交代</mark>
    2. 3 (0.423287)
    Body
        <mark>亲口</mark>

性能评测

Jieba中文分词系列性能评测

测试

Unittest

go test ./...

Benchmark

go test -bench "Jieba" -test.benchtime 10s
go test -bench "Extractor" -test.benchtime 10s

最后

不知道这次的雄心壮志是否又会最后变成『挖坑不填』, 但是,至少也算是起了个头,一年来再回头看看,是否真的有所建树。

转载请注明出处: Golang版结巴中文分词『GoJieba』