Lucene教程
Posted 朱小杰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene教程相关的知识,希望对你有一定的参考价值。
一:简单的示例 1.1:生成索引
1.1.1:Field.Store和Field.Index
1.1.2:为数字生成索引
1.1.3:为索引加权
1.1.4:为日期生成索引
1.2:查询
1.2.1:介绍IndexReader
1.3:删除
1.3.1:还原删除的文档
1.3.2:清空回收站时面的数据
1.4:更新
前言:本教程用于Lucene3.5,Maven地址为
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>3.5.0</version> </dependency>
一:简单的示例
我就不介绍Lucene了,想来看这篇博客的人,都知道Lucene是什么。直接给出生成索引,和查询的示例
1.1:生成索引
生成索引的代码如下:
/** * 创建索引 */ public void index(){ IndexWriter writer = null; try { //1、创建Derictory // Directory directory = new RAMDirectory();//这个方法是建立在内存中的索引 Directory directory = FSDirectory.open(new File("G:\\TestLucene\\index"));//这个方法是建立在磁盘上面的索引 // 2、创建IndexWriter,用完后要关闭 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)); writer = new IndexWriter(directory,config); //3、创建Document对象 Document document = null; File fl = new File("G:\\TestLucene\\file"); //4、为Document添加Field for(File file : fl.listFiles()){ document = new Document();
document.add(new Field("content",new FileReader(file))); //把文件名存放到硬盘中,不作分词 document.add(new Field("fileName",file.getName(),Field.Store.YES, Field.Index.ANALYZED.NOT_ANALYZED)); //把绝对路径放到硬盘中,不作分词 document.add(new Field("path", file.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED)); } //5、通过IndexWriter添加文档到索引中 writer.addDocument(document); } catch (IOException e) { e.printStackTrace(); } finally { if(null != writer){ try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.1.1:Field.Store和Field.Index
这里说明一个Field.Index和Field.Store
//Field.Store.YES或者NO部分 // 如果为YES,代表着是否要把这个域中的内容完全存储到文件中,方便进行还原 //如果为NO,代表着不把这个域的内容存储到文件,但是可以被索引,但是这些内容不可被还原 //Field.Index.ANALYZED:进行分词和索引,适用于标题,内容等 //Field.Index.NOT_ANALYZED:进行索引,但是不进行分词。精准的数据不分词,像id,身份证号,姓名等不分词,用于精确搜索 //Field.Index.ANALYZED_NOT_NORMS:进行分词但是不存储norm信息,这个norms中包括了索引的时间和权值等信息 //Field.Index.NOT_ANALYZED_NOT_NORMS:既不进行分词,也不存储norms信息 //Field.Index.NO:完全不进行索引
1.1.2:为数字生成索引
看过Field构造方法的人可能知道,这里面并没有对数字索引添加方法,那么会有人说,把数字转换成字符串?额。数字在索引中处理方式与字符串不同,我们可以使用一个新的对象
//搜索content中包含有着like的 TermQuery termQuery = new TermQuery(new Term("content","like")); //给数字加索引要用另一个对象 document.add(new NumericField("attachs").setIntValue(attachs[i]));
//给数字加索引要用另一个对象 //查看源码会发现,这个构造函数默认是不存储,但是会进行索引 document.add(new NumericField("attachs").setIntValue(attachs[i])); //通过这个构造方法,可以把其修改为存储,最后的boolean参数代表着是否索引 document.add(new NumericField("attachs", Field.Store.YES,true).setIntValue(attachs[i]));
这里使用一个新的字段,NumericField
1.1.3:为索引加权
大家看到搜索引擎的排序,就肯定能猜到,搜索引擎是按照了一定的要求,对查询的结果进行了排序,这里介绍一个简单的加权排序方法,后面会深入研究
//加权 document.setBoost(2.1f);
注意:权重越大,排序越前
1.1.4:为日期生成索引
既然数字有专门的NumericField,那么给日期生成索引,是不是也有DateField呢?其实是没有的,那怎么办?
但是我们都忽略了一件事,日期其实也是一个long类型的数字
document.add(new NumericField("attachs", Field.Store.YES,true).setLongValue(new Date().getTime()));
这不就行了吗?
1.2:查询
这里演示根据已生成的索引,来查询
代码如下:
/** * 搜索 */ public void searcher(){ try { //1、创建Directory Directory directory = FSDirectory.open(new File("G:\\TestLucene\\index")); //2、创建IndexReader,需要关闭 IndexReader reader = IndexReader.open(directory); //3、根据IndexReader创建IndexSearcher IndexSearcher searcher = new IndexSearcher(reader); //4、创建索引的Query //第二个参数代表着要搜索的域 QueryParser parser = new QueryParser(Version.LUCENE_35,"content",new StandardAnalyzer(Version.LUCENE_35)); //表示搜索content中包含java的文档 Query query = parser.parse("朱小杰");
//5、根据searcher搜索并返回TopDocs // 表示返回前面10条 TopDocs topDocs = searcher.search(query,10); //6、根据TopDocs获取ScoreDoc对象 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for(ScoreDoc sd : scoreDocs){ //7、根据Searcher和ScordDoc对象获取具体的Document对象 //获取这个文档的id int doc = sd.doc; Document document = searcher.doc(doc); //8、根据Document对象获取需要的值 System.out.println("【找到】" + document.get("fileName") + " " + document.get("path") + " .." + document.get("content")); } reader.close(); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } }
1.2.1:介绍IndexReader
IndexReader顾名思义,它是用来读取索引的信息的,下面来演示一些它的用法
(1)获取文档的数量
//存储的文档数量,也就是document对象的数量,删除索引后,这个数值会减少
System.out.println("存储的文档数量: " + reader.numDocs());
(2)获取文档的总量
//存储过的文档的最大数量,删除索引后,数量不会减少
//此时删除的文件并不会完全删除,它存在回收站里面
System.out.println("文档存储的总存储量: " + reader.maxDoc());
(3)获取已删除文档的数量
System.out.println("删除文档的数量: " + reader.numDeletedDocs());
1.3:删除
下面给出删除的代码
/** * 删除索引 */ public void delete(){ try { IndexWriter writer = null; writer = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35))); //删除全部的索引 //writer.deleteAll(); //参数可以为一个查询的Query,也可以为一个Term,它是一个精确的值,代表着把id为1的给删除掉 writer.deleteDocuments(new Term("id","1")); writer.close(); } catch (IOException e) { e.printStackTrace(); } }
注意,这里的删除,并不是真的删除。执行完之后,可以在索引的目录里面看到多了一个.del的文件,那是一个类似回收站的文件,在回收站中的文件是可以进行还原的
1.3.1:还原删除的文档
之前有说到,删除并没有作真正的删除,而是把这个文件放到了类似回收站的位置中,下面来使用代码来进行还原已删除的文件
/** * 删除索引并不是完全删除,它是有着一个回收站的功能 * 上面的delete删除了一个索引,这里进行恢复 */ public void recovery(){ try { //这一步很重要,因为默认打开的reader是只读的,所以这里要通过构造方法,把它的readonly设置为false,否则会抛出异常 IndexReader reader = IndexReader.open(directory,false); //还原所有已删除的数据 reader.undeleteAll(); reader.close(); } catch (IOException e) { e.printStackTrace(); } }
注意:上面的构造方法和以往不同,后面多了一个boolean值,这个值,如果不写,默认是true,代表着只读,那么如果在这种情况下进行还原,是会抛出异常的。这里将其设置为false,也就是把只读设置为了false,这样就可以还原了。
1.3.2:清空回收站里面的数据
上面说完从回收站里面还原数据,那么回收站怎么清空掉呢?下面给出代码:
/** * 清空回收站里面的数据 */ public void clearRecovery(){ try { IndexWriter writer = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35))); writer.forceMergeDeletes(); //代表着是否等待当前操作完成后,再清空回收站里面的数据 writer.forceMergeDeletes(true); writer.close(); } catch (IOException e) { e.printStackTrace(); } }
这里面是有着两个重载的方法,其中一个是立即删除,一个是等待当前操作完成后,再删除
1.4:更新
更新一个索引的代码如下:
/** * 更新数据 */ public void update(){ try { //注意,Lucene其实并没有更新的操作,它的实际原理是先删除,再添加 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)); IndexWriter writer = new IndexWriter(directory,config); Document document = new Document(); document.add(new Field("id","1", Field.Store.YES, Field.Index.NOT_ANALYZED)); writer.updateDocument(new Term("id","1"),document); writer.close(); } catch (IOException e) { e.printStackTrace(); } }
值得注意的是,这里的更新,并不是在原有的记录里面更新,而是先把该记录删除,然后增加新的记录,所以在查看已删除的文档数量里面会发出多出一条记录,同样的,在文档总量里面,也会增加一条记录
以上是关于Lucene教程的主要内容,如果未能解决你的问题,请参考以下文章