lucene索引的增删改查

1.全文检索系统的结构 
 
2.Lucene倒排索引原理 
假设有两篇文章1和2 
文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too. 
文章2的内容为:He once lived in Shanghai. 
经过分词处理后 
    文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou] 
    文章2的所有关键词为:[he] [live] [shanghai] 
加上“出现频率”和“出现位置”信息后,我们的索引结构为: 
 
3.索引的增删改查 
核心索引类: 
public class IndexWriter 
org.apache.lucene.index.IndexWriter 
public abstract class Directory 
org.apache.lucene.store.Directory 
public abstract class Analyzer 
org.apache.lucene.analysis.Analyzer 
public final class Document 
org.apache.lucene.document.Document 
public final class Field 
org.apache.lucene.document.Field 示例代码: 

Java代码   收藏代码
  1. package cn.yang;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.text.ParseException;  
  6. import java.text.SimpleDateFormat;  
  7. import java.util.Date;  
  8. import java.util.HashMap;  
  9. import java.util.Map;  
  10.   
  11. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  12. import org.apache.lucene.document.Document;  
  13. import org.apache.lucene.document.Field;  
  14. import org.apache.lucene.document.NumericField;  
  15. import org.apache.lucene.index.IndexReader;  
  16. import org.apache.lucene.index.IndexWriter;  
  17. import org.apache.lucene.index.IndexWriterConfig;  
  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.FSDirectory;  
  25. import org.apache.lucene.util.Version;  
  26.   
  27. public class IndexUtil {  
  28.     //准备数据  
  29.     private String[] ids = { "1""2""3""4""5""6" };  
  30.     private String[] emails = { "aa@yang.org""bb@sina.org""cc@aa.org""dd@qq.org",  
  31.             "ee@yahoo.org""ff@yi.org" };  
  32.     private String[] content = { "welcom to visited""hello boy",  
  33.             "my name is yang""liu meigui is a dog""haha fuck",  
  34.             "i like fuck liu" };  
  35.     private int[] attaches = { 244567 };  
  36.     private String[] names = { "zhangsan""lisi""yuhan""john""dav",  
  37.             "liu" };  
  38.     private Date[] dates = null;  
  39.       
  40.     //加权信息  
  41.     private Map<String,Float> scores = new HashMap<String,Float>();  
  42.   
  43.     private Directory directory = null;  
  44.       
  45.     //因IndexReader打开耗费资源 故使用静态的  
  46.     private static IndexReader reader = null;  
  47.       
  48.     //初始化日期  
  49.     public void setDates(){  
  50.         SimpleDateFormat sdf = new SimpleDateFormat("yyyymmdd");  
  51.         dates = new Date[ids.length];  
  52.         try {  
  53.             dates[0] = sdf.parse("2014-03-20");  
  54.             dates[1] = sdf.parse("2012-03-22");  
  55.             dates[2] = sdf.parse("2013-03-21");  
  56.             dates[3] = sdf.parse("2011-03-20");  
  57.             dates[4] = sdf.parse("2014-03-23");  
  58.             dates[5] = sdf.parse("2014-03-24");  
  59.         } catch (ParseException e) {              
  60.             e.printStackTrace();  
  61.         }  
  62.     }  
  63.       
  64.     //构造函数内舒适化加权信息及directory、reader  
  65.     public IndexUtil() {  
  66.         try {  
  67.             scores.put("yang.org"2.0f);  
  68.             scores.put("sina.org"2.0f);  
  69.             directory = FSDirectory.open(new File("d:/lucene/indextest"));  
  70.             //false设置reder不为只读  
  71.             reader = IndexReader.open(directory,false);  
  72.         } catch (IOException e) {  
  73.             e.printStackTrace();  
  74.         }  
  75.     }  
  76.       
  77.     //得到IndexSearcher  
  78.     public IndexSearcher getSearcher(){  
  79.         //实时更新单例reder  
  80.         try {  
  81.             if(null == reader){       
  82.                 //false设置reder不为只读  
  83.                 reader = IndexReader.open(directory,false);  
  84.             } else {  
  85.                 IndexReader tr = IndexReader.openIfChanged(reader);  
  86.                 if (null != tr)   
  87.                 reader.close();   
  88.                 reader=tr;  
  89.             }  
  90.             return new IndexSearcher(reader);  
  91.         }catch (Exception e) {            
  92.             e.printStackTrace();  
  93.         }   
  94.         return null;  
  95.           
  96.           
  97.           
  98.     }  
  99.   
  100.     // 创建索引步骤:创建Directory;创建IndexWriter;创建Document并add Field;将Document加入IndexWriter  
  101.     public void index() {  
  102.         IndexWriter writer = null;  
  103.         try {  
  104.             writer = new IndexWriter(directory, new IndexWriterConfig(  
  105.                     Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));  
  106.             Document doc = null;  
  107.             for (int i = 0; i < ids.length; i++) {  
  108.                 doc = new Document();  
  109.                 // Field.Store.YES或NO (存储域选项)  
  110.                 // YES表示把这个域即field中的内容完全存储到索引文件中,方便进行文本的还原  
  111.                 // NO表示把这个域中的内容不存储到索引文件中,但是可以被索引,但是内容无法完全还原  
  112.   
  113.                 // Field.Index (索引域选项)  
  114.                 // Index.ANALYZED:进行分词和索引,适用于标题内容等  
  115.                 // Index.NOT_ANALYZED:进行索引,但是不进行分词,如身份证号,姓名,ID等适用于精确搜索  
  116.                 // Index.ANALYZED_NOT_NORMS:即进行分词但不存储norms信息,信息中包括创建索引的时间和权值等信息,影响评分排序的信息  
  117.                 // Index.NOT_ANALYZED_NOT_NORMS:不分词不存储  
  118.                 // Index.NO:不进行索引  
  119.                 doc.add(new Field("id", ids[i], Field.Store.YES,  
  120.                         Field.Index.NOT_ANALYZED_NO_NORMS));  
  121.                 doc.add(new Field("email", emails[i], Field.Store.YES,  
  122.                         Field.Index.ANALYZED));  
  123.                 doc.add(new Field("content", content[i], Field.Store.NO,  
  124.                         Field.Index.ANALYZED));  
  125.                 doc.add(new Field("name", names[i], Field.Store.YES,  
  126.                         Field.Index.NOT_ANALYZED_NO_NORMS));  
  127.                 //为数字加索引  
  128.                 doc.add(new NumericField("attaches", Field.Store.YES,true).setIntValue(attaches[i]));  
  129.                 //为日期字段加索引  
  130.                 doc.add(new NumericField("date", Field.Store.YES,true).setLongValue(dates[i].getTime()));  
  131.                       
  132.                 //加权信息  
  133.                 String et = emails[i].substring(emails[i].lastIndexOf("@")+1);  
  134.                 if(scores.containsKey(et)){  
  135.                     doc.setBoost(scores.get(et));             
  136.                 }else{  
  137.                     doc.setBoost(0.5f);   
  138.                 }  
  139.                           
  140.                 writer.addDocument(doc);  
  141.             }  
  142.   
  143.         } catch (Exception e) {  
  144.             e.printStackTrace();  
  145.         } finally {  
  146.             if (writer != null)  
  147.                 try {  
  148.                     writer.close();  
  149.                 } catch (Exception e) {  
  150.                     e.printStackTrace();  
  151.                 }  
  152.         }  
  153.     }  
  154.     public void seach01(){  
  155.         try {     
  156.             // 创建IndexReader  
  157.             IndexReader reader = IndexReader.open(directory);  
  158.             // 根据IndexWriter创建IndexSearcher  
  159.             IndexSearcher seacher = new IndexSearcher(reader);  
  160.             // 创建搜索的Query  
  161.             TermQuery query = new TermQuery(new Term("content","like"));  
  162.             // 根据seacher搜索并返回TopDocs  
  163.             TopDocs tds = seacher.search(query, 10);              
  164.             // 根据TopDocs获取ScoreDoc  
  165.             ScoreDoc[] sds = tds.scoreDocs;  
  166.             for(ScoreDoc sd: sds){  
  167.                 // 根据seacher和ScoreDoc对象获取具体的Dcument对象  
  168.                 Document d = seacher.doc(sd.doc);  
  169.                 // 根据Dcument对象获取需要的值  
  170.                 System.out.println("id:"+d.get("id"));  
  171.                 System.out.println("name:"+d.get("name"));  
  172.                 System.out.println("email:"+d.get("email"));  
  173.                 System.out.println("attach:"+d.get("attaches"));  
  174.                 System.out.println("date:"+d.get("date"));  
  175.             }     
  176.             reader.close();  
  177.         } catch (Exception e) {  
  178.             e.printStackTrace();  
  179.         }  
  180.     }  
  181.       
  182.     public void seach02(){  
  183.         try {     
  184.           
  185.             // 调用方法getSearcher()取得IndexSearcher  
  186.             IndexSearcher seacher = getSearcher();  
  187.             // 创建搜索的Query  
  188.             TermQuery query = new TermQuery(new Term("content","like"));  
  189.             // 根据seacher搜索并返回TopDocs  
  190.             TopDocs tds = seacher.search(query, 10);              
  191.             // 根据TopDocs获取ScoreDoc  
  192.             ScoreDoc[] sds = tds.scoreDocs;  
  193.             for(ScoreDoc sd: sds){  
  194.                 // 根据seacher和ScoreDoc对象获取具体的Dcument对象  
  195.                 Document d = seacher.doc(sd.doc);  
  196.                 // 根据Dcument对象获取需要的值  
  197.                 System.out.println("id:"+d.get("id"));  
  198.                 System.out.println("name:"+d.get("name"));  
  199.                 System.out.println("email:"+d.get("email"));  
  200.                 System.out.println("attach:"+d.get("attaches"));  
  201.                 System.out.println("date:"+d.get("date"));  
  202.             }     
  203.             seacher.close();  
  204.           
  205.         } catch (Exception e) {  
  206.             e.printStackTrace();  
  207.         }  
  208.     }  
  209.     //查询  
  210.     public void query(){  
  211.         IndexReader reader = null;  
  212.         try {  
  213.             //获得文档数量  
  214.             reader = IndexReader.open(directory);  
  215.             System.out.println("numDocs:"+reader.numDocs());  
  216.             System.out.println("maxDocs:"+reader.maxDoc() );  
  217.         } catch (Exception e) {  
  218.             e.printStackTrace();  
  219.         }finally{  
  220.             if (reader != null)  
  221.                 try {  
  222.                     reader.close();  
  223.                 } catch (IOException e) {  
  224.                     e.printStackTrace();  
  225.                 }  
  226.             }  
  227.     }  
  228.     //删除索引   通过writer删除文档  
  229.     public void delete(){  
  230.         IndexWriter writer = null;  
  231.         try {  
  232.             writer = new IndexWriter(directory, new IndexWriterConfig(  
  233.                     Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));  
  234.             //删除id1的文档 参数还可以是一个query或一个term(精确查找的值)  
  235.             //删除的文档并不会被完全删除,而是存储在一个单独类似回收站文件,可进行恢复  
  236.             writer.deleteDocuments(new Term("id","1"));  
  237.             //清空回收站 不可恢复  
  238.             writer.forceMergeDeletes();  
  239.         }catch(Exception e){  
  240.             e.printStackTrace();  
  241.         }finally {  
  242.             if (writer != null)  
  243.                 try {  
  244.                     writer.close();  
  245.                 } catch (Exception e) {  
  246.                     e.printStackTrace();  
  247.                 }  
  248.         }  
  249.           
  250.     }  
  251.       
  252.     //删除索引   通过reader删除文档  
  253.     public void delete02(){       
  254.         try {  
  255.             reader.deleteDocuments(new Term("id","1"));  
  256.         }catch(Exception e){  
  257.             e.printStackTrace();  
  258.         }finally {  
  259.               
  260.         }  
  261.           
  262.     }  
  263.     //恢复删除的文档  
  264.     public void undelete(){  
  265.         IndexReader reader = null;  
  266.         try {  
  267.             reader = IndexReader.open(directory,false);  
  268.             //恢復時必須把IndexReader的只读属性設置為false  
  269.             reader.undeleteAll();  
  270.               
  271.             System.out.println("numDocs:"+reader.numDocs());  
  272.             System.out.println("maxDocs:"+reader.maxDoc() );  
  273.             System.out.println("deleteDocs:"+reader.numDeletedDocs() );  
  274.         } catch (Exception e) {  
  275.             e.printStackTrace();  
  276.         } finally{  
  277.             if (reader != null)  
  278.             try {  
  279.                 reader.close();  
  280.             } catch (IOException e) {  
  281.                 e.printStackTrace();  
  282.             }  
  283.         }  
  284.           
  285.     }  
  286.       
  287.     //优化合并  
  288.     public void merge(){  
  289.         IndexWriter writer = null;  
  290.         try {  
  291.             writer = new IndexWriter(directory, new IndexWriterConfig(  
  292.                     Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));  
  293.             //将索引合并为两段,这两段中被删除的数据会被清空  
  294.             writer.forceMerge(2);  
  295.         }catch(Exception e){  
  296.             e.printStackTrace();  
  297.         }finally {  
  298.             if (writer != null)  
  299.                 try {  
  300.                     writer.close();  
  301.                 } catch (Exception e) {  
  302.                     e.printStackTrace();  
  303.                 }  
  304.         }  
  305.     }  
  306.     //更新操作  
  307.     public void update(){  
  308.         IndexWriter writer = null;  
  309.         try {  
  310.             writer = new IndexWriter(directory, new IndexWriterConfig(  
  311.                     Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));  
  312.             //lucene并不提供更新,更新为先删除后添加  
  313.             Document doc = new Document();  
  314.             doc.add(new Field("id""11", Field.Store.YES,  
  315.                     Field.Index.NOT_ANALYZED_NO_NORMS));  
  316.             doc.add(new Field("email", emails[0], Field.Store.YES,  
  317.                     Field.Index.ANALYZED));  
  318.             doc.add(new Field("content", content[0], Field.Store.NO,  
  319.                     Field.Index.ANALYZED));  
  320.             doc.add(new Field("name", names[0], Field.Store.YES,  
  321.                     Field.Index.NOT_ANALYZED_NO_NORMS));  
  322.             writer.updateDocument(new Term("id","1"), doc);  
  323.         }catch(Exception e){  
  324.             e.printStackTrace();  
  325.         }finally {  
  326.             if (writer != null)  
  327.                 try {  
  328.                     writer.close();  
  329.                 } catch (Exception e) {  
  330.                     e.printStackTrace();  
  331.                 }  
  332.         }  
  333.     }  
  334.   
  335. }  
  336.   
  337. package cn.yang;  
  338.   
  339. import org.junit.Test;  
  340.   
  341. public class TestIndex {  
  342.       
  343.     @Test  
  344.     public void testIndex(){  
  345.         IndexUtil iu = new IndexUtil();  
  346.         iu.index();  
  347.           
  348.     }  
  349.     @Test  
  350.     public void testQuery(){  
  351.         IndexUtil iu = new IndexUtil();  
  352.         iu.query();  
  353.           
  354.     }  
  355.     @Test  
  356.     public void testDelete(){  
  357.         IndexUtil iu = new IndexUtil();  
  358.         iu.delete();  
  359.     }  
  360.     @Test  
  361.     public void testunDelete(){  
  362.         IndexUtil iu = new IndexUtil();  
  363.         iu.undelete();  
  364.     }  
  365.       
  366.     @Test  
  367.     public void testSerch01(){  
  368.         IndexUtil iu = new IndexUtil();  
  369.         iu.seach01();  
  370.     }  
  371.       
  372.     @Test  
  373.     public void testSerch02(){  
  374.         IndexUtil iu = new IndexUtil();  
  375.         //iu.seach02();  
  376.         for(int i=0;i<5;i++){  
  377.             iu.seach02();  
  378.             System.out.println("----------");  
  379.             iu.seach02();  
  380.             try {  
  381.                 Thread.sleep(10000);  
  382.             } catch (InterruptedException e) {  
  383.                 e.printStackTrace();  
  384.             }  
  385.         }  
  386.     }  
  387.   
  388. }  


