一. 我本來的程序
其實我原本的程式挺簡單, 完全修改自Demo裡面的SearchFiles和IndexFiles. 唯一不同的是引用了SmartCN的分詞器.
我把修改那一點的程式碼貼出來.
IndexhChinese.java:
Date start = new Date();try { IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new SmartChineseAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED);indexth.LIMITED); .println("Indexing to directory '" +INDEX_DIR+ "'..."); System.out.println("Optimizing..."); //writer.optimize(); writer.close(); Date end = new Date(); System.out.println(end.getTime() - start.getTime() + " total milliseconds"); }
SearchChinese.java
Analyzer analyzer = new SmartChineseAnalyzer(Version.LUCENE_CURRENT); BufferedReader in = null;if (queries != null) { in = new BufferedReader(new FileReader(queries));} else { in = new BufferedReader(new Inputin. , "GBK"));}
在這裡, 我制定了輸入的查詢是採用GBK編碼的.
然後我充滿信心的運行後......發現無法檢索出中文, 裡面的英文檢索是正常的.
二. 發現問題.
於是我就鬱悶了, 由於對於java與lucene都是太熟悉, 而且用的3.0.0版外面的討論又不是太多, 就瞎折騰了一會兒, 發現我如果把文件的格式另存為ansi就可以檢索中文了(以前是utf-8的), 看來是文件編碼的問題, 摸索了一下, 在indexChinese.java中發現瞭如下的代碼:
static void indexDocs(IndexWriter writer, File file) throws IOException { // do not try to index files that cannot be read if (file.canRead()) { if (file.isDirectory()) { String[] files = file. list(); // an IO error could occur if (files != null) { for (int i = 0; i < files.length; i++) { indexDocs(writer, new File(file, files[i])) ; } } } else { System.out.println("adding " + file); try { writer.addDocument(FileDocument.Document(file)); } // at least on windows, some temporary files raise this exception with an " access denied" message // checking if the file can be read doesn't help catch (FileNotFoundException fnfe) { ; } } }
重點在於這一句:
try { writer.addDocument(FileDocument.Document(file));}
讀取檔案的程式碼應該就在這裡面, 追蹤進去:
public static Document Document(File f) throws java.io.FileNotFoundException, UnsupportedEncodingException { Document doc = new Document(); doc.add(new Field("path", f.getPath(), Field.Store.YES, Field. Index.NOT_ANALYZED)); doc.add(new Field("modified", DateTools.timeToString(f.lastModified(), DateTools.Resolution.MINUTE), Field.Store.YES, Field.Index.NOT_ANALYZED)); doc. add(new Field("contents", FileReader(f))); // return the document return doc;} private FileDocument() {}}
這是Lucene的一個內部類別, 作用就是從一個文字檔案中取得內容, 產生的Document預設有3個網域: path, modified, content, 而content就是檔案的文字內容了. 看來是FileReader(f),這個函數出了問題了, 根本沒有製定採用什麼編碼進行讀取啊, 於是把這兒簡單的修改了一下.
FileInputStream fis=new FileInputStream(f);// 依照UTF-8 編碼方式將位元組流轉換為字元流InputStreamReader isr=new InputStreamReader(fis,"UNICODE");// 從字元流取得文字並進行緩衝BufferedReader br=new BufferedReader(isr); doc.add(new Field("contents", br));
至於那個"Unicode"可以修改為支援的所有編碼, 當我修改為"utf-8"後就可以正常使用了.
三. 一些猜測:
對於Lucene索引檔的時候, 編碼是沒有關係的, 只要正確指定了, 那麼輸出的檔案都是可以被正常檢索到的, 也就是說, 不同的編碼檔案索引後的結果一樣(求證)