一榜聂、分詞工具
ansj
、hanlp
嗓蘑、jieba
二须肆、優(yōu)缺點
1. ansj
優(yōu)點:
- 提供多種分詞方式
- 可直接根據(jù)內(nèi)部詞庫分出人名匿乃、機構(gòu)等信息
- 可構(gòu)造多個詞庫,在分詞時可動態(tài)選擇所要使用的詞庫
缺點:
- 自定義詞典時豌汇,系統(tǒng)詞典還是被優(yōu)先使用幢炸,導(dǎo)致詞性不是自定義詞典中的詞性
- 多單詞英文姓名無法分出
適用場景
- 若不使用自定義分詞,可直接使用ansj
2. hanlp
優(yōu)點:
- 自定義分詞拒贱、詞性方便
- 可分出多單詞的英文名稱(詞典數(shù)據(jù)可帶空格)
- 可動態(tài)增刪詞庫,
- 動態(tài)添加詞典前五千萬速度很快宛徊,5m左右
缺點:
- 動態(tài)添加詞典前五千萬快的很,越往后越慢
- 詞典文件添加自定義詞典速度略慢逻澳,添加100w需要2m30s
適用場景:
- 詞典數(shù)量少于五千萬闸天,詞典數(shù)據(jù)若包含空格,用hanlp比較合適
3. jieba
優(yōu)點:
- 自定義分詞斜做、詞性方便
- 詞典文件添加自定義詞典比hanlp快苞氮,詞典文件添加100w需要1m,八千萬 2h多
缺點:
- 自定義詞典時陨享,帶空格的詞不支持
適用場景:
- 詞典數(shù)量大于五千萬
- 詞典數(shù)據(jù)不能包含空格葱淳,否則分不出
ansj的使用
1. maven引入ansj包
<ansj.version>5.0.4</ansj.version>
<tree_split.version>1.5</tree_split.version>
<nlp-lang.version>1.7.7</nlp-lang.version>
<!-- ansj_seg -->
<dependency>
<groupId>org.ansj</groupId>
<artifactId>ansj_seg</artifactId>
<version>${ansj.version}</version>
</dependency>
<!-- tree_split -->
<dependency>
<groupId>org.ansj</groupId>
<artifactId>tree_split</artifactId>
<version>${tree_split.version}</version>
</dependency>
<!-- nlp-lang -->
<dependency>
<groupId>org.nlpcn</groupId>
<artifactId>nlp-lang</artifactId>
<version>${nlp-lang.version}</version>
</dependency>
2. 在項目根目錄下創(chuàng)建library文件夾,文件夾下包括以下幾個詞典文件(自行添加)
ambiguity.dic
default.dic
userLibrary.dic
3. 使用
package com.zhen.segment;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.library.UserDefineLibrary;
import org.ansj.splitWord.analysis.BaseAnalysis;
import org.ansj.splitWord.analysis.NlpAnalysis;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.nlpcn.commons.lang.tire.domain.Forest;
import org.nlpcn.commons.lang.tire.domain.Value;
import org.nlpcn.commons.lang.tire.library.Library;
/**
* @author FengZhen
* @date Jan 30, 2019
* ansj分詞
*/
public class SegmentTest {
public static void main(String[] args) {
// dynamicWord();
// localDic();
// moreUserDic();
}
/**
* 多用戶詞典(新增抛姑、刪除)
*/
public static void moreUserDic() {
// 多用戶詞典
String str = "神探夏洛克這部電影作者.是一個dota迷";
System.out.println(ToAnalysis.parse(str));
// 兩個詞匯 神探夏洛克 douta迷
Forest dic1 = new Forest();
Library.insertWord(dic1, new Value("神探夏洛克", "define", "1000"));
Forest dic2 = new Forest();
Library.insertWord(dic2, new Value("dota迷", "define", "1000"));
System.out.println(ToAnalysis.parse(str, dic1, dic2));
System.out.println("-------刪除dic1中的詞");
Library.removeWord(dic1, "神探夏洛克");
System.out.println(ToAnalysis.parse(str, dic1, dic2));
}
/**
* 動態(tài)增刪詞庫
*/
public static void dynamicWord(){
// 增加新詞,中間按照'\t'隔開
UserDefineLibrary.insertWord("ansj中文分詞", "userDefine", 1000);
Result result = ToAnalysis.parse("我覺得Ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!");
System.out.println("增加新詞例子:" + result);
// 刪除詞語,只能刪除.用戶自定義的詞典.
UserDefineLibrary.removeWord("ansj中文分詞");
result = ToAnalysis.parse("我覺得ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!");
System.out.println("刪除用戶自定義詞典例子:" + result);
//將用戶自定義詞典清空
UserDefineLibrary.clear();
}
/**
* 加載詞典文件
*/
public static void localDic(){
try {
//讀的是根目錄下的
Forest rootForest = Library.makeForest("library/userLibrary.dic");
System.out.println(rootForest.toMap());
//加載字典文件,取的是resource下的
InputStream inputStream = SegmentTest.class.getResourceAsStream("/library/userLibrary.dic");
Forest resoutceForest=Library.makeForest(inputStream);
String str = "我覺得ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!";
Result result=ToAnalysis.parse(str, resoutceForest);//傳入forest
List<Term> termList=result.getTerms();
for(Term term:termList){
System.out.println(term.getName()+":"+term.getNatureStr());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 基本分詞
* 基本就是保證了最基本的分詞.詞語顆粒度最非常小的..所涉及到的詞大約是10萬左右.
* 基本分詞速度非常快.在macAir上.能到每秒300w字每秒.同時準(zhǔn)確率也很高.但是對于新詞他的功能十分有限
* @param content
*/
public static void baseAnay(String content) {
Result result = BaseAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
System.out.println("result:" + result);
}
/**
* 精準(zhǔn)分詞
* 它在易用性,穩(wěn)定性.準(zhǔn)確性.以及分詞效率上.都取得了一個不錯的平衡.
* @param content
*/
public static void toAnay(String content){
Result result = ToAnalysis.parse(content);
System.out.println("result:" + result);
}
/**
* nlp分詞(單條新聞處理7秒)
* 可以識別出未登錄詞.但是它也有它的缺點.速度比較慢.穩(wěn)定性差.ps:我這里說的慢僅僅是和自己的其他方式比較.應(yīng)該是40w字每秒的速度吧.
* 個人覺得nlp的適用方式.1.語法實體名抽取.未登錄詞整理.只要是對文本進行發(fā)現(xiàn)分析等工作
* 會把企業(yè)分開
* @param content
*/
public static void nlpAnay(String content){
Result result = NlpAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
System.out.println("result:" + result);
List<Term> terms = result.getTerms();
for (Term term : terms) {
String name = term.getName();
String nature = term.getNatureStr();
if (nature.equals("nt") || nature.equals("nr")) {
System.out.println("------------------");
System.out.println("getName:" + term.getName());
System.out.println("getNatureStr:" + term.getNatureStr());
}
}
}
/**
* 篩除HTML標(biāo)簽
* @param htmlStr
* @return
*/
public static String delHTMLTag(String htmlStr){
String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/script>"; //定義script的正則表達式
String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>"; //定義style的正則表達式
String regEx_html="<[^>]+>"; //定義HTML標(biāo)簽的正則表達式
Pattern p_script=Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
Matcher m_script=p_script.matcher(htmlStr);
htmlStr=m_script.replaceAll(""); //過濾script標(biāo)簽
Pattern p_style=Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
Matcher m_style=p_style.matcher(htmlStr);
htmlStr=m_style.replaceAll(""); //過濾style標(biāo)簽
Pattern p_html=Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
Matcher m_html=p_html.matcher(htmlStr);
htmlStr=m_html.replaceAll(""); //過濾html標(biāo)簽
return htmlStr.trim(); //返回文本字符串
}
}
hanlp的使用
1. maven添加依賴
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.7.1</version>
</dependency>
2. 動態(tài)添加詞
/**
* 新增詞
*/
public static void addWord(String word, NatureEnum nature) {
logger.info("==== addWord@word:{},nature:{},weight:{} ====", word, nature.getNature(), nature.getWeight());
if (!StringUtils.isBlank(word) && !word.equals("null")) {
//大小括號問題
if (word.contains("(") || word.contains(")")) {
CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
}else if (word.contains("(") || word.contains(")")) {
CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
}
CustomDictionary.insert(word, nature.getNature());
}else {
logger.warn("==== addWord@ word({})為空 ====", word);
}
}
3. 動態(tài)刪除詞
/**
* 刪除詞
* @param forest
* @param word
*/
public static void deleteWord(String word) {
logger.info("==== deleteWord@word:{} ====", word);
if (!StringUtils.isBlank(word)) {
CustomDictionary.remove(word);
}else {
logger.warn("==== deleteWord@word為空({}) ====", word);
}
}
4. 使用
/**
* 分詞
* @param content
* @param forests
* ToAnalysis精準(zhǔn)分詞
* BaseAnalysis基礎(chǔ)分詞
*/
public static SegmentResult segment(String content) {
logger.info("==== segment@content:{} ====", content);
SegmentResult segmentResult = new SegmentResult();
List<Term> terms = HanLP.segment(content);
Set<String> companySet = new HashSet<String>();
for (Term term : terms) {
String name = term.word;
String nature = term.nature.toString();
if (nature.equals(NatureEnum.Company.getNature())) {
companySet.add(name);
}
}
segmentResult.setCompanys(new ArrayList<String>(companySet));
logger.info("==== segment@分詞結(jié)果:{},提取結(jié)果:{} ====", terms.toString(), segmentResult.toString());
return segmentResult;
}
5. 自定義詞典文件
詞典文件格式如下,依次是 詞艳狐、詞性定硝、權(quán)重
word nature weight
需要下載hanlp的data及hanlp.properties
https://github.com/hankcs/HanLP
data文件夾如下
image
hanlp.properties如下
#本配置文件中的路徑的根目錄,根目錄+其他路徑=完整路徑(支持相對路徑毫目,請參考:https://github.com/hankcs/HanLP/pull/254)
#Windows用戶請注意蔬啡,路徑分隔符統(tǒng)一使用/
root=/Users/FengZhen/Desktop/accumulate/分詞/HanLP/
#好了,以上為唯一需要修改的部分镀虐,以下配置項按需反注釋編輯箱蟆。
#核心詞典路徑
#CoreDictionaryPath=data/dictionary/CoreNatureDictionary.txt
#2元語法詞典路徑
#BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.txt
#自定義詞典路徑,用;隔開多個自定義詞典刮便,空格開頭表示在同一個目錄空猜,使用“文件名 詞性”形式則表示這個詞典的詞性默認(rèn)是該詞性。優(yōu)先級遞減恨旱。
#所有詞典統(tǒng)一使用UTF-8編碼辈毯,每一行代表一個單詞,格式遵從[單詞] [詞性A] [A的頻次] [詞性B] [B的頻次] ... 如果不填詞性則表示采用詞典的默認(rèn)詞性搜贤。
CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; Company.txt company; 現(xiàn)代漢語補充詞庫.txt; 全國地名大全.txt ns; 人名詞典.txt; 機構(gòu)名詞典.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf;
#停用詞詞典路徑
#CoreStopWordDictionaryPath=data/dictionary/stopwords.txt
#同義詞詞典路徑
#CoreSynonymDictionaryDictionaryPath=data/dictionary/synonym/CoreSynonym.txt
#人名詞典路徑
#PersonDictionaryPath=data/dictionary/person/nr.txt
#人名詞典轉(zhuǎn)移矩陣路徑
#PersonDictionaryTrPath=data/dictionary/person/nr.tr.txt
#繁簡詞典根目錄
#tcDictionaryRoot=data/dictionary/tc
#HMM分詞模型
#HMMSegmentModelPath=data/model/segment/HMMSegmentModel.bin
#分詞結(jié)果是否展示詞性
#ShowTermNature=true
#IO適配器谆沃,實現(xiàn)com.hankcs.hanlp.corpus.io.IIOAdapter接口以在不同的平臺(Hadoop、Redis等)上運行HanLP
#默認(rèn)的IO適配器如下仪芒,該適配器是基于普通文件系統(tǒng)的唁影。
#IOAdapter=com.hankcs.hanlp.corpus.io.FileIOAdapter
#感知機詞法分析器
#PerceptronCWSModelPath=data/model/perceptron/pku199801/cws.bin
#PerceptronPOSModelPath=data/model/perceptron/pku199801/pos.bin
#PerceptronNERModelPath=data/model/perceptron/pku199801/ner.bin
#CRF詞法分析器
#CRFCWSModelPath=data/model/crf/pku199801/cws.txt
#CRFPOSModelPath=data/model/crf/pku199801/pos.txt
#CRFNERModelPath=data/model/crf/pku199801/ner.txt
#更多配置項請參考 https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/HanLP.java#L59 自行添加
注意
:
1.hanlp.properties中的root路徑為本地data文件夾的父級路徑
2.準(zhǔn)備好的詞典文件可直接放入 data/dictionary/custom/下耕陷,然后再hanlp.properties中的 CustomDictionaryPath后添加該詞典文件名即可,如果不想在詞典文件中指定詞性据沈,也可在CustomDictionaryPath指定名字的同時哟沫,在后邊空格指定詞性。如上Company.txt company
3.在調(diào)用分詞方法時卓舵,hanlp會去自動加載自定義添加的詞典南用。速度比較慢,100w需要2m30s
4.自定義詞典文件更新時掏湾,需要將data/dictionary/custom/CustomDictionary.txt.bin刪掉裹虫。
Jieba的使用
1. 環(huán)境準(zhǔn)備
需要Python環(huán)境,需要pip
2. 安裝jieba
sudo pip install jieba
3. 使用
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網(wǎng)易杭研大廈") # 默認(rèn)是精確模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業(yè)于中國科學(xué)院計算所融击,后在日本京都大學(xué)深造") # 搜索引擎模式
print(", ".join(seg_list))
4.自定義詞典
# encoding=utf-8
import jieba
import jieba.posseg as pseg
import time
print("start-time" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
file_name = "/home/jenkins/fz/segment/jieba/data/Company.txt"
jieba.load_userdict(file_name) # file_name 為文件類對象或自定義詞典的路徑
print("end-time" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
seg_list = jieba.cut("北京尚伯樂文化發(fā)展有限公司")
print("custom dic: " + "/ ".join(seg_list))
seg_list = pseg.cut(content) #帶詞性
for seg in seg_list:
print(seg)
Done