4.域选项介绍: 
Field.Index 表示Field的索引方式 
NO 表示该Field不需要索引,也就是用户不需要去查找该Field的值 
NO_NORMS 表示对该Field进行索引,但是不使用Analyzer,同时禁止它参加评分,主要是为了减少内存的消耗 
TOKENIZED 表示该Field先被分词再索引 
UN_TOKENIZED 像链接地址URL、文件系统路径信息、时间日期、人名、居民身份证、电话号码等等通常将被索引并且完整的存储在索引中,但一般不需要切分词 

Field.Store 表示Field的存储方式 
COMPRESS压缩存储 
NO 原文不存储在索引文件中,搜索结果命中后,再根据其他附加属性如文件的Path,数据库的主键等,重新连接打开原文,适合原文内容较大的情况。 
YES索引文件本来只存储索引数据, 此设计将原文内容直接也存储在索引文件中,如文档的标题。 
5.IndexReader和IndexWriter的生命周期问题 
IndexReader耗资源,做成单例 
IndexReader在工作时IndexWriter重建或者更新了索引,假如IndexReader为单例模式,不  
能实时查询到IndexWriter的更新 
解决方法:IndexReader.openIfChanged(reader); 
IndexWriter在项目中有可能只存在一个,故操作后要进行commit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值