分詞技術就是搜索引擎針對用戶提交查詢的關鍵詞串進行的查詢處理後根據用戶的關鍵詞串用各種匹配方法進行分詞的一種技術。
中文分詞(Chinese Word Segmentation)指的是將一個漢字序列(句子)切分成一個一個的單獨的詞,分詞就是將連續的字序列按照一定的規則重新組合成詞序列的過程。
現在分詞方法大致有三種:基於字符串配置的分詞方法、基於理解的分詞方法和基於統計的分詞方法。
今天爲大家分享一個國內使用人數最多的中文分詞工具GoJieba,源代碼地址:GoJieba ,官方文檔:GoJieba官方文檔
官方介紹
- 支持多種分詞方式,包括: 最大概率模式, HMM新詞發現模式, 搜索引擎模式, 全模式
- 核心算法底層由C++實現,性能高效。
- 無縫集成到 Bleve 到進行搜索引擎的中文分詞功能。
- 字典路徑可配置,NewJieba(...string), NewExtractor(...string) 可變形參,當參數爲空時使用默認詞典(推薦方式)
模式擴展
- 精確模式:將句子精確切開,適合文本字符分析
- 全模式:把短語中所有的可以組成詞語的部分掃描出來,速度非常快,會有歧義
- 搜索引擎模式:精確模式基礎上,對長詞再次切分,提升引擎召回率,適用於搜索引擎分詞
主要算法
- 前綴詞典實現高效的詞圖掃描,生成句子中漢字所有可能出現成詞情況所構成的有向無環圖(DAG)
- 採用動態規劃查找最大概率路徑,找出基於詞頻最大切分組合
- 對於未登錄詞,採用漢字成詞能力的HMM模型,採用Viterbi算法計算
- 基於Viterbi算法做詞性標註
- 基於TF-IDF和TextRank模型抽取關鍵詞
編碼實現
package main
import (
"fmt"
"github.com/yanyiwu/gojieba"
"strings"
)
func main() {
var seg = gojieba.NewJieba()
defer seg.Free()
var useHmm = true
var separator = "|"
var resWords []string
var sentence = "萬里長城萬里長"
resWords = seg.CutAll(sentence)
fmt.Printf("%s\t全模式:%s \n", sentence, strings.Join(resWords, separator))
resWords = seg.Cut(sentence, useHmm)
fmt.Printf("%s\t精確模式:%s \n", sentence, strings.Join(resWords, separator))
var addWord = "萬里長"
seg.AddWord(addWord)
fmt.Printf("添加新詞:%s\n", addWord)
resWords = seg.Cut(sentence, useHmm)
fmt.Printf("%s\t精確模式:%s \n", sentence, strings.Join(resWords, separator))
sentence = "北京鮮花速遞"
resWords = seg.Cut(sentence, useHmm)
fmt.Printf("%s\t新詞識別:%s \n", sentence, strings.Join(resWords, separator))
sentence = "北京鮮花速遞"
resWords = seg.CutForSearch(sentence, useHmm)
fmt.Println(sentence, "\t搜索引擎模式:", strings.Join(resWords, separator))
sentence = "北京市朝陽公園"
resWords = seg.Tag(sentence)
fmt.Println(sentence, "\t詞性標註:", strings.Join(resWords, separator))
sentence = "魯迅先生"
resWords = seg.CutForSearch(sentence, !useHmm)
fmt.Println(sentence, "\t搜索引擎模式:", strings.Join(resWords, separator))
words := seg.Tokenize(sentence, gojieba.SearchMode, !useHmm)
fmt.Println(sentence, "\tTokenize Search Mode 搜索引擎模式:", words)
words = seg.Tokenize(sentence, gojieba.DefaultMode, !useHmm)
fmt.Println(sentence, "\tTokenize Default Mode搜索引擎模式:", words)
word2 := seg.ExtractWithWeight(sentence, 5)
fmt.Println(sentence, "\tExtract:", word2)
return
}
運行結果
go build -o gojieba
time ./gojieba
萬里長城萬里長 全模式:萬里|萬里長城|里長|長城|萬里|里長
萬里長城萬里長 精確模式:萬里長城|萬里|長
添加新詞:萬里長
萬里長城萬里長 精確模式:萬里長城|萬里長
北京鮮花速遞 新詞識別:北京|鮮花|速遞
北京鮮花速遞 搜索引擎模式: 北京|鮮花|速遞
北京市朝陽公園 詞性標註: 北京市/ns|朝陽/ns|公園/n
魯迅先生 搜索引擎模式: 魯迅|先生
魯迅先生 Tokenize Search Mode 搜索引擎模式: [{魯迅 0 6} {先生 6 12}]
魯迅先生 Tokenize Default Mode搜索引擎模式: [{魯迅 0 6} {先生 6 12}]
魯迅先生 Extract: [{魯迅 8.20023407859} {先生 5.56404756434}]
real 0m1.746s
user 0m1.622s
sys 0m0.124s
性能評測
語言 | 源碼 | 耗時 |
C++版本 | CppJieba | 7.5 s |
Golang版本 | GoJieba | 9.11 s |
Python版本 | Jieba | 88.7 s |
計算分詞過程的耗時,不包括加載詞典耗時,CppJieba性能是GoJieba的1.2倍。CppJieba性能詳見jieba-performance-comparison,GoJieba由於是C++開發的CppJieba,性能方面僅次於CppJieba,如果追求性能還是可以考慮的。