1. 程式人生 > >Java搜尋工具——Lucene例項總結(一)

Java搜尋工具——Lucene例項總結(一)

    搞了一天半,終於利用lucene工具Demo完了我想要的功能,這其中包括為資料庫建立增量索引、從索引檔案根據id刪除索引、單欄位查詢功能、多欄位查詢功能、多條件查詢功能以及查詢結果關鍵字高亮顯示的功能。今天晚些的時候把這些功能進行了整理。看樣子一時半會還下不了班,就把Demo的結果 一 一 列舉下來吧。。。

1. 所需要的檔案(見附件)

    依賴包:

    lucene-core-2.4.0.jar                   lucene工具包

    lucene-highlighter-2.4.0.jar          高亮顯示工具包

    IKAnalyzer2.0.2OBF.jar                分詞工具(支援字典分詞)

    mysql-connector-java-5.0.3-bin    連結mysql驅動

    資料表:

    pd_ugc.sql(所在資料庫為lucenetest)

    類檔案:

    在附件index.rar和test.rar,解壓後放入java工程中的src下即可

2. 為資料庫建立增量索引

    參考網頁:http://www.blogjava.net/laoding/articles/279230.html

Java程式碼  收藏程式碼
  1. package index;  
  2. //--------------------- Change Logs----------------------
      
  3. // <p>@author zhiqiang.zhang Initial Created at 2010-12-23<p>  
  4. //-------------------------------------------------------  
  5. import java.io.BufferedReader;  
  6. import java.io.File;  
  7. import java.io.FileReader;  
  8. import java.io.FileWriter;  
  9. import java.io.IOException;  
  10. import java.io.PrintWriter;  
  11. import
     java.sql.Connection;  
  12. import java.sql.DriverManager;  
  13. import java.sql.ResultSet;  
  14. import java.sql.Statement;  
  15. import java.util.Date;  
  16. import org.apache.lucene.analysis.Analyzer;  
  17. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  18. import org.apache.lucene.document.Document;  
  19. import org.apache.lucene.document.Field;  
  20. import org.apache.lucene.index.IndexWriter;  
  21. //增量索引  
  22. /* 
  23.  * 實現思路:首次查詢資料庫表所有記錄,對每條記錄建立索引,並將最後一條記錄的id儲存到storeId.txt檔案中 
  24.  *         當新插入一條記錄時,再建立索引時不必再對所有資料重新建一遍索引, 
  25.  *         可根據存放在storeId.txt檔案中的id查出新插入的資料,只對新增的資料新建索引,並把新增的索引追加到原來的索引檔案中 
  26.  * */  
  27. public class IncrementIndex {  
  28.     public static void main(String[] args) {  
  29.         try {  
  30.             IncrementIndex index = new IncrementIndex();  
  31.             String path = "E:\\workspace2\\Test\\lucene_test\\poiIdext";//索引檔案的存放路徑  
  32.             String storeIdPath = "E:\\workspace2\\Test\\lucene_test\\storeId.txt";//儲存ID的路徑  
  33.             String storeId = "";  
  34.             Date date1 = new Date();  
  35.             storeId = index.getStoreId(storeIdPath);  
  36.             ResultSet rs = index.getResult(storeId);  
  37.             System.out.println("開始建立索引。。。。");  
  38.             index.indexBuilding(path, storeIdPath, rs);  
  39.             Date date2 = new Date();  
  40.             System.out.println("耗時:"+(date2.getTime()-date1.getTime())+"ms");  
  41.             storeId = index.getStoreId(storeIdPath);  
  42.             System.out.println(storeId);//打印出這次儲存起來的ID  
  43.         } catch (Exception e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47.     public static void buildIndex(String indexFile, String storeIdFile) {  
  48.         try {  
  49.             String path = indexFile;//索引檔案的存放路徑  
  50.             String storeIdPath = storeIdFile;//儲存ID的路徑  
  51.             String storeId = "";  
  52.             storeId = getStoreId(storeIdPath);  
  53.             ResultSet rs = getResult(storeId);  
  54.             indexBuilding(path, storeIdPath, rs);  
  55.             storeId = getStoreId(storeIdPath);  
  56.             System.out.println(storeId);//打印出這次儲存起來的ID  
  57.         } catch (Exception e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.     }  
  61.     public static ResultSet getResult(String storeId) throws Exception {  
  62.         Class.forName("com.mysql.jdbc.Driver").newInstance();  
  63.         String url = "jdbc:mysql://localhost:3306/lucenetest";  
  64.         String userName = "root";  
  65.         String password = "****";  
  66.         Connection conn = DriverManager.getConnection(url, userName, password);  
  67.         Statement stmt = conn.createStatement();  
  68.         String sql = "select  * from pd_ugc";  
  69.         ResultSet rs = stmt.executeQuery(sql + " where id > '" + storeId + "'order by id");  
  70.         return rs;  
  71.     }  
  72.     public static boolean indexBuilding(String path, String storeIdPath, ResultSet rs) {  
  73.         try {  
  74.             Analyzer luceneAnalyzer = new StandardAnalyzer();  
  75.             // 取得儲存起來的ID,以判定是增量索引還是重新索引  
  76.             boolean isEmpty = true;  
  77.             try {  
  78.                 File file = new File(storeIdPath);  
  79.                 if (!file.exists()) {  
  80.                     file.createNewFile();  
  81.                 }  
  82.                 FileReader fr = new FileReader(storeIdPath);  
  83.                 BufferedReader br = new BufferedReader(fr);  
  84.                 if (br.readLine() != null) {  
  85.                     isEmpty = false;  
  86.                 }  
  87.                 br.close();  
  88.                 fr.close();  
  89.             } catch (IOException e) {  
  90.                 e.printStackTrace();  
  91.             }  
  92.             //isEmpty=false表示增量索引  
  93.             IndexWriter writer = new IndexWriter(path, luceneAnalyzer, isEmpty);  
  94.             String storeId = "";  
  95.             boolean indexFlag = false;  
  96.             String id;  
  97.             String name;  
  98.             String address;  
  99.             String citycode;  
  100.             while (rs.next()) {  
  101.                 id = rs.getInt("id") + "";  
  102.                 name = rs.getString("name");  
  103.                 address = rs.getString("address");  
  104.                 citycode = rs.getString("citycode");  
  105.                 writer.addDocument(Document(id, name, address, citycode));  
  106.                 storeId = id;//將拿到的id給storeId,這種拿法不合理,這裡為了方便  
  107.                 indexFlag = true;  
  108.             }  
  109.             writer.optimize();  
  110.             writer.close();  
  111.             if (indexFlag) {  
  112.                 // 將最後一個的ID存到磁碟檔案中  
  113.                 writeStoreId(storeIdPath, storeId);  
  114.             }  
  115.             return true;  
  116.         } catch (Exception e) {  
  117.             e.printStackTrace();  
  118.             System.out.println("出錯了" + e.getClass() + "\n   錯誤資訊為:   " + e.getMessage());  
  119.             return false;  
  120.         }  
  121.     }  
  122.     public static Document Document(String id, String name, String address, String citycode) {  
  123.         Document doc = new Document();  
  124.         doc.add(new Field("id", id, Field.Store.YES, Field.Index.TOKENIZED));  
  125.         doc.add(new Field("name", name, Field.Store.YES, Field.Index.TOKENIZED));//查詢欄位  
  126.         doc.add(new Field("address", address, Field.Store.YES, Field.Index.TOKENIZED));  
  127.         doc.add(new Field("citycode", citycode, Field.Store.YES, Field.Index.TOKENIZED));//查詢欄位  
  128.         return doc;  
  129.     }  
  130.     // 取得儲存在磁碟中的ID  
  131.     public static String getStoreId(String path) {  
  132.         String storeId = "";  
  133.         try {  
  134.             File file = new File(path);  
  135.             if (!file.exists()) {  
  136.                 file.createNewFile();  
  137.             }  
  138.             FileReader fr = new FileReader(path);  
  139.             BufferedReader br = new BufferedReader(fr);  
  140.             storeId = br.readLine();  
  141.             if (storeId == null || storeId == "") storeId = "0";  
  142.             br.close();  
  143.             fr.close();  
  144.         } catch (Exception e) {  
  145.             e.printStackTrace();  
  146.         }  
  147.         return storeId;  
  148.     }  
  149.     // 將ID寫入到磁碟檔案中  
  150.     public static boolean writeStoreId(String path, String storeId) {  
  151.         boolean b = false;  
  152.         try {  
  153.             File file = new File(path);  
  154.             if (!file.exists()) {  
  155.                 file.createNewFile();  
  156.             }  
  157.             FileWriter fw = new FileWriter(path);  
  158.             PrintWriter out = new PrintWriter(fw);  
  159.             out.write(storeId);  
  160.             out.close();  
  161.             fw.close();  
  162.             b = true;  
  163.         } catch (IOException e) {  
  164.             e.printStackTrace();  
  165.         }  
  166.         return b;  
  167.     }  
  168. }  

3. 索引操作

Java程式碼  收藏程式碼
  1. package index;  
  2. import java.io.IOException;  
  3. import java.io.Reader;  
  4. import java.io.StringReader;  
  5. import java.util.ArrayList;  
  6. import java.util.Date;  
  7. import java.util.List;  
  8. import org.apache.lucene.analysis.Analyzer;  
  9. import org.apache.lucene.analysis.StopFilter;  
  10. import org.apache.lucene.analysis.Token;  
  11. import org.apache.lucene.analysis.TokenStream;  
  12. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  13. import org.apache.lucene.document.Document;  
  14. import org.apache.lucene.index.CorruptIndexException;  
  15. import org.apache.lucene.index.IndexReader;  
  16. import org.apache.lucene.index.Term;  
  17. import org.apache.lucene.queryParser.MultiFieldQueryParser;  
  18. import org.apache.lucene.queryParser.ParseException;  
  19. import org.apache.lucene.queryParser.QueryParser;  
  20. import org.apache.lucene.search.BooleanClause;  
  21. import org.apache.lucene.search.BooleanQuery;  
  22. import org.apache.lucene.search.Hits;  
  23. import org.apache.lucene.search.IndexSearcher;  
  24. import org.apache.lucene.search.Query;  
  25. import org.apache.lucene.search.ScoreDoc;  
  26. import org.apache.lucene.search.TopDocCollector;  
  27. import org.apache.lucene.search.highlight.Highlighter;  
  28. import org.apache.lucene.search.highlight.QueryScorer;  
  29. import org.apache.lucene.search.highlight.SimpleFragmenter;  
  30. import org.apache.lucene.search.highlight.SimpleHTMLFormatter;  
  31. import org.mira.lucene.analysis.IK_CAnalyzer;  
  32. public class IndexUtils {  
  33.     //0. 建立增量索引  
  34.     public static void buildIndex(String indexFile, String storeIdFile) {  
  35.         IncrementIndex.buildIndex(indexFile, storeIdFile);  
  36.     }  
  37.     //1. 單欄位查詢  
  38.     @SuppressWarnings("deprecation")  
  39.     public static List<IndexResult> queryByOneKey(IndexSearcher indexSearcher, String field,  
  40.             String key) {  
  41.         try {  
  42.             Date date1 = new Date();  
  43.             QueryParser queryParser = new QueryParser(field, new StandardAnalyzer());  
  44.             Query query = queryParser.parse(key);  
  45.             Hits hits = indexSearcher.search(query);  
  46.             Date date2 = new Date();  
  47.             System.out.println("耗時:" + (date2.getTime() - date1.getTime()) + "ms");  
  48.             List<IndexResult> list = new ArrayList<IndexResult>();  
  49.             for (int i = 0; i < hits.length(); i++) {  
  50.                 list.add(getIndexResult(hits.doc(i)));  
  51.             }  
  52.             return list;  
  53.         } catch (ParseException e) {  
  54.             e.printStackTrace();  
  55.         } catch (IOException e) {  
  56.             e.printStackTrace();  
  57.         }  
  58.         return null;  
  59.     }  
  60.     //2. 多條件查詢。這裡實現的是and操作  
  61.     //注:要查詢的欄位必須是index的  
  62.     //即doc.add(new Field("pid", rs.getString("pid"), Field.Store.YES,Field.Index.TOKENIZED));     
  63.     @SuppressWarnings("deprecation")  
  64.     public static List<IndexResult> queryByMultiKeys(IndexSearcher indexSearcher, String[] fields,  
  65.             String[] keys) {  
  66.         try {  
  67.             BooleanQuery m_BooleanQuery = new BooleanQuery();  
  68.             if (keys != null && keys.length > 0) {  
  69.                 for (int i = 0; i < keys.length; i++) {  
  70.                     QueryParser queryParser = new QueryParser(fields[i], new StandardAnalyzer());  
  71.                     Query query = queryParser.parse(keys[i]);  
  72.                     m_BooleanQuery.add(query, BooleanClause.Occur.MUST);//and操作  
  73.                 }  
  74.                 Hits hits = indexSearcher.search(m_BooleanQuery);  
  75.                 List<IndexResult> list = new ArrayList<IndexResult>();  
  76.                 for (int i = 0; i < hits.length(); i++) {  
  77.                     list.add(getIndexResult(hits.doc(i)));  
  78.                 }  
  79.                 return list;  
  80.             }  
  81.         } catch (ParseException e) {  
  82.             e.printStackTrace();  
  83.         } catch (IOException e) {  
  84.             e.printStackTrace();  
  85.         }  
  86.         return null;  
  87.     }  
  88.     //3.高亮顯示  實現了單條件查詢  
  89.     //可改造為多條件查詢  
  90.     public static List<IndexResult> highlight(IndexSearcher indexSearcher, String key) {  
  91.         try {  
  92.             QueryParser queryParser = new QueryParser("name"new StandardAnalyzer());  
  93.             Query query = queryParser.parse(key);  
  94.             TopDocCollector collector = new TopDocCollector(800);  
  95.             indexSearcher.search(query, collector);  
  96.             ScoreDoc[] hits = collector.topDocs().scoreDocs;  
  97.             Highlighter highlighter = null;  
  98.             SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<font color='red'>",  
  99.                     "</font>");  
  100.             highlighter = new Highlighter(simpleHTMLFormatter, new QueryScorer(query));  
  101.             highlighter.setTextFragmenter(new SimpleFragmenter(200));  
  102.             List<IndexResult> list = new ArrayList<IndexResult>();  
  103.             Document doc;  
  104.             for (int i = 0; i < hits.length; i++) {  
  105.                 //System.out.println(hits[i].score);  
  106.                 doc = indexSearcher.doc(hits[i].doc);  
  107.                 TokenStream tokenStream = new StandardAnalyzer().tokenStream("name",  
  108.                         new StringReader(doc.get("name")));  
  109.                 IndexResult ir = getIndexResult(doc);  
  110.                 ir.setName(highlighter.getBestFragment(tokenStream, doc.get("name")));  
  111.                 list.add(ir);  
  112.             }  
  113.             return list;  
  114.         } catch (ParseException e) {  
  115.             e.printStackTrace();  
  116.         } catch (IOException e) {  
  117.             e.printStackTrace();  
  118.         }  
  119.         return null;  
  120.     }  
  121.     //4. 多欄位查詢  
  122.     @SuppressWarnings("deprecation")  
  123.     public static List<IndexResult> queryByMultiFileds(IndexSearcher indexSearcher,  
  124.             String[] fields, String key) {  
  125.         try {  
  126.             MultiFieldQueryParser mfq = new MultiFieldQueryParser(fields, new StandardAnalyzer());  
  127.             Query query = mfq.parse(key);  
  128.             Hits hits = indexSearcher.search(query);  
  129.             List<IndexResult> list = new ArrayList<IndexResult>();  
  130.             for (int i = 0; i < hits.length(); i++) {  
  131.                 list.add(getIndexResult(hits.doc(i)));  
  132.             }  
  133.             return list;  
  134.         } catch (ParseException e) {  
  135.             e.printStackTrace();  
  136.         } catch (IOException e) {  
  137.             e.printStackTrace();  
  138.         }  
  139.         return null;  
  140.     }  
  141.     //5. 刪除索引  
  142.     public static void deleteIndex(String indexFile, String id) throws CorruptIndexException,  
  143.             IOException {  
  144.         IndexReader indexReader = IndexReader.open(indexFile);  
  145.         indexReader.deleteDocuments(new Term("id", id));  
  146.         indexReader.close();  
  147.     }  
  148.     //6. 一元分詞  
  149.     @SuppressWarnings("deprecation")  
  150.     public static String Standard_Analyzer(String str) {  
  151.         Analyzer analyzer = new StandardAnalyzer();  
  152.         Reader r = new StringReader(str);  
  153.         StopFilter sf = (StopFilter) analyzer.tokenStream("", r);  
  154.         System.out.println("=====StandardAnalyzer====");  
  155.         System.out.println("分析方法:預設沒有詞只有字(一元分詞)");  
  156.         Token t;  
  157.         String results = "";  
  158.         try {  
  159.             while ((t = sf.next()) != null) {  
  160.                 System.out.println(t.termText());  
  161.                 results = results + " " + t.termText();  
  162.             }  
  163.         } catch (IOException e) {  
  164.             e.printStackTrace();  
  165.         }  
  166.         return results;  
  167.     }  
  168.     //7. 字典分詞  
  169.     @SuppressWarnings("deprecation")  
  170.     public static String ik_CAnalyzer(String str) {  
  171.         Analyzer analyzer = new IK_CAnalyzer();  
  172.         Reader r = new StringReader(str);  
  173.         TokenStream ts = (TokenStream) analyzer.tokenStream("", r);  
  174.         System.out.println("=====IK_CAnalyzer====");  
  175.         System.out.println("分析方法:字典分詞,正反雙向搜尋");  
  176.         Token t;  
  177.         String results = "";  
  178.         try {  
  179.             while ((t = ts.next()) != null) {  
  180.                 System.out.println(t.termText());  
  181.                 results = results + " " + t.termText();  
  182.             }  
  183.         } catch (IOException e) {  
  184.             e.printStackTrace();  
  185.         }  
  186.         return results;  
  187.     }  
  188.     //在結果中搜索  
  189.     public static void queryFromResults() {  
  190.     }  
  191.     //組裝物件  
  192.     public static IndexResult getIndexResult(Document doc) {  
  193.         IndexResult ir = new IndexResult();  
  194.         ir.setId(doc.get("id"));  
  195.         ir.setName(doc.get("name"));  
  196.         ir.setAddress(doc.get("address"));  
  197.         ir.setCitycode(doc.get("citycode"));  
  198.         return ir;  
  199.     }  
  200. }  

    查詢索引結果物件:IndexResult

Java程式碼  收藏程式碼
  1. package index;  
  2. public class IndexResult {  
  3.     private String id;  
  4.     private String name;  
  5.     private String address;  
  6.     private String citycode;  
  7.     public String getId() {  
  8.         return id;  
  9.     }  
  10.     public void setId(String id) {  
  11.         this.id = id;  
  12.     }  
  13.     public String getName() {  
  14.         return name;  
  15.     }  
  16.     public void setName(String name) {  
  17.         this.name = name;  
  18.     }  
  19.     public String getAddress() {  
  20.         return address;  
  21.     }  
  22.     public void setAddress(String address) {  
  23.         this.address = address;  
  24.     }  
  25.     public String getCitycode() {  
  26.         return citycode;  
  27.     }  
  28.     public void setCitycode(String citycode) {  
  29.         this.citycode = citycode;  
  30.     }  
  31. }  

4. 測試類

Java程式碼  收藏程式碼
  1. package test;  
  2. /** 
  3.  * $Id$ 
  4.  * Copyright 2009-2010 Oak Pacific Interactive. All rights reserved. 
  5.  */  
  6. import index.IndexResult;  
  7. import index.IndexUtils;  
  8. import java.util.Date;  
  9. import java.util.List;  
  10. import org.apache.lucene.search.IndexSearcher;  
  11. public class Test {  
  12.     //存放索引檔案  
  13.     private static String indexFile = "E:\\workspace2\\Test\\lucene_test\\poiIdext";  
  14.     //存放id  
  15.     private static String storeIdFile = "E:\\workspace2\\Test\\lucene_test\\storeId.txt";  
  16.     public static void main(String[] args) throws Exception {  
  17.         //0. 建立增量索引  
  18.         IndexUtils.buildIndex(indexFile, storeIdFile);  
  19.         IndexSearcher indexSearcher = new IndexSearcher(indexFile);  
  20.         String key = IndexUtils.ik_CAnalyzer("靜安中心");  
  21.         //1.單欄位查詢  
  22.         Date date1 = new Date();  
  23.         List<IndexResult> list = IndexUtils.queryByOneKey(indexSearcher, "name", key);  
  24.         Date date2 = new Date();  
  25.         System.out.println("耗時:" + (date2.getTime() - date1.getTime()) + "ms\n" + list.size()  
  26.                 + "條=======================================單欄位查詢");  
  27.         //printResults(list);  
  28.         //2.多條件查詢  
  29.         String[] fields = { "name""citycode" };  
  30.         String[] keys = { IndexUtils.ik_CAnalyzer("靜安中心"), "0000" };  
  31.         date1 = new Date();  
  32.         list = IndexUtils.queryByMultiKeys(indexSearcher, fields, keys);  
  33.         date2 = new Date();  
  34.         System.out.println("耗時:" + (date2.getTime() - date1.getTime()) + "ms\n" + list.size()  
  35.                 + "條\n===============================多條件查詢");  
  36.         printResults(list);  
  37.         //3.高亮顯示  單欄位查詢  
  38.         System.out.println("\n\n");  
  39.         date1 = new Date();  
  40.         list = IndexUtils.highlight(indexSearcher, key);  
  41.         date2 = new Date();  
  42.         System.out.println("耗時:" + (date2.getTime() - date1.getTime()) + "ms\n" + list.size()  
  43.                 + "條\n======================================高亮顯示");  
  44.        // printResults(list);  
  45.         //4. 多欄位查詢  
  46.         date1 = new Date();  
  47.         list = IndexUtils.queryByMultiFileds(indexSearcher, fields, key);  
  48.         date2 = new Date();  
  49.         System.out.println("耗時:" + (date2.getTime() - date1.getTime()) + "ms\n" + list.size()  
  50.                 + "條\n=====================================多欄位查詢");  
  51.        // printResults(list);  
  52.         //5. 刪除索引中的欄位  根據id進行刪除  
  53.         IndexUtils.deleteIndex(indexFile, "123");  
  54.     }  
  55.     //列印結果  
  56.     public static void printResults(List<IndexResult> list) {  
  57.         if (list != null && list.size() > 0) {  
  58.             for (int i = 0; i < list.size(); i++) {  
  59.                 System.out.println(list.get(i).getId() + "," + list.get(i).getName() + ","  
  60.                         + list.get(i).getAddress() + "," + list.get(i).getCitycode()+"--->"+i);  
  61.             }  
  62.         }  
  63.     }  
  64. }  

5. 其它

全文索引:

目前的情況是,搜尋hello,"hello world"、"hi hello, how are you"但"worldhello"顯示不出來

預設情況下,QueryParser不支援萬用字元打頭的查詢(如,*ook)。不過在Lucene 2.1版本以後,他們可以通過呼叫QueryParser.setAllowLeadingWildcard( true )的 方法開啟這一功能。注意,這是一個開銷很大的操作:它需要掃描索引中全部記號的列表,來尋找匹配這個模式的詞。(譯註:高效支援這種字尾查詢的辦法是,建立反序的記號表,Lucene沒有實現這一模式。)http://www.codechina.org/faq/show/42/

支援空格分詞搜尋:"廁所 26 瀋陽" 這是三個詞

不支援:“廁所瀋陽”這是一個詞

http://www.codechina.org/faq/show/63/

可以。主要有兩種做法:

  • 使用QueryFilter把第一個查詢當作一個過濾器處理。(你可以在Lucene的郵件列表裡面搜尋 QueryFilter, Doug Cutting(Lucene的最初作者)反對這種做法。
  • BooleanQuery把前後兩個查詢結合起來,前一個查詢使用 required選項。

我們推薦使用BooleanQuery的方法。

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

 // 建立標準文字分析器, 標準的是可以支援的中文的

   Analyzer luceneAnalyzer = new StandardAnalyzer();

   indexWriter = new IndexWriter(indexDir, luceneAnalyzer, true);

   // 可以說是建立一個新的寫入工具

   // 第一個引數是要索引建立在哪個目錄裡

   // 第二個引數是新建一個文字分析器,這裡用的是標準的大家也可以自己寫一個

   // 第三個引數如果是true,在建立索引之前先將c: \\index目錄清空

poi_data_ugc搜尋中,索引放在記憶體裡還是磁碟上????

針對於lucene使用和優化

http://hi.baidu.com/lewutian/blog/item/48a86d03de58b984d43f7c1b.html

ucene入門例項(1):索引文字檔案

http://www.java3z.com/cwbwebhome/article/article5/51021.html