支持中文分詞(N-最短路分詞、CRF分詞、索引分詞、用戶自定義詞典、詞性標註),命名實體識別(中國人名、音譯人名、日本人名、地名、實體機構名識別),關鍵詞提取,自動摘要,短語提取,拼音轉換,簡繁轉換,文本推薦,依存句法分析(MaxEnt依存句法分析、CRF依存句法分析)。提供Lucene插件,兼容Lucene4.x。html
漢語言處理包java
HanLP是由一系列模型與算法組成的Java工具包,目標是促進天然語言處理在生產環境中的應用。HanLP具有功能完善、性能高效、架構清晰、語料時新、可自定義的特色。git
HanLP提供下列功能:程序員
1 中文分詞 2 3 最短路分詞 4 5 N-最短路分詞 6 7 CRF分詞 8 9 索引分詞 10 11 極速詞典分詞 12 13 用戶自定義詞典 14 15 詞性標註 16 17 命名實體識別 18 19 中國人名識別 20 21 音譯人名識別 22 23 日本人名識別 24 25 地名識別 26 27 實體機構名識別 28 29 關鍵詞提取 30 31 TextRank關鍵詞提取 32 33 自動摘要 34 35 TextRank自動摘要 36 37 短語提取 38 39 基於互信息和左右信息熵的短語提取 40 41 拼音轉換 42 43 多音字 44 45 聲母 46 47 韻母 48 49 聲調 50 51 簡繁轉換 52 53 繁體中文分詞 54 55 簡繁分歧詞 56 57 文本推薦 58 59 語義推薦 60 61 拼音推薦 62 63 字詞推薦 64 65 依存句法分析 66 67 MaxEnt依存句法分析 68 69 CRF依存句法分析 70 71 語料庫工具 72 73 分詞語料預處理 74 75 詞頻詞性詞典制做 76 77 BiGram統計 78 79 詞共現統計 80 81 CoNLL語料預處理 82 83 CoNLL UA/LA/DA評測工具
在提供豐富功能的同時,HanLP內部模塊堅持低耦合、模型堅持惰性加載、服務堅持靜態提供、詞典堅持明文發佈,使用很是方便,同時自帶一些語料處理工具,幫助用戶訓練本身的語料。github
HanLP項目主頁:https://github.com/hankcs/HanLP 算法
HanLP下載地址:https://github.com/hankcs/HanLP/releases 編程
內存120MB以上(-Xms120m -Xmx120m -Xmn64m),標準數據包(35萬核心詞庫+默認用戶詞典),分詞測試正常。數組
所有詞典和模型都是惰性加載的,若是你只用拼音轉換的話,則只加載拼音詞典,未加載的詞典至關於不存在,不佔內存。同理,模型也是如此。緩存
爲了方便用戶,特提供內置了數據包的Portable版,只需在pom.xml加入:網絡
1 <dependency> 2 <groupId>com.hankcs</groupId> 3 <artifactId>hanlp</artifactId> 4 <version>portable-1.2.4</version> 5 </dependency>
零配置,便可使用基本功能(除CRF分詞、依存句法分析外的所有功能)。連Maven都懶得用的話,能夠直接下載portable版的jar。
若是用戶有自定義的需求,能夠參考方式二,使用hanlp.properties進行配置。
目前Portable體積僅僅5.7MB,做爲代價,使用的是1998年的小詞典,對現代漢語的支持有限;因此仍是建議外掛下面的數據包比較好。
HanLP將數據與程序分離,給予用戶自定義的自由。
數據包 | 功能 | 體積(MB) |
---|---|---|
data.zip | 所有詞典,所有模型 | 280(注:分詞詞典大約40MB,主要是句法分析模型佔體積,能夠自行刪除。) |
在GitHub的release頁面Ctrl+F搜索data便可,下載後解壓到任意目錄,接下來經過配置文件告訴HanLP數據包的位置。
HanLP中的數據分爲詞典和模型,其中詞典是詞法分析必需的,模型是句法分析必需的。
1 data 2 │ 3 ├─dictionary 4 └─model
用戶能夠自行增刪替換,若是不須要句法分析功能的話,隨時能夠刪除model文件夾。
示例配置文件:hanlp.properties
配置文件的做用是告訴HanLP數據包的位置,只需修改第一行
root=usr/home/HanLP/
爲data的父目錄便可,好比data目錄是/Users/hankcs/Documents/data
,那麼root=/Users/hankcs/Documents/
。
若是選用mini詞典的話,則須要修改配置文件:
CoreDictionaryPath=data/dictionary/CoreNatureDictionary.mini.txt
BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.mini.txt
最後將HanLP.properties放入classpath便可,對於Eclipse,通常是:
1 $Project/bin
Web項目的話能夠放在以下位置:
1 $Project/WEB-INF/classes
對於任何項目,均可以放到src目錄下,編譯時IDE會自動將其複製到classpath中。
若是放置不當,HanLP會智能提示當前環境下的合適路徑,而且嘗試從項目根目錄讀取數據集。
HanLP幾乎全部的功能均可以經過工具類HanLP
快捷調用,當你想不起來調用方法時,只需鍵入HanLP.
,IDE應當會給出提示,並展現HanLP完善的文檔。
推薦用戶始終經過工具類HanLP
調用,這麼作的好處是,未來HanLP升級後,用戶無需修改調用代碼。
全部Demo都位於com.hankcs.demo下。
1 System.out.println(HanLP.segment("你好,歡迎使用HanLP漢語處理包!"));
1 List<Term> termList = StandardTokenizer.segment("商品和服務"); 2 System.out.println(termList);
說明
HanLP中有一系列「開箱即用」的靜態分詞器,以Tokenizer
結尾,在接下來的例子中會繼續介紹。
HanLP.segment
實際上是對StandardTokenizer.segment
的包裝。
分詞結果包含詞性,每一個詞性的意思請查閱《HanLP詞性標註集》。
算法詳解
1 List<Term> termList = NLPTokenizer.segment("中國科學院計算技術研究所的宗成慶教授正在教授天然語言處理課程"); 2 System.out.println(termList);
說明
NLP分詞NLPTokenizer
會執行所有命名實體識別和詞性標註。
1 List<Term> termList = IndexTokenizer.segment("主副食品"); 2 for (Term term : termList) 3 { 4 System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]"); 5 }
說明
索引分詞IndexTokenizer
是面向搜索引擎的分詞器,可以對長詞全切分,另外經過term.offset
能夠獲取單詞在文本中的偏移量。
1 Segment nShortSegment = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true); 2 Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true); 3 String[] testCase = new String[]{ 4 "今天,劉志軍案的關鍵人物,山西女商人丁書苗在市二中院出庭受審。", 5 "劉喜傑石國祥會見吳亞琴先進事蹟報告團成員", 6 }; 7 for (String sentence : testCase) 8 { 9 System.out.println("N-最短分詞:" + nShortSegment.seg(sentence) + "\n最短路分詞:" + shortestSegment.seg(sentence)); 10 }
說明
N最短路分詞器NShortSegment
比最短路分詞器慢,可是效果稍微好一些,對命名實體識別能力更強。
通常場景下最短路分詞的精度已經足夠,並且速度比N最短路分詞器快幾倍,請酌情選擇。
算法詳解
1 /** 2 * CRF分詞(在最新訓練的未壓縮100MB模型下,可以取得較好的效果,能夠投入生產環境) 3 * 4 * @author hankcs 5 */ 6 public class DemoCRFSegment 7 { 8 public static void main(String[] args) 9 { 10 HanLP.Config.ShowTermNature = false; // 關閉詞性顯示 11 Segment segment = new CRFSegment(); 12 String[] sentenceArray = new String[] 13 { 14 "HanLP是由一系列模型與算法組成的Java工具包,目標是普及天然語言處理在生產環境中的應用。", 15 "鐵桿部隊憤怒情緒集結 馬英九腹背受敵", // 繁體無壓力 16 "馬英九回應連勝文「丐幫說」:稱黨內同志談話應謹慎", 17 "高錳酸鉀,強氧化劑,紫紅色晶體,可溶於水,遇乙醇即被還原。經常使用做消毒劑、水淨化劑、氧化劑、漂白劑、毒氣吸取劑、二氧化碳精製劑等。", // 專業名詞有必定辨識能力 18 "《夜晚的骰子》經過描述淺草的舞女在暗夜中扔骰子的情景,寄託了做者對庶民生活區的情感", // 非新聞語料 19 "這個像是真的[委屈]前面那個打扮太江戶了,一點不上品...@hankcs", // 微博 20 "鼎泰豐的小籠一點味道也沒有...每樣都淡淡的...淡淡的,哪有食堂2A的好次", 21 "克里斯蒂娜·克羅爾說:不,我不是虎媽。我全家都熱愛音樂,我也鼓勵他們這麼作。", 22 "今日APPS:Sago Mini Toolbox培養孩子動手能力", 23 "財政部副部長王保安調任國家統計局黨組書記", 24 "2.34米男子娶1.53米女粉絲 稱夫妻生活沒問題", 25 "你看過穆赫蘭道嗎", 26 "樂視超級手機可否承載賈布斯的生態夢" 27 }; 28 for (String sentence : sentenceArray) 29 { 30 List<Term> termList = segment.seg(sentence); 31 System.out.println(termList); 32 } 33 } 34 }
說明
CRF對新詞有很好的識別能力,可是沒法利用自定義詞典。
算法詳解
1 /** 2 * 演示極速分詞,基於AhoCorasickDoubleArrayTrie實現的詞典分詞,適用於「高吞吐量」「精度通常」的場合 3 * @author hankcs 4 */ 5 public class DemoHighSpeedSegment 6 { 7 public static void main(String[] args) 8 { 9 String text = "江西鄱陽湖乾枯,中國最大淡水湖變成大草原"; 10 System.out.println(SpeedTokenizer.segment(text)); 11 long start = System.currentTimeMillis(); 12 int pressure = 1000000; 13 for (int i = 0; i < pressure; ++i) 14 { 15 SpeedTokenizer.segment(text); 16 } 17 double costTime = (System.currentTimeMillis() - start) / (double)1000; 18 System.out.printf("分詞速度:%.2f字每秒", text.length() * pressure / costTime); 19 } 20 }
說明
極速分詞是詞典最長分詞,速度極其快,精度通常。
在i7上跑出了2000萬字每秒的速度。
算法詳解
1 public class DemoCustomDictionary 2 { 3 public static void main(String[] args) 4 { 5 // 動態增長 6 CustomDictionary.add("攻城獅"); 7 // 強行插入 8 CustomDictionary.insert("白富美", "nz 1024"); 9 // 刪除詞語(註釋掉試試) 10 // CustomDictionary.remove("攻城獅"); 11 System.out.println(CustomDictionary.add("單身狗", "nz 1024 n 1")); 12 System.out.println(CustomDictionary.get("單身狗")); 13 14 String text = "攻城獅逆襲單身狗,迎娶白富美,走上人生巔峯"; // 怎麼可能噗哈哈! 15 16 // DoubleArrayTrie分詞 17 final char[] charArray = text.toCharArray(); 18 CustomDictionary.parseText(charArray, new AhoCorasickDoubleArrayTrie.IHit<CoreDictionary.Attribute>() 19 { 20 @Override 21 public void hit(int begin, int end, CoreDictionary.Attribute value) 22 { 23 System.out.printf("[%d:%d]=%s %s\n", begin, end, new String(charArray, begin, end - begin), value); 24 } 25 }); 26 // 首字哈希以後二分的trie樹分詞 27 BaseSearcher searcher = CustomDictionary.getSearcher(text); 28 Map.Entry entry; 29 while ((entry = searcher.next()) != null) 30 { 31 System.out.println(entry); 32 } 33 34 // 標準分詞 35 System.out.println(HanLP.segment(text)); 36 37 // Note:動態增刪不會影響詞典文件 38 // 目前CustomDictionary使用DAT儲存詞典文件中的詞語,用BinTrie儲存動態加入的詞語,前者性能高,後者性能低 39 // 之因此保留動態增刪功能,一方面是歷史遺留特性,另外一方面是調試用;將來可能會去掉動態增刪特性。 40 }
說明
CustomDictionary
是一份全局的用戶自定義詞典,能夠隨時增刪,影響所有分詞器。
另外能夠在任何分詞器中關閉它。經過代碼動態增刪不會保存到詞典文件。
追加詞典
CustomDictionary
主詞典文本路徑是data/dictionary/custom/CustomDictionary.txt
,用戶能夠在此增長本身的詞語(不推薦);也能夠單獨新建一個文本文件,經過配置文件CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 個人詞典.txt;
來追加詞典(推薦)。
始終建議將相同詞性的詞語放到同一個詞典文件裏,便於維護和分享。
詞典格式
每一行表明一個單詞,格式聽從[單詞] [詞性A] [A的頻次] [詞性B] [B的頻次] ...
若是不填詞性則表示採用詞典的默認詞性。
詞典的默認詞性默認是名詞n,能夠經過配置文件修改:全國地名大全.txt ns;
若是詞典路徑後面空格緊接着詞性,則該詞典默認是該詞性。
關於用戶詞典的更多信息請參考詞典說明一章。
算法詳解
1 String[] testCase = new String[]{ 2 "簽約儀式前,秦光榮、李紀恆、仇和等一同會見了參加簽約的企業家。", 3 "王國強、高峯、汪洋、張朝陽光着頭、韓寒、小四", 4 "張浩和胡健康復員回家了", 5 "王總和小麗結婚了", 6 "編劇邵鈞林和稽道青說", 7 "這裏有關天培的有關事蹟", 8 "龔學平等領導,鄧穎超生前", 9 }; 10 Segment segment = HanLP.newSegment().enableNameRecognize(true); 11 for (String sentence : testCase) 12 { 13 List<Term> termList = segment.seg(sentence); 14 System.out.println(termList); 15 }
說明
目前分詞器基本上都默認開啓了中國人名識別,好比HanLP.segment()
接口中使用的分詞器等等,用戶沒必要手動開啓;上面的代碼只是爲了強調。
有必定的誤命中率,好比誤命中關鍵年
,則能夠經過在data/dictionary/person/nr.txt
加入一條關鍵年 A 1
來排除關鍵年
做爲人名的可能性,也能夠將關鍵年
做爲新詞登記到自定義詞典中。
若是你經過上述辦法解決了問題,歡迎向我提交pull request,詞典也是寶貴的財富。
算法詳解
1 String[] testCase = new String[]{ 2 "一桶冰水當頭倒下,微軟的比爾蓋茨、Facebook的扎克伯格跟桑德博格、亞馬遜的貝索斯、蘋果的庫克全都不惜溼身入鏡,這些硅谷的科技人,飛蛾撲火似地犧牲演出,其實全爲了慈善。", 3 "世界上最長的姓名是簡森·喬伊·亞歷山大·比基·卡利斯勒·達夫·埃利奧特·福克斯·伊維魯莫·馬爾尼·梅爾斯·帕特森·湯普森·華萊士·普雷斯頓。", 4 }; 5 Segment segment = HanLP.newSegment().enableTranslatedNameRecognize(true); 6 for (String sentence : testCase) 7 { 8 List<Term> termList = segment.seg(sentence); 9 System.out.println(termList); 10 }
說明
目前分詞器基本上都默認開啓了音譯人名識別,用戶沒必要手動開啓;上面的代碼只是爲了強調。
算法詳解
1 String[] testCase = new String[]{ 2 "北川景子參演了林詣彬導演的《速度與激情3》", 3 "林志玲亮相網友:肯定不是波多野結衣?", 4 }; 5 Segment segment = HanLP.newSegment().enableJapaneseNameRecognize(true); 6 for (String sentence : testCase) 7 { 8 List<Term> termList = segment.seg(sentence); 9 System.out.println(termList); 10 }
說明
目前標準分詞器默認關閉了日本人名識別,用戶須要手動開啓;這是由於日本人名的出現頻率較低,可是又消耗性能。
算法詳解
1 String[] testCase = new String[]{ 2 "武勝縣新學鄉政府大樓門前鑼鼓喧天", 3 "藍翔給寧夏固原市彭陽縣紅河鎮黑牛溝村捐贈了挖掘機", 4 }; 5 Segment segment = HanLP.newSegment().enablePlaceRecognize(true); 6 for (String sentence : testCase) 7 { 8 List<Term> termList = segment.seg(sentence); 9 System.out.println(termList); 10 }
說明
目前標準分詞器都默認關閉了地名識別,用戶須要手動開啓;這是由於消耗性能,其實多數地名都收錄在核心詞典和用戶自定義詞典中。
在生產環境中,能靠詞典解決的問題就靠詞典解決,這是最高效穩定的方法。
算法詳解
1 String[] testCase = new String[]{ 2 "我在上海林原科技有限公司兼職工做,", 3 "我常常在臺川喜宴餐廳吃飯,", 4 "偶爾去地中海影城看電影。", 5 }; 6 Segment segment = HanLP.newSegment().enableOrganizationRecognize(true); 7 for (String sentence : testCase) 8 { 9 List<Term> termList = segment.seg(sentence); 10 System.out.println(termList); 11 }
說明
目前分詞器默認關閉了機構名識別,用戶須要手動開啓;這是由於消耗性能,其實經常使用機構名都收錄在核心詞典和用戶自定義詞典中。
HanLP的目的不是演示動態識別,在生產環境中,能靠詞典解決的問題就靠詞典解決,這是最高效穩定的方法。
算法詳解
1 String content = "程序員(英文Programmer)是從事程序開發、維護的專業人員。通常將程序員分爲程序設計人員和程序編碼人員,但二者的界限並不很是清楚,特別是在中國。軟件從業人員分爲初級程序員、高級程序員、系統分析員和項目經理四大類。"; 2 List<String> keywordList = HanLP.extractKeyword(content, 5); 3 System.out.println(keywordList);
說明
內部採用TextRankKeyword
實現,用戶能夠直接調用TextRankKeyword.getKeywordList(document, size)
算法詳解
1 String document = "算法可大體分爲基本算法、數據結構的算法、數論算法、計算幾何的算法、圖的算法、動態規劃以及數值分析、加密算法、排序算法、檢索算法、隨機化算法、並行算法、厄米變形模型、隨機森林算法。\n" + 2 "算法能夠寬泛的分爲三類,\n" + 3 "一,有限的肯定性算法,這類算法在有限的一段時間內終止。他們可能要花很長時間來執行指定的任務,但仍將在必定的時間內終止。這類算法得出的結果常取決於輸入值。\n" + 4 "二,有限的非肯定算法,這類算法在有限的時間內終止。然而,對於一個(或一些)給定的數值,算法的結果並非惟一的或肯定的。\n" + 5 "三,無限的算法,是那些因爲沒有定義終止定義條件,或定義的條件沒法由輸入的數據知足而不終止運行的算法。一般,無限算法的產生是因爲未能肯定的定義終止條件。"; 6 List<String> sentenceList = HanLP.extractSummary(document, 3); 7 System.out.println(sentenceList);
說明
內部採用TextRankSentence
實現,用戶能夠直接調用TextRankSentence.getTopSentenceList(document, size)
。
算法詳解
1 String text = "算法工程師\n" + 2 "算法(Algorithm)是一系列解決問題的清晰指令,也就是說,可以對必定規範的輸入,在有限時間內得到所要求的輸出。" + 3 "若是一個算法有缺陷,或不適合於某個問題,執行這個算法將不會解決這個問題。不一樣的算法可能用不一樣的時間、" + 4 "空間或效率來完成一樣的任務。一個算法的優劣能夠用空間複雜度與時間複雜度來衡量。算法工程師就是利用算法處理事物的人。\n" + 5 "\n" + 6 "1職位簡介\n" + 7 "算法工程師是一個很是高端的職位;\n" + 8 "專業要求:計算機、電子、通訊、數學等相關專業;\n" + 9 "學歷要求:本科及其以上的學歷,大多數是碩士學歷及其以上;\n" + 10 "語言要求:英語要求是熟練,基本上能閱讀國外專業書刊;\n" + 11 "必須掌握計算機相關知識,熟練使用仿真工具MATLAB等,必須會一門編程語言。\n" + 12 "\n" + 13 "2研究方向\n" + 14 "視頻算法工程師、圖像處理算法工程師、音頻算法工程師 通訊基帶算法工程師\n" + 15 "\n" + 16 "3目前國內外情況\n" + 17 "目前國內從事算法研究的工程師很多,可是高級算法工程師卻不多,是一個很是緊缺的專業工程師。" + 18 "算法工程師根據研究領域來分主要有音頻/視頻算法處理、圖像技術方面的二維信息算法處理和通訊物理層、" + 19 "雷達信號處理、生物醫學信號處理等領域的一維信息算法處理。\n" + 20 "在計算機音視頻和圖形圖像技術等二維信息算法處理方面目前比較先進的視頻處理算法:機器視覺成爲此類算法研究的核心;" + 21 "另外還有2D轉3D算法(2D-to-3D conversion),去隔行算法(de-interlacing),運動估計運動補償算法" + 22 "(Motion estimation/Motion Compensation),去噪算法(Noise Reduction),縮放算法(scaling)," + 23 "銳化處理算法(Sharpness),超分辨率算法(Super Resolution),手勢識別(gesture recognition),人臉識別(face recognition)。\n" + 24 "在通訊物理層等一維信息領域目前經常使用的算法:無線領域的RRM、RTT,傳送領域的調製解調、信道均衡、信號檢測、網絡優化、信號分解等。\n" + 25 "另外數據挖掘、互聯網搜索算法也成爲當今的熱門方向。\n" + 26 "算法工程師逐漸往人工智能方向發展。"; 27 List<String> phraseList = HanLP.extractPhrase(text, 5); 28 System.out.println(phraseList);
說明
內部採用MutualInformationEntropyPhraseExtractor
實現,用戶能夠直接調用MutualInformationEntropyPhraseExtractor..extractPhrase(text, size)
。
算法詳解
1 /** 2 * 漢字轉拼音 3 * @author hankcs 4 */ 5 public class DemoPinyin 6 { 7 public static void main(String[] args) 8 { 9 String text = "重載不是重任"; 10 List<Pinyin> pinyinList = HanLP.convertToPinyinList(text); 11 System.out.print("原文,"); 12 for (char c : text.toCharArray()) 13 { 14 System.out.printf("%c,", c); 15 } 16 System.out.println(); 17 System.out.print("拼音(數字音調),"); 18 for (Pinyin pinyin : pinyinList) 19 { 20 System.out.printf("%s,", pinyin); 21 } 22 System.out.println(); 23 System.out.print("拼音(符號音調),"); 24 for (Pinyin pinyin : pinyinList) 25 { 26 System.out.printf("%s,", pinyin.getPinyinWithToneMark()); 27 } 28 System.out.println(); 29 System.out.print("拼音(無音調),"); 30 for (Pinyin pinyin : pinyinList) 31 { 32 System.out.printf("%s,", pinyin.getPinyinWithoutTone()); 33 } 34 System.out.println(); 35 System.out.print("聲調,"); 36 for (Pinyin pinyin : pinyinList) 37 { 38 System.out.printf("%s,", pinyin.getTone()); 39 } 40 System.out.println(); 41 System.out.print("聲母,"); 42 for (Pinyin pinyin : pinyinList) 43 { 44 System.out.printf("%s,", pinyin.getShengmu()); 45 } 46 System.out.println(); 47 System.out.print("韻母,"); 48 for (Pinyin pinyin : pinyinList) 49 { 50 System.out.printf("%s,", pinyin.getYunmu()); 51 } 52 System.out.println(); 53 System.out.print("輸入法頭,"); 54 for (Pinyin pinyin : pinyinList) 55 { 56 System.out.printf("%s,", pinyin.getHead()); 57 } 58 System.out.println(); 59 } 60 }
說明
HanLP不只支持基礎的漢字轉拼音,還支持聲母、韻母、音調、音標和輸入法首字母首聲母功能。
HanLP可以識別多音字,也能給繁體中文注拼音。
最重要的是,HanLP採用的模式匹配升級到AhoCorasickDoubleArrayTrie
,性能大幅提高,可以提供毫秒級的響應速度!
算法詳解
1 /** 2 * 簡繁轉換 3 * @author hankcs 4 */ 5 public class DemoTraditionalChinese2SimplifiedChinese 6 { 7 public static void main(String[] args) 8 { 9 System.out.println(HanLP.convertToTraditionalChinese("用筆記本電腦寫程序")); 10 System.out.println(HanLP.convertToSimplifiedChinese("「以後等妳當上皇后,就能買士多啤梨慶祝了」")); 11 } 12 }
說明
HanLP可以識別簡繁分歧詞,好比打印機=印表機
。許多簡繁轉換工具不能區分「之後」「皇后」中的兩個「後」字,HanLP能夠。
算法詳解
/** * 文本推薦(句子級別,從一系列句子中挑出與輸入句子最類似的那一個) * @author hankcs */ public class DemoSuggester { public static void main(String[] args) { Suggester suggester = new Suggester(); String[] titleArray = ( "威廉王子發表演說 呼籲保護野生動物\n" + "《時代》年度人物最終入圍名單出爐 普京馬雲入選\n" + "「黑格比」橫掃菲:菲吸收「海燕」經驗及早疏散\n" + "日本保密法將正式生效 日媒指其損害國民知情權\n" + "英報告說空氣污染帶來「公共健康危機」" ).split("\\n"); for (String title : titleArray) { suggester.addSentence(title); } System.out.println(suggester.suggest("發言", 1)); // 語義 System.out.println(suggester.suggest("危機公共", 1)); // 字符 System.out.println(suggester.suggest("mayun", 1)); // 拼音 } }
說明
在搜索引擎的輸入框中,用戶輸入一個詞,搜索引擎會聯想出最合適的搜索詞,HanLP實現了相似的功能。
能夠動態調節每種識別器的權重
/** * 語義距離 * @author hankcs */ public class DemoWordDistance { public static void main(String[] args) { String[] wordArray = new String[] { "香蕉", "蘋果", "白菜", "水果", "蔬菜", "自行車", "公交車", "飛機", "買", "賣", "購入", "新年", "春節", "丟失", "補辦", "辦理", "送給", "尋找", "孩子", "教室", "教師", "會計", }; for (String a : wordArray) { for (String b : wordArray) { System.out.println(a + "\t" + b + "\t之間的距離是\t" + CoreSynonymDictionary.distance(a, b)); } } } }
說明
設想的應用場景是搜索引擎對詞義的理解,詞與詞並不僅存在「同義詞」與「非同義詞」的關係,就算是同義詞,它們之間的意義也是有微妙的差異的。
算法
爲每一個詞分配一個語義ID,詞與詞的距離經過語義ID的差獲得。語義ID經過《同義詞詞林擴展版》計算而來。
/** * 依存句法解析 * @author hankcs */ public class DemoDependencyParser { public static void main(String[] args) { System.out.println(HanLP.parseDependency("把市場經濟奉行的等價交換原則引入黨的生活和國家機關政務活動中")); } }
說明
內部採用MaxEntDependencyParser
實現,用戶能夠直接調用MaxEntDependencyParser.compute(sentence)
也能夠調用基於隨機條件場的依存句法分析器CRFDependencyParser.compute(sentence)
在封閉測試集上準確率有90%以上,但在開放測試集上則不理想。
算法詳解
本章詳細介紹HanLP中的詞典格式,知足用戶自定義的須要。HanLP中有許多詞典,它們的格式都是類似的,形式都是文本文檔,隨時能夠修改。
詞典分爲詞頻詞性詞典和詞頻詞典。
詞頻詞性詞典
每一行表明一個單詞,格式聽從[單詞] [詞性A] [A的頻次] [詞性B] [B的頻次] ...
。
詞頻詞典
每一行表明一個單詞,格式聽從[單詞] [單詞的頻次]
。
每一行的分隔符爲空格符或製表符
少數詞典有本身的專用格式,好比同義詞詞典兼容《同義詞詞林擴展版》的文本格式,而轉移矩陣詞典則是一個csv表格。
下文主要介紹通用詞典,如不註明,詞典特指通用詞典。
Trie樹(字典樹)是HanLP中使用最多的數據結構,爲此,我實現了通用的Trie樹,支持泛型、遍歷、儲存、載入。
用戶自定義詞典採用AhoCorasickDoubleArrayTrie和二分Trie樹儲存,其餘詞典採用基於雙數組Trie樹(DoubleArrayTrie)實現的AC自動機AhoCorasickDoubleArrayTrie。
詞典有兩個形態:文本文件(filename.txt)和緩存文件(filename.txt.bin或filename.txt.trie.dat和filename.txt.trie.value)。
文本文件
採用明文儲存,UTF-8編碼,CRLF換行符。
緩存文件
就是一些二進制文件,一般在文本文件的文件名後面加上.bin表示。有時候是.trie.dat和.trie.value。後者是歷史遺留產物,分別表明trie樹的數組和值。
若是你修改了任何詞典,只有刪除緩存才能生效。
HanLP的核心詞典訓練自人民日報2014語料,語料不是完美的,總會存在一些錯誤。這些錯誤可能會致使分詞出現奇怪的結果,這時請打開調試模式排查問題:
核心詞性詞頻詞典
好比你在data/dictionary/CoreNatureDictionary.txt
中發現了一個不是詞的詞,或者詞性標註得明顯不對,那麼你能夠修改它,而後刪除緩存文件使其生效。
核心二元文法詞典
二元文法詞典data/dictionary/CoreNatureDictionary.ngram.txt
儲存的是兩個詞的接續,若是你發現不可能存在這種接續時,刪掉便可。
你也能夠添加你認爲合理的接續,可是這兩個詞必須同時在覈心詞典中才會生效。
命名實體識別詞典
基於角色標註的命名實體識別比較依賴詞典,因此詞典的質量大幅影響識別質量。
這些詞典的格式與原理都是相似的,請閱讀相應的文章或代碼修改它。
若是問題解決了,歡迎向我提交一個pull request,這是我在代碼庫中保留明文詞典的緣由,衆人拾柴火焰高!
Apache License Version 2.0
HanLP產品初始知識產權歸上海林原信息科技有限公司全部,任何人和企業能夠免費使用,能夠對產品、源代碼進行任何形式的修改,能夠打包在其餘產品中進行銷售。
任何使用了HanLP的所有或部分功能、詞典、模型的項目、產品或文章等形式的成果必須顯式註明HanLP及此項目主頁。
感謝下列優秀開源項目:
感謝NLP界各位學者老師的著做:
《基於角色標註的中國人名自動識別研究》張華平 劉羣
《基於層疊隱馬爾可夫模型的中文命名實體識別》俞鴻魁 張華平 劉羣 呂學強 施水才
《基於角色標註的中文機構名識別》俞鴻魁 張華平 劉羣
《基於最大熵的依存句法分析》 辛霄 範士喜 王軒 王曉龍
An Efficient Implementation of Trie Structures, JUN-ICHI AOE AND KATSUSHI MORIMOTO
TextRank: Bringing Order into Texts, Rada Mihalcea and Paul Tarau