標籤:class opd except 最簡 ted 二分法 實驗 either 是什麼
參考部落格: http://blog.csdn.net/ayi_5788/article/category/6348409分頁: http://blog.csdn.net/hu948162999/article/details/41209699 1、 什麼是中文分詞 學過英文的都知道,英文是以單詞為單位的,單詞與單詞之間以空格或者逗號句號隔開。而中文則以字為單位,字又組成詞,字和詞再組成句子。所以對於英文,我們可以簡單以空格判斷某個字串是否為一個單詞,比如I love China,love 和 China很容易被程式區分開來;但中文“我愛中國”就不 一樣了,電腦不知道“中國”是一個詞語還是“愛中”是一個詞語。把中文的句子切分成有意義的詞,就是中文分詞,也稱切詞。我愛中國,分詞的結果是:我 愛 中國。 目前中文分詞還是一個難題———對於需要上下文區別的詞以及新詞(人名、地名等)很難完美的區分。國際上將同樣存在分詞問題的韓國、日本和中國並稱為CJK(Chinese Japanese Korean),對於CJK這個代稱可能包含其他問題,分詞只是其中之一。 2、 中文分詞的實現 Lucene中對中文的處理是基於自動切分的單字切分,或者二元切分。除此之外,還有最大切分(包括向前、向後、以及前後相結合)、最少切分、全切分等等。 Lucene內建了幾個分詞器WhitespaceAnalyzer, SimpleAnalyzer, StopAnalyzer, StandardAnalyzer, ChineseAnalyzer, CJKAnalyzer等。前面三個只適用於英文分詞,StandardAnalyzer對可最簡單地實現中文分詞,即二分法,每個字都作為一個詞,比如:”北京天安門” ==> “北京 京天 天安 安門”。這樣分出來雖然全面,但有很多缺點,比如,索引檔案過大,檢索時速度慢等。ChineseAnalyzer是按字分的,與StandardAnalyzer對中文的分詞沒有大的區別。 CJKAnalyzer是按兩字切分的, 比較武斷,並且會產生垃圾Token,影響索引大小。以上分詞器過於簡單,無法滿足現實的需求,所以我們需要實現自己的分詞演算法。 這樣,在查詢的時候,無論是查詢”北京” 還是查詢”天安門”,將查詢片語按同樣的規則進行切分:”北京”,”天安安門”,多個關鍵詞之間按與”and”的關係組合,同樣能夠正確地映射到相應的索引中。這種方式對於其他亞洲語言:韓文,日文都是通用的。 基於自動切分的最大優點是沒有詞表維護成本,實現簡單,缺點是索引效率低,但對於中小型應用來說,基於2元文法的切分還是夠用的。基於2元切分後的索引一般大小和源檔案差不多,而對於英文,索引檔案一般只有原檔案的30%-40%不同。 目前比較大的搜尋引擎的語言分析演算法一般是基於以上2個機制的結合。關於中文的語言分析演算法,大家可以在Google查關鍵詞”wordsegment search”能找到更多相關的資料。 =============================分割線=============================== 由於Lucene不同的版本差距較大,,此系列教程打算把3.5版本,4.5版本,5.0版本都給出個例子,方便大家學習,也方便自己複習。 註:由於Lucene5.0版本是基於JDK1.7開發的,所以想學習的同學請配置1.7及以上的版本。故測試Lucene 6.1.0也適用Lucene 5.0中的代碼。Lucene 6.1.0最低要求也是JDK1.7. 建立索引可分為主要的幾步,我自己實驗過,不同的版本間會有些不同,但是跟著如下的幾大步驟一步一步寫,問題不會太大。 1、建立Directory 2、建立IndexWriter 3、建立Document對象 4、為Document添加Field 5、通過IndexWriter添加文檔到索引中 搜尋可分為如下幾步: 1、建立Directory 2、建立IndexReader 3、根據IndexReader建立IndexSearch 4、建立搜尋的Query 5、根據searcher搜尋並且返回TopDocs 6、根據TopDocs擷取ScoreDoc對象 7、根據searcher和ScoreDoc對象擷取具體的Document對象 8、根據Document對象擷取需要的值 我們向Document添加Field可以有更多的設定,那麼都是什麼意思呢? name:欄位名,很容易理解 value:欄位值,也很容易理解 store和index怎麼解釋,下面就來看一下這兩個選項的可選值: Field.Store.YES或者NO(儲存域選項) 設定為YES表示或把這個域中的內容完全儲存到檔案中,方便進行文本的還原 設定為NO表示把這個域的內容不儲存到檔案中,但是可以被索引,此時內容無法完全還原 Field.Index(索引選項) Index.ANALYZED:進行分詞和索引,適用於標題、內容等 Index.NOT_ANALYZED:進行索引,但是不進行分詞,如果社會安全號碼,姓名,ID等,適用於精確搜尋 Index.ANALYZED_NOT_NORMS:進行分詞但是不儲存norms資訊,這個norms中包括了建立索引的時間和權值等資訊 Index.NOT_ANALYZED_NOT_NORMS:即不進行分詞也不儲存norms資訊 Index.NO:不進行索引 lucene4.5例子:
import java.io.File;import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.standard.StandardAnalyzer;import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.document.FieldType;import org.apache.lucene.document.StringField;import org.apache.lucene.document.TextField;import org.apache.lucene.index.DirectoryReader;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.IndexWriterConfig;import org.apache.lucene.queryparser.classic.QueryParser;import org.apache.lucene.search.IndexSearcher;import org.apache.lucene.search.Query;import org.apache.lucene.search.ScoreDoc;import org.apache.lucene.search.TopDocs;import org.apache.lucene.store.Directory;import org.apache.lucene.store.FSDirectory;import org.apache.lucene.util.Version;public class IndexUtil { private static final String[] ids = { "1", "2", "3" }; private static final String[] authors = { "Darren", "Tony", "Grylls" }; private static final String[] titles = { "Hello World", "Hello Lucene", "Hello Java" }; private static final String[] contents = { "Hello World, I am on my way", "Today is my first day to study Lucene", "I like Java" }; /** * 建立索引 */ public static void index() { IndexWriter indexWriter = null; try { // 1、建立Directory Directory directory = FSDirectory.open(new File("F:/test/lucene/index")); // 2、建立IndexWriter Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45); IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_45, analyzer); indexWriter = new IndexWriter(directory, config); int size = ids.length; for (int i = 0; i < size; i++) { // 3、建立Document對象 Document document = new Document(); // 看看四個參數的意思 // 4、為Document添加Field /** * Create field with String value. * * @param name * field name * @param value * string value * @param type * field type * @throws IllegalArgumentException * if either the name or value is null, or if the field‘s type is neither indexed() nor * stored(), or if indexed() is false but storeTermVectors() is true. * @throws NullPointerException * if the type is null * * public Field(String name, String value, FieldType type) */ /** * 注意:這裡與3.5版本不同,原來的建構函式已淘汰 */ /** * 註:這裡4.5版本使用FieldType代替了原來的Store和Index,不同的Field預定義了一些FieldType * */ // 對ID儲存,但是不分詞也不儲存norms資訊 FieldType idType = TextField.TYPE_STORED; idType.setIndexed(false); idType.setOmitNorms(false); document.add(new Field("id", ids[i], idType)); // 對Author儲存,但是不分詞 FieldType authorType = TextField.TYPE_STORED; authorType.setIndexed(false); document.add(new Field("author", authors[i], authorType)); // 對Title儲存,分詞 document.add(new Field("title", titles[i], StringField.TYPE_STORED)); // 對Content不儲存,但是分詞 document.add(new Field("content", contents[i], TextField.TYPE_NOT_STORED)); // 5、通過IndexWriter添加文檔到索引中 indexWriter.addDocument(document); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (indexWriter != null) { indexWriter.close(); } } catch (Exception e) { e.printStackTrace(); } } } /** * 搜尋 */ public static void search() { DirectoryReader indexReader = null; try { // 1、建立Directory Directory directory = FSDirectory.open(new File("F:/test/lucene/index")); // 2、建立IndexReader /** * 注意Reader與3.5版本不同: * * 所以使用DirectoryReader * * @Deprecated public static DirectoryReader open(final Directory directory) throws IOException { return * DirectoryReader.open(directory); } */ indexReader = DirectoryReader.open(directory); // 3、根據IndexReader建立IndexSearch IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 4、建立搜尋的Query // 使用預設的標準分詞器 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45); // 在content中搜尋Lucene // 建立parser來確定要搜尋檔案的內容,第二個參數為搜尋的域 QueryParser queryParser = new QueryParser(Version.LUCENE_45, "content", analyzer); // 建立Query表示搜尋域為content包含Lucene的文檔 Query query = queryParser.parse("Lucene"); // 5、根據searcher搜尋並且返回TopDocs TopDocs topDocs = indexSearcher.search(query, 10); // 6、根據TopDocs擷取ScoreDoc對象 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { // 7、根據searcher和ScoreDoc對象擷取具體的Document對象 Document document = indexSearcher.doc(scoreDoc.doc); // 8、根據Document對象擷取需要的值 System.out.println("id : " + document.get("id")); System.out.println("author : " + document.get("author")); System.out.println("title : " + document.get("title")); /** * 看看content能不能列印出來,為什嗎? */ System.out.println("content : " + document.get("content")); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (indexReader != null) { indexReader.close(); } } catch (Exception e) { e.printStackTrace(); } } }}
Lucene入門學習