1. 程式人生 > >字串分詞,字串詞語切割

字串分詞,字串詞語切割

 

基本分詞-BaseAnalysis

基本分詞是什麼

基本就是保證了最基本的分詞.詞語顆粒度最非常小的..所涉及到的詞大約是10萬左右.

基本分詞速度非常快.在macAir上.能到每秒300w字每秒.同時準確率也很高.但是對於新詞他的功能十分有限

基本分詞具有什麼功能

使用者自定義詞典 數字識別 人名識別 機構名識別 新詞發現
Χ Χ Χ Χ

一個簡單的使用方式

package demo;

import java.util.List;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.BaseAnalysis;
 
/**
 * @author liuchaojun
 * @date 2018-8-27 下午05:18:50
 */
public class Test {
	public static void main(String[] args) {
			List<Term> parse = BaseAnalysis.parse("大家新年好!");
			System.out.println(parse);
	}
}
 

執行結果

 

精準分詞-ToAnalysis

精準分詞是什麼

精準分詞是Ansj分詞的店長推薦款

它在易用性,穩定性.準確性.以及分詞效率上.都取得了一個不錯的平衡.

如果你初次賞識Ansj如果你想開箱即用.那麼就用這個分詞方式是不會錯的.

精準分詞具有什麼功能

使用者自定義詞典 數字識別 人名識別 機構名識別 新詞發現
Χ Χ

一個簡單的使用方式

/**
 * 
 */
package demo;

import java.util.List;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

/**
 * @author liuchaojun
 * @date 2018-9-26 下午01:47:23
 */
public class Test1 {
	public static void main(String[] args) {
		  List<Term> parse = ToAnalysis.parse("讓戰士們過一個歡樂祥和的新春佳節。");
		    System.out.println(parse);

	}
}

執行結果:

 

nlp分詞-NlpAnalysis

nlp分詞是什麼

nlp分詞是總能給你驚喜的一種分詞方式.

它可以識別出未登入詞.但是它也有它的缺點.速度比較慢.穩定性差.ps:我這裡說的慢僅僅是和自己的其他方式比較.應該是40w字每秒的速度吧.

個人覺得nlp的適用方式.1.語法實體名抽取.未登入詞整理.只要是對文字進行發現分析等工作

精準分詞具有什麼功能

使用者自定義詞典 數字識別 人名識別 機構名識別 新詞發現

一個簡單的使用方式

package demo;

import java.util.List;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.NlpAnalysis;

/**
 * @author liuchaojun
 * @date 2018-9-26 下午02:12:19
 */
public class Test3 {
	public static void main(String[] args) {
		   List<Term> parse = NlpAnalysis.parse("潔面儀配合潔面深層清潔毛孔 清潔鼻孔面膜碎覺使勁擠才能出一點點皺紋 臉頰毛孔修復的看不見啦 草莓鼻歷史遺留問題沒轍 臉和脖子差不多顏色的面板才是健康的 長期使用安全健康的比同齡人顯小五到十歲 28歲的妹子看看你們的魚尾紋");
		   System.out.println(parse);
	}
}

執行結果:

面向索引的分詞-IndexAnalysis

面向索引的分詞是什麼

面向索引的分詞。故名思議就是適合在lucene等文字檢索中用到的分詞。 主要考慮以下兩點

  • 召回率
    • 召回率是對分詞結果儘可能的涵蓋。比如對“上海虹橋機場南路” 召回結果是[上海/ns, 上海虹橋機場/nt, 虹橋/ns, 虹橋機場/nz, 機場/n, 南路/nr]
  • 準確率
    • 其實這和召回本身是具有一定矛盾性的Ansj的強大之處是很巧妙的避開了這兩個的衝突 。比如我們常見的歧義句“旅遊和服務”->對於一般保證召回 。大家會給出的結果是“旅遊 和服 服務” 對於ansj不存在跨term的分詞。意思就是。召回的詞只是針對精準分詞之後的結果的一個細分。比較好的解決了這個問題

基本分詞具有什麼功能

使用者自定義詞典 數字識別 人名識別 機構名識別 新詞發現
Χ Χ

一個簡單的使用方式

package demo;

import java.util.List;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.IndexAnalysis;

/**
 * @author liuchaojun
 * @date 2018-9-26 下午02:15:57
 */
public class Test4 {
	public static void main(String[] args) {
		List<Term> parse = IndexAnalysis.parse("上海虹橋機場");
		System.out.println(parse);
	}
}

執行結果:

使用者自定義詞典

Ansj的一個喜人的功能就是支援使用者自定義詞典.

詞典是基於tree_split專案來的.就是一個超級簡單.做過一些優化的tire樹結構.它具有使用靈活.記憶體佔用小等特點

Ansj目前支援以下的公戶自定義詞典的操作方式.

  • 從檔案中載入詞典
    • 配置檔案
    • 編碼路徑
  • 從記憶體操作詞典
    • 增加
    • 刪除
    • 修改

同時Ansj的使用者自定義詞典.支援多詞典.多層次的分詞.對於特定領域的分詞.就是一神器.O(∩_∩)O~

 

動態新增

直接看例子.這個功能其實在tree-split中就已經存在的.

說明:

1..刪除只能刪除使用者自定義詞典的詞.

2.對了分詞預設把大寫都轉換為小寫了.所以新增新詞的時候要求必須是小寫.

package demo;
import java.util.List;
import org.ansj.domain.Term;
import org.ansj.library.UserDefineLibrary;
import org.ansj.splitWord.analysis.ToAnalysis;
/**
 * @author liuchaojun
 * @date 2018-9-26 下午02:22:58 
 */
public class DynamicWordDemo {
	 public static void main(String[] args) {
	        // 增加新詞,中間按照'\t'隔開
	        UserDefineLibrary.insertWord("ansj中文分詞", "userDefine", 1000);
	        List<Term> terms = ToAnalysis.parse("我覺得Ansj中文分詞是一個不錯的系統!我是王婆!");
	        System.out.println("增加新詞例子:" + terms);
	        // 刪除詞語,只能刪除.使用者自定義的詞典.
	        UserDefineLibrary.removeWord("ansj中文分詞");
	        terms = ToAnalysis.parse("我覺得ansj中文分詞是一個不錯的系統!我是王婆!");
	        System.out.println("刪除使用者自定義詞典例子:" + terms);
	}
}

執行結果:

0

 

設定辭典路徑

關於ansj分詞使用者自定義詞典的路徑設定

第一種.正規方式

建立library.properties 中增加

#path of userLibrary
userLibrary=library/userLibrary/userLibrary.dic
ambiguityLibrary=/library/ambiguity.dic

第二種 在用詞典未載入前可以通過,程式碼方式方式來載入

MyStaticValue.userLibrary=[你的路徑]

第三種,呼叫api載入.在程式執行的任何時間都可以.動態價值

loadLibrary.loadLibrary(String path)方式載入

路徑可以是具體檔案也可以是一個目錄 如果是一個目錄.那麼會掃描目錄下的dic檔案自動加入詞典

 

 

歧義糾正辭典

很多時候.分詞發生歧異不是很好調整.使用者需要更強的規則來約束所以.ansj中增加了歧異消除的一個強規則方式

在library/ambiguity.dic

中你會看到如下內容

習近平    習近平    nr
李民工作    李民    nr    工作    vn
三個和尚    三個    m    和尚    n
的確定不    的確    d    定    v    不    v
大和尚    大    a    和尚    n
張三和    張三    nr    和    c

這裡例子告訴計算機

如果你發現 李民工作 ---> 李/民工/作 糾正為 --->李民/工作/ 這種型別..

第一列是識別串.第二列是分詞結果.奇數行是詞.偶數行是詞性.

ps:這個是優先分詞執行的.所以新增時候要謹慎...

當然 ambiguity.dic 的路徑你可以在分詞呼叫前..

用 MyStaticValue.ambiguityLibrary = "歧異詞典的路徑" 來設定

歧義糾正是Ansj分詞的最後最後的大招了。殺傷力巨大。謹慎使用。極可能造成其他的錯誤。

下面給一個例子。是動態新增的。

            //歧義糾正
            Value value = new Value("川府辦", "川府辦", "n");
            Library.insertWord(UserDefineLibrary.ambiguityForest, value);

            value = new Value("京財企業務", "京財企", "nt", "業務", "j");
            Library.insertWord(UserDefineLibrary.ambiguityForest, value);

            System.out.println(NlpAnalysis.parse("據說川府辦發的發文很厲害"));;
            System.out.println(NlpAnalysis.parse("京財企業務繁忙"));;

 

自定義詞性和停用詞

很多時候.系統的內建詞性無法滿足您的需求.

你需要根據自己的規則對詞語進行詞性標註.

最簡單的就是使用者自定義詞典中的詞性在分詞結果中,並不是優先出現的.

