?? 中文分詞程序源代碼.txt
字號:
前幾天因為好久沒發blog了,就拿我畢設中的一段算法湊數,沒想到引起很多人的興趣。因此就把我的分詞算法單獨拎出來做了一個項目叫作DartSplitter。暫時把分詞算法的名稱叫做樹狀詞庫分詞法。
剛剛統計了一下源代碼,一共也就950多行代碼,加上測試用例共1200行代碼。看來確實還是想法比實現重要。說明如下:
1、由于不能用原來的專業詞庫,因此我特地去網上找了個Access的詞庫,一共有一萬條記錄左右,還有很多單字,因此分詞的效果不會太理想。不過我這里只是為了演示一下功能,幸好從數據庫轉成我現的詞庫并不復雜,我的演示程序里提供了例子,后面還會有說明。而且,真正好的詞庫可能還要加入機器學習等功能,真正全面的分詞可能還需要將基于詞庫的分詞與無意義的分詞結合,不過這些功能都不是那么簡單的啦。
2、由于測試對詞庫的依賴性太強了,因此我的測試用例里沒有用太多的assert,只是簡單地log一下結果。而且考慮到大家用TestNG的還比較少,因此我把測試用例都改成JUnit了。測試用例與外部資源的依賴一直是困擾著我的問題,不知大家有何良策?
3、由于我現在寫程序已經對Spring產生依賴癥了,因此雖然我希望我程序依賴的包越少越好,但還是用了Spring,這樣的好處是所有接口與關聯都是可配置的。因此如果要替換掉某一部分實現也會比較簡單,例如從關系數據庫的詞庫取詞的接口肯定是要重寫,只要配置文件里修改一行就可以了,這個在后面說明。
4、為了方便大家使用我特意寫了示例splitterTest,里面提供了兩個main,一個是建詞庫(DictSerializationMain),另一個是對一篇文章的analysis(AnalysisTest),用了SimpleAnalyzer,StandardAnalyzer和我的TreeDictAnalyzer進行對比。
5、系統在設計的時候就是與lucene緊耦合,分詞的單位也是lucene中token。這是通用性與效率平衡的結果,最后我選擇了效率,而且畢竟lucene是大家用得最多的全文檢索引擎包。
下面講一下使用說明:
1、如果不需要修改源代碼的話,只要下載dartsplitter-0.3.jar就可以了。
2、需要在新建項目的source的etc下放入以下配置文件(示例項目里都有,只要copy就行了):dartSplitter.properties, dictJdbc.properties, dartSplitterContext.xml。
dartSplitter.properties的大概內容如下:
splitter.dictDir=f:/WebDict (指定了詞典的路徑,主要用于lazy load,目前還沒用到)
splitter.dictFile=f:/WebDict/common.dict (詞典的文件名,只要將詞典文件與配置對就行了)
splitter.maxWordLength=20 (放入詞庫的最大詞長,load之后相當于樹的高度)
演示的字典文件名位于dict文件夾下:common.dict。 commonDict.mdb則是當時找來的access文件。
dictJdbc.properties的內容如下:
dict.jdbc.driverClassName=sun.jdbc.odbc.JdbcOdbcDriver
dict.jdbc.url=jdbc:odbc:commonDict
dict.jdbc.username=
dict.jdbc.password=
其實就是詞庫文件對應的Jdbc鏈接啦。
dartSplitterContext.xml是Spring的配置文件,除了建詞庫時訪問關系數據庫的DAO配置要改動外,其它都不要去動。
3、建自己的詞庫
A、自己implements一下DictDAO接口,提供自己的實現,DictDAO的接口定義很簡單,只要實現兩個方法就行了,可參考CommonDictDAO的實現:
public interface DictDAO {
/**
* @param strPrefix 詞的首個字
* @return 以這個字為首字的詞對象(@see cn.edu.zju.dartsplitter.data.DictValue)的列表
*/
public List<DictValue> getDictValues(String strPrefix);
/**
* @return 詞庫中所有詞的首字列表
*/
public List<String> getAllPrefixes();
}
B、修改dartSplitterContext.xml的配置:
<bean id="dictTree" class="cn.edu.zju.dartsplitter.impl.DictTreeImpl">
<property name="rebuild"><value>false</value></property>
<property name="maxWordLength"><value>${splitter.maxWordLength}</value></property>
<property name="fileName"><value>${splitter.dictFile}</value></property>
<property name="dictDAOList">
<list>
<ref local="commonDictDAO "/>
</list>
</property>
</bean>
只要在以下這段里將替換commonDictDAO為自己的DAO就行了,也可以加入新的DAO,因為我們考慮到有多個數據來源的情況,因此可以把多個DAO實現一起放入List里。
C、執行一下包里或者示例程序里的DictSerializationMain就OK了
最后感謝要一下blueGuitar,如果沒有當時與他討論時的靈感,就不會有現在的算法。還要謝謝車東,是他引導我使我對中文分詞感興趣的。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -