lucene第一步,lucene基礎,索引建立

風的王子發表於2013-08-09

出自:http://blog.csdn.net/wxwzy738/article/details/8799184 的整理


1、工程結構


2、索引建立時的屬性:

Field.Store.YES或者NO(儲存域選項)
設定為YES表示或把這個域中的內容完全儲存到檔案中,方便進行文字的還原
設定為NO表示把這個域的內容不儲存到檔案中,但是可以被索引,此時內容無法完全還原(doc.get)

Field.Index(索引選項)
Index.ANALYZED:進行分詞和索引,適用於標題、內容等
Index.NOT_ANALYZED:進行索引,但是不進行分詞,如果身份證號,姓名,ID等,適用於精確搜尋
Index.ANALYZED_NOT_NORMS:進行分詞但是不儲存norms資訊,這個norms中包括了建立索引的時間和權值等資訊
norms中儲存了很多排序的資訊,
Index.NOT_ANALYZED_NOT_NORMS:即不進行分詞也不儲存norms資訊
Index.NO:不進行索引 

3、lucene的增刪改查類

  1. package org.itat.index;  
  2.   
  3. import java.io.IOException;  
  4. import java.text.ParseException;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.Date;  
  7. import java.util.HashMap;  
  8. import java.util.Map;  
  9. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  10. import org.apache.lucene.document.Document;  
  11. import org.apache.lucene.document.Field;  
  12. import org.apache.lucene.document.NumericField;  
  13. import org.apache.lucene.index.CorruptIndexException;  
  14. import org.apache.lucene.index.IndexReader;  
  15. import org.apache.lucene.index.IndexWriter;  
  16. import org.apache.lucene.index.IndexWriterConfig;  
  17. import org.apache.lucene.index.StaleReaderException;  
  18. import org.apache.lucene.index.Term;  
  19. import org.apache.lucene.search.IndexSearcher;  
  20. import org.apache.lucene.search.ScoreDoc;  
  21. import org.apache.lucene.search.TermQuery;  
  22. import org.apache.lucene.search.TopDocs;  
  23. import org.apache.lucene.store.Directory;  
  24. import org.apache.lucene.store.LockObtainFailedException;  
  25. import org.apache.lucene.store.RAMDirectory;  
  26. import org.apache.lucene.util.Version;  
  27.   
  28.   
  29. public class IndexUtil {  
  30.     private String[] ids = {"1","2","3","4","5","6"};  
  31.     private String[] emails = {"aa@itat.org","bb@itat.org","cc@cc.org","dd@sina.org","ee@zttc.edu","ff@itat.org"};  
  32.     private String[] contents = {  
  33.             "welcome to visited the space,I like book",  
  34.             "hello boy, I like pingpeng ball",  
  35.             "my name is cc I like game",  
  36.             "I like football",  
  37.             "I like football and I like basketball too",  
  38.             "I like movie and swim"  
  39.     };  
  40.     private Date[] dates = null;  
  41.     private int[] attachs = {2,3,1,4,5,5};  
  42.     private String[] names = {"zhangsan","lisi","john","jetty","mike","jake"};  
  43.     private Directory directory = null;  
  44.     private Map<String,Float> scores = new HashMap<String,Float>();  
  45.     private static IndexReader reader = null;  
  46.       
  47.     public IndexUtil() {  
  48.         try {  
  49.             setDates();  
  50.             scores.put("itat.org",2.0f);  
  51.             scores.put("zttc.edu"1.5f);  
  52.             //directory = FSDirectory.open(new File("d:/lucene/index02"));  
  53.             directory = new RAMDirectory();  
  54.             index();  
  55.             reader = IndexReader.open(directory,false);  
  56.         } catch (IOException e) {  
  57.             e.printStackTrace();  
  58.         }  
  59.     }  
  60.       
  61.     /** 
  62.      * 對於IndexReader而言,反覆使用Index.open開啟會有很大的開銷,所以一般在整個程式的生命週期中 
  63.      * 只會開啟一個IndexReader,通過這個IndexReader來建立不同的IndexSearcher,如果使用單例模式, 
  64.      * 可能出現的問題有: 
  65.      * 1、當使用Writer修改了索引之後不會更新資訊,所以需要使用IndexReader.openIfChange方法操作 
  66.      * 如果IndexWriter在建立完成之後,沒有關閉,需要進行commit操作之後才能提交 
  67.      * @return 
  68.      */  
  69.     public IndexSearcher getSearcher() {  
  70.         try {  
  71.             if(reader==null) {  
  72.                 reader = IndexReader.open(directory,false);  
  73.             } else {  
  74.                 IndexReader tr = IndexReader.openIfChanged(reader);  
  75.                 //如果原來的reader沒改變,返回null  
  76.                 //如果原來的reader改變,則更新為新的索引  
  77.                 if(tr!=null) {  
  78.                     reader.close();  
  79.                     reader = tr;  
  80.                 }  
  81.             }  
  82.             return new IndexSearcher(reader);  
  83.         } catch (CorruptIndexException e) {  
  84.             e.printStackTrace();  
  85.         } catch (IOException e) {  
  86.             e.printStackTrace();  
  87.         }  
  88.         return null;  
  89.           
  90.     }  
  91.       
  92.     private void setDates() {  
  93.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  
  94.         try {  
  95.             dates = new Date[ids.length];  
  96.             dates[0] = sdf.parse("2010-02-19");  
  97.             dates[1] = sdf.parse("2012-01-11");  
  98.             dates[2] = sdf.parse("2011-09-19");  
  99.             dates[3] = sdf.parse("2010-12-22");  
  100.             dates[4] = sdf.parse("2012-01-01");  
  101.             dates[5] = sdf.parse("2011-05-19");  
  102.         } catch (ParseException e) {  
  103.             e.printStackTrace();  
  104.         }  
  105.     }  
  106.     /** 
  107.      * 把之前刪除的索引資料進行恢復 
  108.      */  
  109.     public void undelete() {  
  110.         //使用IndexReader進行恢復  
  111.         try {  
  112.             IndexReader reader = IndexReader.open(directory,false);  
  113.             //恢復時,必須把IndexReader的只讀(readOnly)設定為false  
  114.             reader.undeleteAll();  
  115.             reader.close();  
  116.         } catch (CorruptIndexException e) {  
  117.             e.printStackTrace();  
  118.         } catch (StaleReaderException e) {  
  119.             e.printStackTrace();  
  120.         } catch (LockObtainFailedException e) {  
  121.             e.printStackTrace();  
  122.         } catch (IOException e) {  
  123.             e.printStackTrace();  
  124.         }  
  125.     }  
  126.     /** 
  127.      * forceMerge是lucene3.5之前替代optimize方法的,其實只是改了個名稱,因為優化的使效率變低 
  128.      * 因為一到優化它就會全部更新索引,這個所涉及到的負載是很大的 
  129.      * 所以改了個名稱,不推薦使用,在做優化的時候會把索引回收站中的資料檔案全部刪除 
  130.      * lucene會在你寫索引的時候根據你的索引的段越來越多會自動幫忙優化的,force是強制優化 
  131.      */  
  132.     public void merge() {  
  133.         IndexWriter writer = null;  
  134.         try {  
  135.             writer = new IndexWriter(directory,  
  136.                     new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)));  
  137.             //會將索引合併為2段,這兩段中的被刪除的資料會被清空  
  138.             //特別注意:此處Lucene在3.5之後不建議使用,因為會消耗大量的開銷,  
  139.             //Lucene會根據情況自動處理的  
  140.             writer.forceMerge(2);  
  141.         } catch (CorruptIndexException e) {  
  142.             e.printStackTrace();  
  143.         } catch (LockObtainFailedException e) {  
  144.             e.printStackTrace();  
  145.         } catch (IOException e) {  
  146.             e.printStackTrace();  
  147.         } finally {  
  148.             try {  
  149.                 if(writer!=null) writer.close();  
  150.             } catch (CorruptIndexException e) {  
  151.                 e.printStackTrace();  
  152.             } catch (IOException e) {  
  153.                 e.printStackTrace();  
  154.             }  
  155.         }  
  156.     }  
  157.   
  158.     /** 
  159.      * 假如你想要強制刪除回收站的資訊可以呼叫writer.forceMergeDeletes()這個方法, 
  160.      * 但是這個方法不推薦使用,比較消耗記憶體,lucene會自動根據容量的大小刪除所刪除的檔案 
  161.      */  
  162.     public void forceDelete() {  
  163.         IndexWriter writer = null;  
  164.           
  165.         try {  
  166.             writer = new IndexWriter(directory,  
  167.                     new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)));  
  168.             writer.forceMergeDeletes();  
  169.         } catch (CorruptIndexException e) {  
  170.             e.printStackTrace();  
  171.         } catch (LockObtainFailedException e) {  
  172.             e.printStackTrace();  
  173.         } catch (IOException e) {  
  174.             e.printStackTrace();  
  175.         } finally {  
  176.             try {  
  177.                 if(writer!=null) writer.close();  
  178.             } catch (CorruptIndexException e) {  
  179.                 e.printStackTrace();  
  180.             } catch (IOException e) {  
  181.                 e.printStackTrace();  
  182.             }  
  183.         }  
  184.     }  
  185.     /** 
  186.      * 刪除索引資料,預設不會完全刪除,被放入索引回收站 
  187.      */  
  188.     public void delete() {  
  189.         IndexWriter writer = null;  
  190.           
  191.         try {  
  192.             writer = new IndexWriter(directory,  
  193.                     new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)));  
  194.             //引數是一個選項,可以是一個Query,也可以是一個term,term是一個精確查詢的值  
  195.             //此時刪除的文件並不會被完全刪除,而是儲存在一個回收站中的,可以恢復  
  196.             //執行完這個操作,索引資料夾下就會多出一個名叫_0_1.del的檔案,也就是刪除的檔案在這個檔案中記錄了  
  197.             writer.deleteDocuments(new Term("id","1"));  
  198.             writer.commit();  
  199.         } catch (CorruptIndexException e) {  
  200.             e.printStackTrace();  
  201.         } catch (LockObtainFailedException e) {  
  202.             e.printStackTrace();  
  203.         } catch (IOException e) {  
  204.             e.printStackTrace();  
  205.         } finally {  
  206.             try {  
  207.                 if(writer!=null) writer.close();  
  208.             } catch (CorruptIndexException e) {  
  209.                 e.printStackTrace();  
  210.             } catch (IOException e) {  
  211.                 e.printStackTrace();  
  212.             }  
  213.         }  
  214.     }  
  215.     /** 
  216.      * 使用reader刪除,其實裡面也會呼叫writer刪除, 
  217.      * 優點是使用reader刪除馬上會更新索引資訊 
  218.      * 現在一般還是使用writer來刪除,reader.getWriter這個方法被過時了 
  219.      */  
  220.     public void delete02() {  
  221.         try {  
  222.             reader.deleteDocuments(new Term("id","1"));  
  223.         } catch (CorruptIndexException e) {  
  224.             e.printStackTrace();  
  225.         } catch (LockObtainFailedException e) {  
  226.             e.printStackTrace();  
  227.         } catch (IOException e) {  
  228.             e.printStackTrace();  
  229.         }  
  230.     }  
  231.     /** 
  232.      * 更新操作 
  233.      * Lucene並沒有提供更新,這裡的更新操作其實是如下兩個操作的合集 
  234.      * 先刪除之後再新增 
  235.      */  
  236.     public void update() {  
  237.         IndexWriter writer = null;  
  238.         try {  
  239.             writer = new IndexWriter(directory,  
  240.                     new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)));  
  241.             Document doc = new Document();  
  242.             doc.add(new Field("id","11",Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));  
  243.             doc.add(new Field("email",emails[0],Field.Store.YES,Field.Index.NOT_ANALYZED));  
  244.             doc.add(new Field("content",contents[0],Field.Store.NO,Field.Index.ANALYZED));  
  245.             doc.add(new Field("name",names[0],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));  
  246.             writer.updateDocument(new Term("id","1"), doc);  
  247.         } catch (CorruptIndexException e) {  
  248.             e.printStackTrace();  
  249.         } catch (LockObtainFailedException e) {  
  250.             e.printStackTrace();  
  251.         } catch (IOException e) {  
  252.             e.printStackTrace();  
  253.         } finally {  
  254.             try {  
  255.                 if(writer!=null) writer.close();  
  256.             } catch (CorruptIndexException e) {  
  257.                 e.printStackTrace();  
  258.             } catch (IOException e) {  
  259.                 e.printStackTrace();  
  260.             }  
  261.         }  
  262.     }  
  263.       
  264.     public void query() {  
  265.         try {  
  266.             IndexReader reader = IndexReader.open(directory);  
  267.             //通過reader可以有效的獲取到文件的數量  
  268.             System.out.println("numDocs:"+reader.numDocs());//儲存的文件數//不包括被刪除的  
  269.             System.out.println("maxDocs:"+reader.maxDoc());//總儲存量,包括在回收站中的索引  
  270.             System.out.println("deleteDocs:"+reader.numDeletedDocs());  
  271.             reader.close();  
  272.         } catch (CorruptIndexException e) {  
  273.             e.printStackTrace();  
  274.         } catch (IOException e) {  
  275.             e.printStackTrace();  
  276.         }  
  277.     }  
  278.     /** 
  279.      *  索引檔案字尾為.fmn為儲存的是域的名稱等 
  280.      * .fdt和.fdx儲存的是Store.YES的資訊,儲存域裡面儲存的資料 
  281.      * .frq表示這裡的域哪些出現多少次,哪些單詞出現多少次, 
  282.      * .nrm儲存一些評分資訊 
  283.      * .prx儲存一些偏移量等 
  284.      * .tii和.tis專門儲存索引裡面的所有內容資訊 
  285.      */  
  286.     public void index() {  
  287.         IndexWriter writer = null;  
  288.         try {  
  289.             //在2.9版本之後,lucene的就不是全部的索引格式都相容的了,所以在使用的時候必須寫明版本號  
  290.             writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));  
  291.             writer.deleteAll();//清空索引  
  292.             Document doc = null;  
  293.             for(int i=0;i<ids.length;i++) {  
  294.                 doc = new Document();  
  295.                 doc.add(new Field("id",ids[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));  
  296.                 doc.add(new Field("email",emails[i],Field.Store.YES,Field.Index.NOT_ANALYZED));  
  297.                 doc.add(new Field("email","test"+i+"@test.com",Field.Store.YES,Field.Index.NOT_ANALYZED));  
  298.                 doc.add(new Field("content",contents[i],Field.Store.NO,Field.Index.ANALYZED));  
  299.                 doc.add(new Field("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));  
  300.                 //儲存數字  
  301.                 //NumberTools.stringToLong("");已經被標記為過時了  
  302.                 doc.add(new NumericField("attach",Field.Store.YES,true).setIntValue(attachs[i]));  
  303.                 //儲存日期  
  304.                 doc.add(new NumericField("date",Field.Store.YES,true).setLongValue(dates[i].getTime()));  
  305.                 String et = emails[i].substring(emails[i].lastIndexOf("@")+1);  
  306.                 System.out.println(et);  
  307.                 if(scores.containsKey(et)) {  
  308.                     doc.setBoost(scores.get(et));  
  309.                 } else {  
  310.                     doc.setBoost(0.5f);//預設是1.0f  
  311.                 }  
  312.                 writer.addDocument(doc);  
  313.             }  
  314.         } catch (CorruptIndexException e) {  
  315.             e.printStackTrace();  
  316.         } catch (LockObtainFailedException e) {  
  317.             e.printStackTrace();  
  318.         } catch (IOException e) {  
  319.             e.printStackTrace();  
  320.         } finally {  
  321.             try {  
  322.                 if(writer!=null)writer.close();  
  323.             } catch (CorruptIndexException e) {  
  324.                 e.printStackTrace();  
  325.             } catch (IOException e) {  
  326.                 e.printStackTrace();  
  327.             }  
  328.         }  
  329.     }  
  330.       
  331.     public void search01() {  
  332.         try {  
  333.             IndexReader reader = IndexReader.open(directory);  
  334.             IndexSearcher searcher = new IndexSearcher(reader);  
  335.             TermQuery query = new TermQuery(new Term("email","test0@test.com"));  
  336.             TopDocs tds = searcher.search(query, 10);  
  337.             for(ScoreDoc sd:tds.scoreDocs) {  
  338.                 Document doc = searcher.doc(sd.doc);  
  339.                 System.out.println("("+sd.doc+"-"+doc.getBoost()+"-"+sd.score+")"+  
  340.                         doc.get("name")+"["+doc.get("email")+"]-->"+doc.get("id")+","+  
  341.                         doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);  
  342.             }  
  343.             reader.close();  
  344.         } catch (CorruptIndexException e) {  
  345.             e.printStackTrace();  
  346.         } catch (IOException e) {  
  347.             e.printStackTrace();  
  348.         }  
  349.     }  
  350.       
  351.     public void search02() {  
  352.         try {  
  353.             IndexSearcher searcher = getSearcher();  
  354.             TermQuery query = new TermQuery(new Term("content","like"));  
  355.             TopDocs tds = searcher.search(query, 10);  
  356.             for(ScoreDoc sd:tds.scoreDocs) {  
  357.                 Document doc = searcher.doc(sd.doc);  
  358.                 System.out.println(doc.get("id")+"---->"+  
  359.                         doc.get("name")+"["+doc.get("email")+"]-->"+doc.get("id")+","+  
  360.                         doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);  
  361.             }  
  362.             searcher.close();  
  363.         } catch (CorruptIndexException e) {  
  364.             e.printStackTrace();  
  365.         } catch (IOException e) {  
  366.             e.printStackTrace();  
  367.         }  
  368.     }  
  369.   
  370. }  