所以我們通過 FilterModifWord 來對分次結果進一步處理

1.增加停用詞的例子

//增加兩個停用詞
FilterModifWord.insertStopWord("並且") ;
FilterModifWord.insertStopWord("但是") ;

2.增加停用詞性的例子

//加入過濾詞性詞性
FilterModifWord.insertStopNatures("v") ;

3.以使用者自定義的詞性優先

/*
 * 停用詞過濾並且修正詞性
 */
List<Term> parse = ToAnalysis.parse(string) ;
new NatureRecognition(parse).recognition() ;
FilterModifWord.modifResult(parse) ;

4.使用自定義的詞典樹

/*
 * 停用詞過濾並且修正詞性,
 */
public static List<Term> modifResult(List<Term> all, Forest... forests) 

 

分詞http服務

摘要

ansj_seg 內建了一個用來提供分詞 API 的 HttpServer,類名為 org.ansj.web.AnsjServer。

啟動服務

在開發環境中,可以通過 mvn 執行分詞服務:>

mvn exec:java -Dexec.mainClass="org.ansj.web.AnsjServer" -Dexec.args="<埠號>"

在 staging 或生產環境中,執行 org.ansj.webAnsjServer 類即可,如:

java -classpath [jar包位置] org.ansj.app.web.AnsjServer <埠號>


 

API 呼叫

假設埠號為 8888。

一個呼叫例子為:http://127.0.0.1:8888/segment?input=自然語言處理&method=to&nature=true

input

待分詞的文字。

method

使用的分詞方法,可以為 to, nlp 或 base。對應 ansj_seg 的 analysis 中的三種分詞方法。

預設為 to。

nature

是否啟用詞性標註,true 代表啟用,false 代表禁用。

預設為 true。


 

如果需要一個演示介面可以直接訪問

http://127.0.0.1:[]port]/page/index.html

就可以進行視覺化操作了


 

為了方便呼叫。為了不總解釋我搭配好了一套系統大家可以從這裡下載。

http://yun.baidu.com/s/1dDBrec5#dir/path=%2Fansj%E5%88%86%E8%AF%8D 下載ansj_web.jar

解壓縮執行run.sh 然後訪問

展示介面:http://127.0.0.1:8888/page/index.html

API:http://127.0.0.1:8888

 

新詞發現小工具

很高興說這個,這是個有趣的小東西。其實本身是一個tire樹。因為分詞中集成了大量的。新詞識別。 比如 人名識別,機構名識別,新詞發現等,這些新詞的出現對分詞結果起著重要的影響,如何能將這些結果整合起來。 可以想到的有兩種方式,

線性鏈模式:以新詞發現的準確率為基準,進行一步一步的合併。 比如。現識別人名,(因為人名識別的準確率相對較高)再識別機構名,然後是地名等 這個方式的優點是速度快。程式邏輯清晰。在不同識別方式上不必要擔心,詞語權重不一致。 但是缺點也很明顯,人名識別發生錯誤。造成後面的識別一錯再錯,比如“非洲八冠王曾奪世界季軍”,如果現經歷人名識別。會出現“王曾奪”錯誤的劃分為人名。

集合模式:這個方式就是利用了learntool的特性。它將所有識別出來的認為是新詞的詞語。都完整的加入learntool中。之後再以新詞為辭典。構建最優路徑。

好了。說了這麼多。大家一定認為跑題了。我們這裡說的是新詞發現小工具沒錯。真的跑題了

這個工具可以作為辭典整理的一個小東西。具體操作還是上程式碼把。不廢話了



  package org.ansj.demo;

  import org.ansj.dic.LearnTool;
  import org.ansj.domain.Nature;
  import org.ansj.splitWord.analysis.NlpAnalysis;

  /**
   * 新詞發現工具
   * @author ansj
   *
   */
  public class LearnToolDemo {
      public static void main(String[] args) {

          //構建一個新詞學習的工具類。這個物件。儲存了所有分詞中出現的新詞。出現次數越多。相對權重越大。
          LearnTool learnTool = new LearnTool() ;

          //進行詞語分詞。也就是nlp方式分詞,這裡可以分多篇文章
          NlpAnalysis.parse("說過,社交軟體也是打著溝通的平臺,讓無數寂寞男女有了肉體與精神的寄託。", learnTool) ;
          NlpAnalysis.parse("其實可以打著這個需求點去運作的網際網路公司不應只是社交類軟體與可穿戴裝置,還有攜程網,去哪兒網等等,訂房訂酒店多好的寓意", learnTool) ;
          NlpAnalysis.parse("張藝謀的卡宴,馬明哲的戲",learnTool) ;

          //取得學習到的topn新詞,返回前10個。這裡如果設定為0則返回全部
          System.out.println(learnTool.getTopTree(10));

          //只取得詞性為Nature.NR的新詞
          System.out.println(learnTool.getTopTree(10,Nature.NR));

      }
  }

