Lucene 3.6.2入门:针对索引文件的CRUD
来源:互联网 发布:岂可得乎 编辑:程序博客网 时间:2024/05/16 06:43
* @see =============================================================================================================
* @see Lucene官网:http://lucene.apache.org
* @see Lucene下载:http://archive.apache.org/dist/lucene/java/
* @see Lucene文档:http://wiki.apache.org/lucene-java/
* @see =============================================================================================================
* @see 使用Luke查看分词信息(http://code.google.com/p/luke/)
* @see 1)引言:每一个Lucene版本都会有一个相应的Luke文件
* @see 2)打开:双击或java -jar lukeall-3.5.0.jar
* @see 3)选择索引的存放目录后点击OK即可
* @see 7)如果我们的索引有改变,可以点击右侧的Re-open按钮重新载入索引
* @see 4)Luke界面右下角的Top ranking terms窗口中显示的就是分词信息。其中Rank列表示出现频率
* @see 5)Luke菜单下的Documents选项卡中显示的就是文档信息,我们可以根据文档序号来浏览(点击向左和向右的方向箭头)
* @see 6)Luke菜单下的Search选项卡中可以根据我们输入的表达式来查文档内容
* @see 比如在Enter search expression here:输入content:my,再在右侧点击一个黑色粗体字的Search大按钮即可
* @see =============================================================================================================
* @create Jun 30, 2012 4:34:09 PM
*
*/
public class HelloIndex { /* * 定义一组数据,用来演示搜索(这里有一封邮件为例) * 假设每一个变量代表一个Document,这里就定义了6个Document */ //邮件编号 private String[] ids = {"1", "2", "3", "4", "5", "6"}; //邮件主题 private String[] names = {"Michael", "Scofield", "Tbag", "Jack", "Jade", "Jadyer"}; //邮件地址 private String[] emails = {"aa@jadyer.us", "bb@jadyer.cn", "cc@jadyer.cc", "dd@jadyer.tw", "ee@jadyer.hk", "ff@jadyer.me"}; //邮件内容 private String[] contents = {"my blog", "my website", "my name", "I am JavaDeveloper", "I am from Haerbin", "I like Lucene"}; //邮件附件(为数字和日期加索引,与,字符串加索引的方式不同) private int[] attachs = {9,3,5,4,1,2}; //邮件日期 private Date[] dates = new Date[ids.length]; //它的创建是比较耗时耗资源的,所以这里只让它创建一次,此时reader处于整个生命周期中,实际应用中也可能直接放到ApplicationContext里面 private static IndexReader reader = null; private Directory directory = null; public HelloIndex(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); try { dates[0] = sdf.parse("20120601"); dates[1] = sdf.parse("20120603"); dates[2] = sdf.parse("20120605"); dates[3] = sdf.parse("20120607"); dates[4] = sdf.parse("20120609"); dates[5] = sdf.parse("20120611"); directory = FSDirectory.open(new File("myExample/02_index/")); } catch (Exception e) { e.printStackTrace(); } } /** * 获取IndexReader实例 */ private IndexReader getIndexReader(){ try { if(reader == null){ reader = IndexReader.open(directory); }else{ //if the index was changed since the provided reader was opened, open and return a new reader; else,return null //如果当前reader在打开期间index发生改变,则打开并返回一个新的IndexReader,否则返回null IndexReader ir = IndexReader.openIfChanged(reader); if(ir != null){ reader.close(); //关闭原reader reader = ir; //赋予新reader } } return reader; }catch(Exception e) { e.printStackTrace(); } return null; //发生异常则返回null } /** * 通过IndexReader获取文档数量 */ public void getDocsCount(){ System.out.println("maxDocs:" + this.getIndexReader()。maxDoc()); System.out.println("numDocs:" + this.getIndexReader()。numDocs()); System.out.println("deletedDocs:" + this.getIndexReader()。numDeletedDocs()); } /** * 创建索引 */ public void createIndex(){ IndexWriter writer = null; Document doc = null; try{ writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36))); writer.deleteAll(); //创建索引之前,先把文档清空掉 for(int i=0; i doc = new Document(); doc.add(new Field("id", ids[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("name", names[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("email", emails[i], Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field("content", contents[i], Field.Store.NO, Field.Index.ANALYZED)); doc.add(new NumericField("attach", Field.Store.YES, true)。setIntValue(attachs[i])); //为数字加索引(第三个参数指定是否索引) doc.add(new NumericField("date", Field.Store.YES, true)。setLongValue(dates[i].getTime())); //为日期加索引 /* * 建立索引时加权 * 定义排名规则,即加权,这里是为指定邮件名结尾的emails加权 */ if(emails[i].endsWith("jadyer.cn")){ doc.setBoost(2.0f); }else if(emails[i].endsWith("jadyer.me")){ doc.setBoost(1.5f); //为文档加权…默认为1.0,权值越高则排名越高,显示得就越靠前 }else{ doc.setBoost(0.5f); //注意它的参数类型是Float } writer.addDocument(doc); } }catch(Exception e) { e.printStackTrace(); }finally{ if(null != writer){ try { writer.close(); } catch (IOException ce) { ce.printStackTrace(); } } } } /** * 搜索文件 */ public void searchFile(){ IndexSearcher searcher = new IndexSearcher(this.getIndexReader()); Query query = new TermQuery(new Term("content", "my")); //精确搜索:搜索"content"中包含"my"的文档 try{ TopDocs tds = searcher.search(query, 10); for(ScoreDoc sd : tds.scoreDocs){ Document doc = searcher.doc(sd.doc); //sd.doc得到的是文档的序号 //doc.getBoost()得到的权值与创建索引时设置的权值之间是不相搭的,创建索引时的权值的查看需要使用Luke工具 // 之所以这样,是因为这里的Document对象(是获取到的)与创建索引时的Document对象,不是同一个对象 //sd.score得到的是该文档的评分,该评分规则的公式是比较复杂的,它主要与文档的权值和出现次数成正比 System.out.print("(" + sd.doc + "|" + doc.getBoost() + "|" + sd.score + ")" + doc.get("name") + "[" + doc.get("email") + "]-->"); System.out.println(doc.get("id") + "," + doc.get("attach") + "," + new SimpleDateFormat("yyyyMMdd")。format(new Date(Long.parseLong(doc.get("date"))))); } }catch(Exception e){ e.printStackTrace(); }finally{ if(null != searcher){ try { searcher.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 更新索引 * @see Lucene其实并未提供更新索引的方法,这里的更新操作内部是先删除再添加的方式 * @see 因为Lucene认为更新索引的代价,与删除后重建索引的代价,二者是差不多的 */ public void updateIndex(){ IndexWriter writer = null; Document doc = new Document(); try{ writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36))); doc.add(new Field("id", "1111", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("name", names[0], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("email", emails[0], Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field("content", contents[0], Field.Store.NO, Field.Index.ANALYZED)); doc.add(new NumericField("attach", Field.Store.YES, true)。setIntValue(attachs[0])); doc.add(new NumericField("date", Field.Store.YES, true)。setLongValue(dates[0].getTime())); //其实它会先删除索引文档中id为1的文档,然后再将这里的doc对象重新索引,所以即便这里的1!=1111,但它并不会报错 //所以在执行完该方法后:maxDocs=7,numDocs=6,deletedDocs=1,就是因为Lucene会先删除再添加 writer.updateDocument(new Term("id","1"), doc); }catch(Exception e) { e.printStackTrace(); }finally{ if(null != writer){ try { writer.close(); } catch (IOException ce) { ce.printStackTrace(); } } } } /** * 删除索引 * @see ----------------------------------------------------------------------------------------------------- * @see 在执行完该方法后,再执行本类的searchFile()方法,得知numDocs=5,maxDocs=6,deletedDocs=1 * @see 这说明此时删除的文档并没有被完全删除,而是存储在一个回收站中,它是可以恢复的 * @see ----------------------------------------------------------------------------------------------------- * @see 从回收站中清空索引IndexWriter * @see 对于清空索引,Lucene3.5之前叫做优化,调用的是IndexWriter.optimize()方法,但该方法已被禁用 * @see 因为optimize时它会全部更新索引,这一过程所涉及到的负载是很大的,于是弃用了该方法,使用forceMerge代替 * @see 使用IndexWriter.forceMergeDeletes()方法可以强制清空回收站中的内容 * @see 另外IndexWriter.forceMerge(3)方法会将索引合并为3段,这3段中的被删除的数据也会被清空 * @see 但其在Lucene3.5之后不建议使用,因为其会消耗大量的开销,而Lucene会根据情况自动处理的 * @see ----------------------------------------------------------------------------------------------------- */ public void deleteIndex(){ IndexWriter writer = null; try{ writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36))); //其参数可以传Query或Term…Query指的是可以查询出一系列的结果并将其全部删掉,而Term属于精确查找 writer.deleteDocuments(new Term("id", "1")); //删除索引文档中id为1的文档 }catch(Exception e) { e.printStackTrace(); }finally{ if(null != writer){ try { writer.close(); } catch (IOException ce) { ce.printStackTrace(); } } } } /** * 恢复索引 * @see 建议弃用 */ @Deprecated public void unDeleteIndex(){ IndexReader reader = null; try { //IndexReader.open(directory)此时该IndexReader默认的readOnly=true,而在恢复索引时应该指定其为非只读的 reader = IndexReader.open(directory, false); //Deprecated. Write support will be removed in Lucene 4.0. There will be no replacement for this method. reader.undeleteAll(); } catch (Exception e) { e.printStackTrace(); }finally{ if(null != reader){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }下面是用JUnit4.x写的一个小测试
双击代码全选
package com.jadyer.test; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.jadyer.lucene.HelloIndex; public class HelloIndexTest { private HelloIndex hello; @Before public void init(){ hello = new HelloIndex(); } @After public void destroy(){ hello.getDocsCount(); } @Test public void createIndex(){ hello.createIndex(); } @Test public void searchFile(){ hello.searchFile(); } @Test public void updateIndex(){ hello.updateIndex(); } @Test public void deleteIndex(){ hello.deleteIndex(); } @Test @SuppressWarnings("deprecation") public void unDeleteIndex(){ hello.unDeleteIndex(); } }
0 0
- Lucene 3.6.2入门:针对索引文件的CRUD
- 【Lucene3.6.2入门系列】第02节_针对索引文件的CRUD
- 【Lucene3.6.2入门系列】第02节_针对索引文件的CRUD
- Lucene-索引库的CRUD
- lucene的索引文件
- lucene的索引文件
- lucene索引文件的格式(2)
- Lucene学习笔记之(二)索引文档的CRUD
- Lucene&Solr(之二)-索引库CRUD、Solr的安装
- lucene的索引文件结构
- 深入Lucene的索引文件
- lucene学习之针对多索引的搜索
- 第60天(就业班) Lucene入门、创建索引库、CRUD
- Lucene入门之索引的管理
- lucene索引文件大于2G的处理情况
- lucene入门-索引网页
- lucene入门-索引网页
- lucene入门-建立索引
- 【热点】Google的Go语言速度提升
- CoreGraphics 学习摘记 之 Color and Color Spaces
- 银汇通支付:移动支付行业系列报告
- 常见前端开发面试题
- android layoutParams错误原因小结
- Lucene 3.6.2入门:针对索引文件的CRUD
- ASP.NET MVC3中的路由系统(Routes)
- this和static的用法
- vi 编码设置
- HDOJ 2243 考研路茫茫——单词情结 AC自动机+矩阵快速求幂和
- mysql load数据语法
- usefull scripts
- mysql保存当前时间精确到秒
- Lucene 3.6.2入门简述Lucene中常见的搜索功能