利用Lucene制作中文搜尋應用
来源:百度文库 编辑:神马文学网 时间:2024/05/06 07:44:32
之前討論過想要有自行組合新聞的BLOG軟件,這種軟件最重要的部份就是搜尋和相似度統計的功能。要自行制作一個功能完整又效能高的搜尋器絕不容易,幸好早有開放源碼的軟件替我們做此工作。
Apache Lucene
Apache Lucene是一個開放源碼的搜尋器引擎,利用它可以輕易地為Java軟件加入全文搜尋功能。Lucene的最主要工作是替文件的每一個作索引,索引讓搜尋的效率比傳統的逐字比較大大提高,試想想google怎樣可以瞬即自全世界的文件中找到有關鍵字的網頁,但傳統的Windows檔案搜索卻常常要花半小時? Lucen提供一組解讀、過濾、分析文件、編排和使用索引的API,它的強大之處除了高效和簡單外,最重要的是使用者可以隨時應自己需要自訂其功能。
分析器
要為應用提高搜尋效率,不同語言,甚至不同類型的文章都需要特別的分析器(Analyzer)。Lucene 的分析器由分解器(Tokenizer)和過濾器(TokenFilter)組成,前者分割文字、找出文件中的最少單位(Token),後者過濾和改變輸入去方便處理。英語的文字分割簡單直接,但對於中文來說要有意義地分割則困難得多了。 雖然Lucene Sandbox Project下己有兩個可以分析中文的分析器ChineseAnalyzer和CJKAnalyzer,但因為他們策略太簡單,各有不盡理想的地方。
中文詞語分割
以簡單句子為例:「我是中國人」,ChineseTokenizer會將之分割為五個中文字:「我、是、中、國、人」,CJKTokenizer則會將之分割為「我是、是中、中國、國人」四個二節的詞。前者的問題是沒有考慮中文詞語的問題,如搜尋「國中」一樣搜尋到「我是中國人」。後者的問題則是制做了大量沒意義的詞如「是中」「國人」,讓索引沒必要地增大、降低搜尋效率。理想的方法是按詞語分割,如「我、是 、中國人」,但要完美地分割中文卻很困難,多年以來直到現在都有無數的研究都在想有效的新方法。
如何研究更好的方法是一回事,實作一個足夠應用的分析器又是另一回事,要是不滿足於ChineseTokenizer和CJKTokenizer的簡單,又不想花時間研究,可以參考和應用前人所作的解決方案。
實作
管理線上中文工具網站的 Erik Peterson 開發了一個基於詞語的中文分割器。它的算法很簡單:準備一本中文詞典,將輸入的文章的每一字逐字和詞典比較,順序地找文章中可以對應詞語。例如「中國人」,首先找到「中」、找著找到「中國」、再找到「中國人」,分割器就會返回「中國人」作為Token。這種算法簡單但有效,字典用Tree實作的話效能也相當好,Eric的實作包括Perl和Java版本的程式。
怎樣應用這個分割器去制作Lucene的Tokenizer呢?當然我們可以研究它的算法自行寫一個實作Tokenizer介面的Segmenter Class,這樣效率最高但必須重寫整個程式。為了重用已有的資源,我的方案是先準備好輸入字串、經過segmenter分割成有空格的中文字,再用跟英文字一樣的用空格分割方法。
實作時發現以下一些問題(和解決方法):
Segmenter要將整本字典放進記憶體的樹結構中,視電腦速度而定需要3秒到30秒準備,為了避免重覆這漫長過種使用了Singleton去產生Segmenter的實體,同時使用serialize的方法讓第二次執行時不用重新制作樹 原裝的StandardTokenizer設計以英語系為目標,原以為只要輸入有空格的中文即可分割中文,不過發現原來它對中日韓字體另有處理,它跟ChineseTokenizer一樣會把每個中文字當成一個token。幸好StandardTokenizer是使用JavaCC (類似YACC,是JAVA版的語言編譯器) 制作,只要更改原本StandardTokenizer.jj中的語法,把中文當作一般英文字母去處理就能達到原先的目標了。 (更改了的CStandardTokenizer.jj)
完成的Segmenter所造的index比CJK Analyzer或者Chinese Analyzer更少,但要注意由於要載入一個佔記憶體3M以上的大字典所以記憶體方面更求更高,而在分析少量文件時預載字典的overhead隨時比分析少,只有大量使用才會見到它的優點。
Apache Lucene
Apache Lucene是一個開放源碼的搜尋器引擎,利用它可以輕易地為Java軟件加入全文搜尋功能。Lucene的最主要工作是替文件的每一個作索引,索引讓搜尋的效率比傳統的逐字比較大大提高,試想想google怎樣可以瞬即自全世界的文件中找到有關鍵字的網頁,但傳統的Windows檔案搜索卻常常要花半小時? Lucen提供一組解讀、過濾、分析文件、編排和使用索引的API,它的強大之處除了高效和簡單外,最重要的是使用者可以隨時應自己需要自訂其功能。
分析器
要為應用提高搜尋效率,不同語言,甚至不同類型的文章都需要特別的分析器(Analyzer)。Lucene 的分析器由分解器(Tokenizer)和過濾器(TokenFilter)組成,前者分割文字、找出文件中的最少單位(Token),後者過濾和改變輸入去方便處理。英語的文字分割簡單直接,但對於中文來說要有意義地分割則困難得多了。 雖然Lucene Sandbox Project下己有兩個可以分析中文的分析器ChineseAnalyzer和CJKAnalyzer,但因為他們策略太簡單,各有不盡理想的地方。
中文詞語分割
以簡單句子為例:「我是中國人」,ChineseTokenizer會將之分割為五個中文字:「我、是、中、國、人」,CJKTokenizer則會將之分割為「我是、是中、中國、國人」四個二節的詞。前者的問題是沒有考慮中文詞語的問題,如搜尋「國中」一樣搜尋到「我是中國人」。後者的問題則是制做了大量沒意義的詞如「是中」「國人」,讓索引沒必要地增大、降低搜尋效率。理想的方法是按詞語分割,如「我、是 、中國人」,但要完美地分割中文卻很困難,多年以來直到現在都有無數的研究都在想有效的新方法。
如何研究更好的方法是一回事,實作一個足夠應用的分析器又是另一回事,要是不滿足於ChineseTokenizer和CJKTokenizer的簡單,又不想花時間研究,可以參考和應用前人所作的解決方案。
實作
管理線上中文工具網站的 Erik Peterson 開發了一個基於詞語的中文分割器。它的算法很簡單:準備一本中文詞典,將輸入的文章的每一字逐字和詞典比較,順序地找文章中可以對應詞語。例如「中國人」,首先找到「中」、找著找到「中國」、再找到「中國人」,分割器就會返回「中國人」作為Token。這種算法簡單但有效,字典用Tree實作的話效能也相當好,Eric的實作包括Perl和Java版本的程式。
怎樣應用這個分割器去制作Lucene的Tokenizer呢?當然我們可以研究它的算法自行寫一個實作Tokenizer介面的Segmenter Class,這樣效率最高但必須重寫整個程式。為了重用已有的資源,我的方案是先準備好輸入字串、經過segmenter分割成有空格的中文字,再用跟英文字一樣的用空格分割方法。
實作時發現以下一些問題(和解決方法):
Segmenter要將整本字典放進記憶體的樹結構中,視電腦速度而定需要3秒到30秒準備,為了避免重覆這漫長過種使用了Singleton去產生Segmenter的實體,同時使用serialize的方法讓第二次執行時不用重新制作樹 原裝的StandardTokenizer設計以英語系為目標,原以為只要輸入有空格的中文即可分割中文,不過發現原來它對中日韓字體另有處理,它跟ChineseTokenizer一樣會把每個中文字當成一個token。幸好StandardTokenizer是使用JavaCC (類似YACC,是JAVA版的語言編譯器) 制作,只要更改原本StandardTokenizer.jj中的語法,把中文當作一般英文字母去處理就能達到原先的目標了。 (更改了的CStandardTokenizer.jj)
完成的Segmenter所造的index比CJK Analyzer或者Chinese Analyzer更少,但要注意由於要載入一個佔記憶體3M以上的大字典所以記憶體方面更求更高,而在分析少量文件時預載字典的overhead隨時比分析少,只有大量使用才會見到它的優點。
利用Lucene制作中文搜尋應用
Lucene 中文分词
Lucene 中文分词
Lucene中文分词(IKAnalyzer1.4)
Lucene中文分词的highlight显示
Lucene 中文分词的 highlight 显示
Matrix - 与 Java 共舞 - 利用Lucene搜索Java源代码
给Lucene增加中文分词2(猎兔分词,转贴)
我的LUCENE终于实现中文自动分词了
如何在lucene中使用中文自动分词技术
技术文摘: 给Lucene加入性能更好的中文分词
当前几个主要的Lucene中文分词器的比较
利用字体制作标志
利用字体制作标志
利用CorelDraw制作名片
利用CorelDraw制作名片
利用路径制作花边
利用路径制作花边
利用豆浆机制作各种浆汁
给Lucene添加中文分词3(猎兔的另一篇文章)
给Lucene加入性能更好的中文分词1(windshowzbf原创)
lucene.net 2.0 中文分词后语法高亮问题 - 智慧掩盖真相 - 博客园
唐福林 博客雨 : 当前几个主要的Lucene中文分词器的比较
利用eclipse编辑中文资源文件