關於learntool的結果儲存。及重新訓練

有好幾個朋友提出過這個問題.的確當初做這個的時候沒有完整的考慮。那麼讓我們看看他是怎麼可以迭代訓練吧。我直接上程式碼了,因為其內部newWord結構比較複雜。所以在write的時候。我放棄了沒有啟用的詞,很可能這些詞。會在以後啟用,而且放棄了這些詞的詞性。全部為nw,但是這個詞性也可能在以後的訓練中糾正。目前我覺得最簡單的儲存方式只有如此。完整無損儲存這個功能,可能會在以後的版本實現,我最終的意思是。現這麼湊合用吧。也還行問題不大 !^_^

  /**
   * 將訓練結果序列寫入到硬碟中
   */
  List<Entry<String, Double>> topTree = learnTool.getTopTree(0);
  StringBuilder sb = new StringBuilder();
  for (Entry<String, Double> entry : topTree) {
      sb.append(entry.getKey() + "\t" + entry.getValue()+"\n");
  }
  IOUtil.Writer("/home/ansj/temp/learnTool.snap", IOUtil.UTF8, sb.toString());
  sb = null;

  /**
   * reload訓練結果
   */
  learnTool = new LearnTool() ;
  HashMap<String, Double> loadMap = IOUtil.loadMap("/home/ansj/temp/learnTool.snap", IOUtil.UTF8, String.class, Double.class);
  for (Entry<String, Double> entry : loadMap.entrySet()) {
      learnTool.addTerm(new NewWord(entry.getKey(), Nature.NW, entry.getValue())) ;
      learnTool.active(entry.getKey()) ;
  }
  System.out.println(learnTool.getTopTree(10));

 

關鍵詞抽取

/**
 * 關鍵詞提取的例子
 * @author ansj
 *
 */
public class KeyWordCompuerDemo {
public static void main(String[] args) {
    KeyWordComputer kwc = new KeyWordComputer(5);
    String title = "維基解密否認斯諾登接受委內瑞拉庇護";
    String content = "有俄羅斯國會議員,9號在社交網站推特表示,美國中情局前僱員斯諾登,已經接受委內瑞拉的庇護,不過推文在釋出幾分鐘後隨即刪除。俄羅斯當局拒絕發表評論,而一直協助斯諾登的維基解密否認他將投靠委內瑞拉。  俄羅斯國會國際事務委員會主席普什科夫,在個人推特率先披露斯諾登已接受委內瑞拉的庇護建議,令外界以為斯諾登的動向終於有新進展。  不過推文在幾分鐘內旋即被刪除,普什科夫澄清他是看到俄羅斯國營電視臺的新聞才這樣說,而電視臺已經作出否認,稱普什科夫是誤解了新聞內容。  委內瑞拉駐莫斯科大使館、俄羅斯總統府發言人、以及外交部都拒絕發表評論。而維基解密就否認斯諾登已正式接受委內瑞拉的庇護,說會在適當時間公佈有關決定。  斯諾登相信目前還在莫斯科謝列梅捷沃機場,已滯留兩個多星期。他早前向約20個國家提交庇護申請,委內瑞拉、尼加拉瓜和玻利維亞,先後表示答應,不過斯諾登還沒作出決定。  而另一場外交風波,玻利維亞總統莫拉萊斯的專機上星期被歐洲多國以懷疑斯諾登在機上為由拒絕過境事件,涉事國家之一的西班牙突然轉口風,外長馬加略]號表示願意就任何誤解致歉,但強調當時當局沒有關閉領空或不許專機降落。";
        Collection<Keyword> result = kwc.computeArticleTfidf(title, content);
            System.out.println(result);
    }
}

 

詞性標註