4、lucene的單元測試類
  1. package org.itat.test;  
  2.   
  3. import org.itat.index.IndexUtil;  
  4. import org.junit.Test;  
  5.   
  6. public class TestIndex {  
  7.       
  8.     @Test  
  9.     public void testIndex() {  
  10.         IndexUtil iu = new IndexUtil();  
  11.         iu.index();  
  12.     }  
  13.       
  14.     @Test  
  15.     public void testQuery() {  
  16.         IndexUtil iu = new IndexUtil();  
  17.         iu.query();  
  18.     }  
  19.       
  20.     @Test  
  21.     public void testDelete() {  
  22.         IndexUtil iu = new IndexUtil();  
  23.         iu.delete();  
  24.     }  
  25.       
  26.     @Test  
  27.     public void testDelete02() {  
  28.         IndexUtil iu = new IndexUtil();  
  29.         iu.delete02();  
  30.     }  
  31.       
  32.     @Test  
  33.     public void testUnDelete() {  
  34.         IndexUtil iu = new IndexUtil();  
  35.         iu.undelete();  
  36.     }  
  37.       
  38.     @Test  
  39.     public void testForceDelete() {  
  40.         IndexUtil iu = new IndexUtil();  
  41.         iu.forceDelete();  
  42.     }  
  43.       
  44.     @Test  
  45.     public void testMerge() {  
  46.         IndexUtil iu = new IndexUtil();  
  47.         iu.merge();  
  48.     }  
  49.       
  50.     @Test  
  51.     public void testUpdate() {  
  52.         IndexUtil iu = new IndexUtil();  
  53.         iu.update();  
  54.     }  
  55.       
  56.     @Test  
  57.     public void testSearch01() {  
  58.         IndexUtil iu = new IndexUtil();  
  59.         iu.search01();  
  60.     }  
  61.       
  62.     @Test  
  63.     public void testSearch02() {  
  64.         IndexUtil iu = new IndexUtil();  
  65.         for(int i=0;i<5;i++) {  
  66.             iu.search02();  
  67.             System.out.println("-----------------------------");  
  68.             try {  
  69.                 Thread.sleep(10000);  
  70.             } catch (InterruptedException e) {  
  71.                 e.printStackTrace();  
  72.             }  
  73.         }  
  74.     }  

相關文章