Ansj具有詞性標註的功能,ps:我以前做搜尋的,覺得這玩意沒大用,但是隨著在工程上的應用。詞性標註越來越重要了。 所以有必要單拿出來,和大家分享一下

  • Ansj詞性標註是基於HMM的。

    主要利用了ngram的方式,相對而言作的還是比較粗糙

  • 詞性標註的規範

    說句實話,這個自由度一直很高,因為既要支援使用者自定義辭典。而使用者的詞性關我屁事。所以沒有一個完整的統一。但是在實際使用中我們還是儘量以北大標註為準,在另一個文件中,有一份詞性說明。我自己增加了nw詞性,這個詞性意思是是一個新詞,但是具體是什麼。我不知道。

  • 什麼地方需要詞性標註

    除了nlpanalysis 自帶詞性標註。其他的方式都是需要詞性標註的。詞性標註的方式是以工具類的形式呼叫。下面是呼叫程式碼,可以看到我們是利用new NatureRecognition(terms).recognition();對分詞結果進行的標註。

    package org.ansj.demo;

    import java.io.IOException;
    import java.util.List;

    import org.ansj.domain.Term;
    import org.ansj.recognition.NatureRecognition;
    import org.ansj.splitWord.analysis.ToAnalysis;

    /**
     * 詞性標註
     * 
     * @author ansj
     * 
     */
    public class NatureDemo {
        public static void main(String[] args) throws IOException {
            List<Term> terms = ToAnalysis.parse("Ansj中文分詞是一個真正的ict的實現.並且加入了自己的一些資料結構和演算法的分詞.實現了高效率和高準確率的完美結合!");
            new NatureRecognition(terms).recognition(); //詞性標註
            System.out.println(terms);
        }
    }
  • 我只想用ansj的詞性標註。我沒有分詞結果

    好吧,你怎麼這麼多事,:-)開玩笑。是因為我在實際工程中遇到了這個問題看下面demo


    package org.ansj.demo;    
    import java.util.Arrays;
    import java.util.List;
    import org.ansj.domain.Term;
    import org.ansj.recognition.NatureRecognition;

    /**
     * 對非ansj的分詞結果進行詞性標註
     * @author ansj
     *
     */
    public class NatureTagDemo {
        public static void main(String[] args) {
            String[] strs = {"對", "非", "ansj", "的", "分詞", "結果", "進行", "詞性", "標註"} ;
            List<String> lists = Arrays.asList(strs) ;
            List<Term> recognition = NatureRecognition.recognition(lists, 0) ;
            System.out.println(recognition);
        }
    }

 

tree-split

tree-split是一個小巧好用的。tire樹資料庫。

裡面封裝了我一些常用的工具類。比如IOUtil 。 StringUtil。

tire樹就不解釋了。也就是詞典樹,個人認為是最好的分詞資料結構。沒有之一。

tree-split 中的tire採用首字hash 。次字二分查詢的方式。同時也支援引數可配置的形式。。

下面是tree-split的一個使用說明


        /**
         * 詞典的構造.一行一個詞後面是引數.可以從檔案讀取.可以是read流.
         */
        String dic = "中國\t1\tzg\n人名\t2\n中國人民\t4\n人民\t3\n孫健\t5\nCSDN\t6\njava\t7\njava學習\t10\n";
        Forest forest = Library.makeForest(new BufferedReader(new StringReader(dic)));

        /**
         * 刪除一個單詞
         */
        Library.removeWord(forest, "中國");
        /**
         * 增加一個新詞
         */
        Library.insertWord(forest, "中國人");
        String content = "中國人名識別是中國人民的一個驕傲.孫健人民在CSDN中學到了很多最早iteye是java學習筆記叫javaeye但是java123只是一部分";
        GetWord udg = forest.getWord(content);

        String temp = null;
        while ((temp = udg.getFrontWords()) != null)
            System.out.println(temp + "\t\t" + udg.getParam(1) + "\t\t" + udg.getParam(2));

jar包下載地址:

http://maven.ansj.org/org/ansj/tree_split/

maven

==================

  1. 第一步在你的pom.xml中加入.
<project...>
    ....

    <repositories>
        <repository>
            <id>mvn-repo</id>
            <url>http://maven.ansj.org/</url>
        </repository>
    </repositories>
    ....
</project>
  1. 在dependencies標籤中貼上如下:(其實version 以最新的為標準.)
    <dependencies>
        ....
        <dependency>
            <groupId>org.ansj</groupId>
            <artifactId>tree_split</artifactId>
            <version>1.2</version>
        </dependency>
        ....
    </dependencies>

獲得原始碼

https://github.com/ansjsun/tree_split

 

 

Ansj In Lucene

  • Ansj目前有了lucene 什麼版本的外掛:
    • lucene3.x
    • lucene4.x

      對於3.x之前的版本,我表示不會寫相關的jar了,lucene的分詞外掛不是很難寫,如果非要說難寫就是因為他沒有一個很好的文件和說明,裡面暗坑比較多。

  • 如何獲得lucene外掛的jar包:

    你可以從我的maven倉庫中下載http://maven.ansj.org/org/ansj/ 開啟這個

    找到 ansj_lucene3_plug/ , ansj_lucene4_plug/ 從裡面下載jar包把。maven的話同理。不多闡述

          //實際使用中jar最好是最新版本的,需要這三個jar。。。
          http://maven.ansj.org/org/ansj/ansj_lucene4_plug/1.3/ansj_lucene4_plug-1.3.jar
    
          http://maven.ansj.org/org/ansj/ansj_seg/1.x/ansj_seg-1.3-min.jar
    
          http://maven.ansj.org/org/ansj/tree_split/1.x/tree_split-1.2.jar
    
  • 如何用maven整合

     <dependency>
              <groupId>org.ansj</groupId>
              <artifactId>ansj_seg</artifactId>
              <version>1.3</version>
           <classifier>min</classifier>
          </dependency>
          <dependency>
              <groupId>org.ansj</groupId>
              <artifactId>ansj_lucene4_plug</artifactId>
              <version>1.3</version>
          </dependency>
    
  • 如何獲得Ansj lucene外掛的原始碼:

    外掛原始碼我已經集合到ansj_seg的專案中了。在plug目錄下有這兩個專案的原始碼。並且也是maven專案。你可以直接作為maven匯入。

  • 使用例子:

 


import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Date;
import java.util.HashSet;
import java.util.ResourceBundle;
import love.cq.util.IOUtil;
import org.ansj.lucene.util.PorterStemmer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
public class AnsjAnalysisTest {
    @Test
    public void test() throws IOException {
        Token nt = new Token();
        Analyzer ca = new AnsjAnalysis();
        Reader sentence = new StringReader(
                "\n\n\n\n\n\n\n我從小就不由自主地認為自己長大以後一定得成為一個象我父親一樣的畫家, 可能是父母潛移默化的影響。其實我根本不知道作為畫家意味著什麼,我是否喜歡,最重要的是否適合我,我是否有這個才華。其實人到中年的我還是不確定我最喜歡什麼,最想做的是什麼?我相信很多人和我一樣有同樣的煩惱。畢竟不是每個人都能成為作文裡的宇航員,科學家和大教授。知道自己適合做什麼,喜歡做什麼,能做好什麼其實是個非常困難的問題。"

 

                    + "幸運的是,我想我的孩子不會為這個太過煩惱。通過老大,我慢慢發現美國高中的一個重要功能就是幫助學生分析他們的專長和興趣,從而幫助他們選擇大學的專業和未來的職業。我覺得幫助一個未成形的孩子找到她未來成長的方向是個非常重要的過程。"
                    + "美國高中都有專門的職業顧問,通過接觸不同的課程,和各種心理,個性,興趣很多方面的問答來幫助每個學生找到最感興趣的專業。這樣的教育一般是要到高年級才開始, 可老大因為今年上計算機的課程就是研究一個職業走向的軟體專案,所以她提前做了這些考試和麵試。看來以後這樣的教育會慢慢由電腦來測試了。老大帶回家了一些試卷,我挑出一些給大家看看。這門課她花了2個多月才做完,這裡只是很小的一部分。"
                    + "在測試裡有這樣的一些問題:"
                    + "你是個喜歡動手的人嗎? 你喜歡修東西嗎?你喜歡體育運動嗎?你喜歡在室外工作嗎?你是個喜歡思考的人嗎?你喜歡數學和科學課嗎?你喜歡一個人工作嗎?你對自己的智力自信嗎?你的創造能力很強嗎?你喜歡藝術,音樂和戲劇嗎?  你喜歡自由自在的工作環境嗎?你喜歡嘗試新的東西嗎? 你喜歡幫助別人嗎?你喜歡教別人嗎?你喜歡和機器和工具打交道嗎?你喜歡當領導嗎?你喜歡組織活動嗎?你什麼和數字打交道嗎?");
    TokenStream ts = ca.tokenStream("sentence", sentence);

    System.out.println("start: " + (new Date()));
    long before = System.currentTimeMillis();
    while (ts.incrementToken()) {
        System.out.println(ts.getAttribute(CharTermAttribute.class));
    }
    ts.close();
    long now = System.currentTimeMillis();
    System.out.println("time: " + (now - before) / 1000.0 + " s");
}

@Test
public void indexTest() throws CorruptIndexException, LockObtainFailedException, IOException, ParseException {
    HashSet<String> hs = new HashSet<String>();
    BufferedReader reader2 = IOUtil.getReader(ResourceBundle.getBundle("library").getString("stopLibrary"), "UTF-8");
    String word = null;
    while ((word = reader2.readLine()) != null) {
        hs.add(word);
    }
    Analyzer analyzer = new AnsjAnalysis(hs,false);
    Directory directory = null;
    IndexWriter iwriter = null;

    BufferedReader reader = IOUtil.getReader("/Users/ansj/Desktop/未命名資料夾/indextest.txt", "UTF-8");
    String temp = null;
    StringBuilder sb = new StringBuilder();
    while ((temp = reader.readLine()) != null) {
        sb.append(temp);
        sb.append("\n");
    }
    reader.close();
    String text = sb.toString();

    text = "開源專案管理你喜歡在室外工作嗎?你是個喜歡思考的人嗎?你喜歡數學和科學課嗎?你喜歡一個人工作嗎?你對自己的智力自信嗎?你的創造能力很強嗎?你喜歡藝術,音樂和戲劇嗎?  你喜歡自由自在的工作環境嗎?你喜歡嘗試新的東西嗎? 你喜歡幫助別人嗎?你喜歡教別人嗎?你喜歡和機器和工具打交道嗎?你喜歡當領導嗎?你喜歡組織活動嗎?你什麼和數字打交道嗎?";

    IndexWriterConfig ic = new IndexWriterConfig(Version.LUCENE_32, analyzer);
    // 建立記憶體索引物件
    directory = new RAMDirectory();
    iwriter = new IndexWriter(directory, ic);
    // BufferedReader reader =
    // IOUtil.getReader("/Users/ansj/Documents/快盤/分詞/語料/1998年人民日報分詞語料_未區分.txt",
    // "GBK");
    // String temp = null;
    // while ((temp = reader.readLine()) != null) {
    // addContent(iwriter, temp);
    // }
    addContent(iwriter, text);
    addContent(iwriter, text);
    addContent(iwriter, text);
    addContent(iwriter, text);
    iwriter.commit();
    iwriter.close();

    System.out.println("索引建立完畢");

    search(analyzer, directory, "室外工作");
}

private Analyzer ansjHeightAnalyzer = new AnsjAnalysis();

private void search(Analyzer analyzer, Directory directory, String queryStr) throws CorruptIndexException, IOException, ParseException {
    IndexSearcher isearcher;
    // 查詢索引
    isearcher = new IndexSearcher(directory);
    QueryParser tq = new QueryParser(Version.LUCENE_32, "text", ansjHeightAnalyzer);
    Query query = tq.parse(queryStr);
    System.out.println(query);
    TopDocs hits = isearcher.search(query, 5);
    System.out.println(queryStr + ":共找到" + hits.totalHits + "條記錄!");
    for (int i = 0; i < hits.scoreDocs.length; i++) {
        int docId = hits.scoreDocs[i].doc;
        Document document = isearcher.doc(docId);
        System.out.println(toHighlighter(ansjHeightAnalyzer, query, document));
    }
}

/**
 * 高亮設定
 * 
 * @param query
 * @param doc
 * @param field
 * @return
 */
private String toHighlighter(Analyzer analyzer, Query query, Document doc) {
    String field = "text";
    try {
        SimpleHTMLFormatter simpleHtmlFormatter = new SimpleHTMLFormatter("<font color=\"red\">", "</font>");
        Highlighter highlighter = new Highlighter(simpleHtmlFormatter, new QueryScorer(query));
        TokenStream tokenStream1 = analyzer.tokenStream("text", new StringReader(doc.get(field)));
        String highlighterStr = highlighter.getBestFragment(tokenStream1, doc.get(field));
        return highlighterStr == null ? doc.get(field) : highlighterStr;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidTokenOffsetsException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}
private void addContent(IndexWriter iwriter, String text) throws CorruptIndexException, IOException {
    Document doc = new Document();
    doc.add(new Field("text", text, Field.Store.YES, Field.Index.ANALYZED));
    iwriter.addDocument(doc);
}
@Test
public void poreterTest() {
    PorterStemmer ps = new PorterStemmer();
    System.out.println(ps.stem("apache"));
}

Ansj In Solr

已經有熱心的大牛,幫我完成了這個。我直接貼上他的git地址了。有啥問題直接找他與我無關^_^

https://github.com/lgnlgn/ansj4solr

在這裡感謝@梁山伯 帥哥。。。

 

Ansj In Elasticsearch

推薦es神器。也是我最喜歡用的一個搜尋框架。

好吧。我要開始偷懶了

已經有熱心的大牛,幫我完成了這個。我直接貼上他的git地址了。有啥問題直接找他與我無關^_^

https://github.com/4onni/elasticsearch-analysis-ansj

在這裡感謝@4onni 帥哥。。。

 

詞性說明

漢語文字詞性標註標記集

# 1. 名詞  (1個一類,7個二類,5個三類)
名詞分為以下子類:
n 名詞
nr 人名
nr1 漢語姓氏
nr2 漢語名字
nrj 日語人名
nrf 音譯人名
ns 地名
nsf 音譯地名
nt 機構團體名
nz 其它專名
nl 名詞性慣用語
ng 名詞性語素
nw 新詞
# 2. 時間詞(1個一類,1個二類)
t 時間詞
tg 時間詞性語素
# 3. 處所詞(1個一類)
s 處所詞
# 4. 方位詞(1個一類)
f 方位詞
# 5. 動詞(1個一類,9個二類)
v 動詞
vd 副動詞
vn 名動詞
vshi 動詞“是”
vyou 動詞“有”
vf 趨向動詞
vx 形式動詞
vi 不及物動詞(內動詞)
vl 動詞性慣用語
vg 動詞性語素
# 6. 形容詞(1個一類,4個二類)
a 形容詞
ad 副形詞
an 名形詞
ag 形容詞性語素
al 形容詞性慣用語
# 7. 區別詞(1個一類,2個二類)
b 區別詞
bl 區別詞性慣用語
# 8. 狀態詞(1個一類)
z 狀態詞
# 9. 代詞(1個一類,4個二類,6個三類)
r 代詞
rr 人稱代詞
rz 指示代詞
rzt 時間指示代詞
rzs 處所指示代詞
rzv 謂詞性指示代詞
ry 疑問代詞
ryt 時間疑問代詞
rys 處所疑問代詞
ryv 謂詞性疑問代詞
rg 代詞性語素
# 10. 數詞(1個一類,1個二類)
m 數詞
mq 數量詞
# 11. 量詞(1個一類,2個二類)
q 量詞
qv 動量詞
qt 時量詞
# 12. 副詞(1個一類)
d 副詞
# 13. 介詞(1個一類,2個二類)
p 介詞
pba 介詞“把”
pbei 介詞“被”
# 14. 連詞(1個一類,1個二類)
c 連詞
 cc 並列連詞
# 15. 助詞(1個一類,15個二類)
u 助詞
uzhe 著
ule 了 嘍
uguo 過
ude1 的 底
ude2 地
ude3 得
usuo 所
udeng 等 等等 云云
uyy 一樣 一般 似的 般
udh 的話
uls 來講 來說 而言 說來
uzhi 之
ulian 連 (“連小學生都會”)
# 16. 嘆詞(1個一類)
e 嘆詞
# 17. 語氣詞(1個一類)
y 語氣詞(delete yg)
# 18. 擬聲詞(1個一類)
o 擬聲詞
# 19. 字首(1個一類)
h 字首
# 20. 字尾(1個一類)
k 字尾
# 21. 字串(1個一類,2個二類)
x 字串
 xx 非語素字
 xu 網址URL
# 22. 標點符號(1個一類,16個二類)
w 標點符號
wkz 左括號,全形:( 〔  [  {  《 【  〖〈   半形:( [ { <
wky 右括號,全形:) 〕  ] } 》  】 〗 〉 半形: ) ] { >
wyz 左引號,全形:“ ‘ 『 
wyy 右引號,全形:” ’ 』
wj 句號,全形:。
ww 問號,全形:? 半形:?
wt 歎號,全形:! 半形:!
wd 逗號,全形:, 半形:,
wf 分號,全形:; 半形: ;
wn 頓號,全形:、
wm 冒號,全形:: 半形: :
ws 省略號,全形:……  …
wp 破折號,全形:——   --   ——-   半形:---  ----
wb 百分號千分號,全形:% ‰   半形:%
wh 單位符號,全形:¥ $ £  °  ℃  半形:$

專案的文件地址:http://nlpchina.github.io/ansj_seg/ 
感謝作者給我們提供這麼好用的開源工具。