一、是否进行实时搜索
- 实时搜索:只要数据库一变动,马上要更新索引,要使用
writer.commit
来操作,但是这种情况太消耗资源。 - 近实时搜索:当用户修改了信息之后,先把索引保存到内存中,然后在一个统一的时间内对内存中的索引进行提交操作。基于这个原因我们一般进行的是近实时搜索。
二、入门程序(工程lucene-nearRealTime
)
IndexUtil.java
package cn.itcast.util;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.StaleReaderException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.SearcherWarmer;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class IndexUtil {
private String[] ids = {"1", "2", "3", "4", "5", "6"};
//下面是邮件
private String[] emails = {"aa@qq.com", "bb@sina.edu", "cc@yahu.org", "ss@sina.com", "dd@gmail.com", "ee@163.com"};
//下面是邮件内容
private String[] content = {
"welcom to visited the space,I like football",
"hello boy, i like someone",
"come on baby",
"first blood",
"I like football,I like football",
"my girlfriend is so beatiful, every body like game"
};
private int[] attaches = {2,5,6,5,8,4};//附件数量
//发件人名字
private String[] names = {"Tom", "Jack", "goudan", "alibaba", "jerry", "kitty"};
//邮件的日期
private Date[] dates = null;
private Directory directory = null;
private Map<String, Float> scores = new HashMap<String, Float>();//新建一个Map,用来存储权值
/*private static IndexReader reader = null;//声明一个IndexReader的属性*/
private SearcherManager mgr = null;
public IndexUtil() {
try {
setDates();//设置日期
scores.put("qq.com", 2.0f);//如果是"qq.com"结尾的索引则让其权值为2.0,注意:默认是1.0
scores.put("sina.edu", 1.5f);
directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));
mgr = new SearcherManager(directory, new SearcherWarmer() {
//在重新打开的时候可能需要做一个控制,这些控制可以在这个方法中做
@Override
public void warm(IndexSearcher searcher) throws IOException {
System.out.println("has changed");
}
}, Executors.newCachedThreadPool());
} catch (IOException e) {
e.printStackTrace();
}
}
//创建索引
public void index(){
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
//此方法可将索引全部清空
writer.deleteAll();
Document document = null;
for(int i = 0; i < ids.length; i++){
document = new Document();
//id需要存储,不需要加权、分词,email也需要存储,但不需要分词,有时候也需要加权
//对于内容,我们不需要存储和加权,但需要分词。而名字需要存储,不需要分词和加权
//这里我们先不对整型数据进行索引,后面再说
document.add(new Field("id", ids[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("email", emails[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("content", content[i], Field.Store.NO, Field.Index.ANALYZED));
document.add(new Field("name", names[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
//为数字添加索引,第三个参数设置为true表示默认索引
document.add(new NumericField("attach", Field.Store.YES, true).setIntValue(attaches[i]));
//为日期添加索引
document.add(new NumericField("date", Field.Store.YES, true).setLongValue(dates[i].getTime()));
String et = emails[i].substring(emails[i].lastIndexOf("@") + 1);
System.out.println(et);
//加入权值
if(scores.containsKey(et)){
document.setBoost(scores.get(et));
}else{
document.setBoost(0.5f);
}
writer.addDocument(document);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//查询
public void query(){
try {
IndexReader reader = IndexReader.open(directory);
//maxDoc 和 numDocs()方法的区别:maxDoc()返回索引中删除和未被删除的文档总数,
//后者返回索引中未被删除的文档总数,通过reader可以有效获取文档的数量
System.out.println("numDocs: " + reader.numDocs());
System.out.println("maxDocs: " + reader.maxDoc());
//查看被删除的索引
System.out.println("deleteDocs : " + reader.numDeletedDocs());
//记得用完之后关闭
reader.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//删除索引
public void delete(){
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
//参数可以是一个选项,可以是一个query,也可以是一个term,term是一个精确查找的值
//这里我们测试此方法之后再次执行搜索方法,发现文档数numDocs还有5个,比之前少了一个,但是maxDoc还是6个
//在我们的索引目录中发现出现了一个delete的文件。这里的删除就像一个回收站一样,是可以恢复的
writer.deleteDocuments(new Term("id", "1"));//这里表示删除索引为1的id
writer.commit();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//更新索引
public void update(){
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
/* lucene并没有提供更新,这里的更新操作其实是如下两个操作的合集
* 先删除之后再添加,所以不是在之前的位置更新
* 测试之后我们会发现回收站中有一个索引
* */
Document document = new Document();
document.add(new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("email", emails[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("content", content[0], Field.Store.NO, Field.Index.ANALYZED));
document.add(new Field("name", names[0], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
writer.updateDocument(new Term("id", "1"), document);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void search01(){
IndexReader reader;
try {
reader = IndexReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
TermQuery query = new TermQuery(new Term("content", "like"));//搜索内容中含有like的
TopDocs tds = searcher.search(query, 10);
for(ScoreDoc sd : tds.scoreDocs){
Document doc = searcher.doc(sd.doc);
//这里我们获取权值getBoost()的时候发现都是1.0,这是因为这里是获取的一个document,和原来的没有关系。
//要想看其权值信息,可以使用luke工具
//而这里的日期需要我们转换成日期格式
System.out.println("(" + sd.doc + "权值:"+ doc.getBoost() + ")" + doc.get("name") + "[" + doc.get("email") + "]-->"
+ doc.get("id") + "-->" + doc.get("attach") + "-->" + doc.get("date"));
reader.close();
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//设置日期
private void setDates(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
dates = new Date[ids.length];
dates[0] = sdf.parse("2015-02-15");
dates[1] = sdf.parse("2015-03-01");
dates[2] = sdf.parse("2015-05-18");
dates[3] = sdf.parse("2015-09-05");
dates[4] = sdf.parse("2015-12-15");
dates[5] = sdf.parse("2015-08-29");
} catch (ParseException e) {
e.printStackTrace();
}
}
public void search02(){
IndexSearcher searcher = null;
try {
mgr.maybeReopen();//判断是否需要重新打开一个IndexSearcher
searcher = mgr.acquire();
TermQuery query = new TermQuery(new Term("content", "like"));//搜索内容中含有like的
TopDocs tds = searcher.search(query, 10);
for(ScoreDoc sd : tds.scoreDocs){
Document doc = searcher.doc(sd.doc);
System.out.println("(" + sd.doc + "权值:"+ doc.getBoost() + ")" + doc.get("name") + "[" + doc.get("email") + "]-->"
+ doc.get("id") + "-->" + doc.get("attach") + "-->" + doc.get("date"));
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
mgr.release(searcher);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
说明:这是我们之前写过的一个工具类,和之前不同的是我们这里不再直接获取IndexReader
,而是定义一个SearcherManager
对象:
private SearcherManager mgr = null;
然后对IndexUtil
方法进行改造,我们通过SearcherManager
来管理IndexReader
,同时在我们更新索引的过程中我们还可以对资源做一些操作。再对方法search02
方法进行改造,这里我们是通过SearcherManager
来获得IndexReader
对象的,同时是否打开一个新的IndexReader
让SearcherManager
的方法maybeReopen
来决定。而使用完之后我们也不需要关闭IndexReader
,只需要将其释放即可,使用方法release
。
下面进行测试:
package cn.lucene.test;
import org.junit.Test;
import cn.itcast.util.IndexUtil;
public class TestIndex {
@Test
public void testIndex(){
IndexUtil util = new IndexUtil();
util.index();
}
@Test
public void testQuery(){
IndexUtil util = new IndexUtil();
util.query();
}
@Test
public void testDelete(){
IndexUtil util = new IndexUtil();
util.delete();
}
@Test
public void testUpdate(){
IndexUtil util = new IndexUtil();
util.update();
}
@Test
public void testSearch01(){
IndexUtil util = new IndexUtil();
util.search01();
}
@Test
public void testSearch02(){
IndexUtil util = new IndexUtil();
for(int i = 0; i < 5; i++){
util.search02();//这里我们让其执行5次
System.out.println("************************");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
说明:在测试方法testSearch02
之前我们先使用方法testIndex
重建索引,然后我们使用方法testQuery
可以看到记录数:
而在
testSearch02
方法还没有运行完时我们使用testDelete
方法进行删除,此时我们发现testSearch02
方法在后面的输出少了一条记录。将记录0给删除了。虽然如此,当我们再次使用testQuery
方法查询的时候发现记录没有被删掉,这是因为并没有提交,而使用SearcherManager
需要进行writer.commit
才会检测到,于是这就需要用到NRTManager
这个类了。
注意:我们在reopen
时可能需要对某些资源做一些操作,可以在方法SearcherWarmer. Warm
中进行,我们在testSearch02
方法的输出中也可以看到打印出了has changed
。
三、近实时搜索(工程lucene-nearRealTime01
)
只是使用SearcherManager
是不能实现实时搜索的,因为只是更新的内存,而并没有真正的提交。
在类IndexUtil.java
中我们添加两个属性:
private NRTManager nrtMgr = null;
private IndexWriter writer;
对相关方法进行改造:
package cn.itcast.util;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.StaleReaderException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NRTManager;
import org.apache.lucene.search.NRTManagerReopenThread;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.SearcherWarmer;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class IndexUtil {
private String[] ids = {"1", "2", "3", "4", "5", "6"};
//下面是邮件
private String[] emails = {"aa@qq.com", "bb@sina.edu", "cc@yahu.org", "ss@sina.com", "dd@gmail.com", "ee@163.com"};
//下面是邮件内容
private String[] content = {
"welcom to visited the space,I like football",
"hello boy, i like someone",
"come on baby like",
"first blood like",
"I like football,I like football",
"my girlfriend is so beatiful, every body like game"
};
private int[] attaches = {2,5,6,5,8,4};//附件数量
//发件人名字
private String[] names = {"Tom", "Jack", "goudan", "alibaba", "jerry", "kitty"};
//邮件的日期
private Date[] dates = null;
private Directory directory = null;
private Map<String, Float> scores = new HashMap<String, Float>();//新建一个Map,用来存储权值
/*private static IndexReader reader = null;//声明一个IndexReader的属性*/
private SearcherManager mgr = null;
private NRTManager nrtMgr = null;
private IndexWriter writer;
public IndexUtil() {
try {
setDates();//设置日期
scores.put("qq.com", 2.0f);//如果是"qq.com"结尾的索引则让其权值为2.0,注意:默认是1.0
scores.put("sina.edu", 1.5f);
directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
nrtMgr = new NRTManager(writer, new SearcherWarmer() {
@Override
public void warm(IndexSearcher arg0) throws IOException {
System.out.println("reopen");
}
});
//重新打开的时候间隔最大为5.0,最小为0.025,0.025为25秒
NRTManagerReopenThread reopen = new NRTManagerReopenThread(nrtMgr, 5.0, 0.025);
reopen.setDaemon(true);
reopen.setName("NrtManger Reopen Thread");
reopen.start();//启动线程NRTManager的reopen线程
mgr = nrtMgr.getSearcherManager(true);//允许所有更新
} catch (IOException e) {
e.printStackTrace();
}
}
//创建索引
public void index(){
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
//此方法可将索引全部清空
writer.deleteAll();
Document document = null;
for(int i = 0; i < ids.length; i++){
document = new Document();
//id需要存储,不需要加权、分词,email也需要存储,但不需要分词,有时候也需要加权
//对于内容,我们不需要存储和加权,但需要分词。而名字需要存储,不需要分词和加权
//这里我们先不对整型数据进行索引,后面再说
document.add(new Field("id", ids[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("email", emails[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("content", content[i], Field.Store.NO, Field.Index.ANALYZED));
document.add(new Field("name", names[i], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
//为数字添加索引,第三个参数设置为true表示默认索引
document.add(new NumericField("attach", Field.Store.YES, true).setIntValue(attaches[i]));
//为日期添加索引
document.add(new NumericField("date", Field.Store.YES, true).setLongValue(dates[i].getTime()));
String et = emails[i].substring(emails[i].lastIndexOf("@") + 1);
System.out.println(et);
//加入权值
if(scores.containsKey(et)){
document.setBoost(scores.get(et));
}else{
document.setBoost(0.5f);
}
writer.addDocument(document);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//查询
public void query(){
try {
IndexReader reader = IndexReader.open(directory);
//maxDoc 和 numDocs()方法的区别:maxDoc()返回索引中删除和未被删除的文档总数,
//后者返回索引中未被删除的文档总数,通过reader可以有效获取文档的数量
System.out.println("numDocs: " + reader.numDocs());
System.out.println("maxDocs: " + reader.maxDoc());
//查看被删除的索引
System.out.println("deleteDocs : " + reader.numDeletedDocs());
//记得用完之后关闭
reader.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//删除索引
public void delete(){
IndexWriter writer = null;
try {
nrtMgr.deleteDocuments(new Term("id", "1"));//这里表示删除索引为1的id
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//更新索引
public void update(){
try {
/* lucene并没有提供更新,这里的更新操作其实是如下两个操作的合集
* 先删除之后再添加,所以不是在之前的位置更新
* 测试之后我们会发现回收站中有一个索引
* */
Document document = new Document();
document.add(new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("email", emails[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("content", content[0], Field.Store.NO, Field.Index.ANALYZED));
document.add(new Field("name", names[0], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
nrtMgr.updateDocument(new Term("id", "1"), document);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void search01(){
IndexReader reader;
try {
reader = IndexReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
TermQuery query = new TermQuery(new Term("content", "like"));//搜索内容中含有like的
TopDocs tds = searcher.search(query, 10);
for(ScoreDoc sd : tds.scoreDocs){
Document doc = searcher.doc(sd.doc);
//这里我们获取权值getBoost()的时候发现都是1.0,这是因为这里是获取的一个document,和原来的没有关系。
//要想看其权值信息,可以使用luke工具
//而这里的日期需要我们转换成日期格式
System.out.println("(" + sd.doc + "权值:"+ doc.getBoost() + ")" + doc.get("name") + "[" + doc.get("email") + "]-->"
+ doc.get("id") + "-->" + doc.get("attach") + "-->" + doc.get("date"));
reader.close();
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//设置日期
private void setDates(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
dates = new Date[ids.length];
dates[0] = sdf.parse("2015-02-15");
dates[1] = sdf.parse("2015-03-01");
dates[2] = sdf.parse("2015-05-18");
dates[3] = sdf.parse("2015-09-05");
dates[4] = sdf.parse("2015-12-15");
dates[5] = sdf.parse("2015-08-29");
} catch (ParseException e) {
e.printStackTrace();
}
}
public void search02(){
IndexSearcher searcher = null;
try {
mgr.maybeReopen();//判断是否需要重新打开一个IndexSearcher
searcher = mgr.acquire();
TermQuery query = new TermQuery(new Term("content", "like"));//搜索内容中含有like的
TopDocs tds = searcher.search(query, 10);
for(ScoreDoc sd : tds.scoreDocs){
Document doc = searcher.doc(sd.doc);
System.out.println(doc.get("id") + "-->" + doc.get("name") + "[" + doc.get("email") + "]-->"
+ doc.get("attach") + "-->" + doc.get("date"));
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
mgr.release(searcher);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void commit(){
try {
writer.commit();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
说明:在方法IndexUtil
中我们实例化了IndexWriter
对象,同时使用NRTManager
对象来获得SearcherManager
对象,进而管理IndexSearcher
。在delete
和update
方法中,直接使用NRTManager
来进行相关的操作,因为此对象实现了IndexSearcher
的所有方法,所以我们不直接使用IndexSearcher
了。在方法search02中我们使用方法maybeReopen
判断是否需要重新打开IndexSearcher
,而这个打开的时间我们在方法IndexUtil
中设置的为25-5000秒之间。
测试:
测试时对testSearch02
方法进行修改:
@Test
public void testSearch02(){
IndexUtil util = new IndexUtil();
for(int i = 0; i < 5; i++){
util.search02();//这里我们让其执行5次
System.out.println("************************");
util.delete();
if(i == 2){
util.update();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
说明:测试结果:
1-->Tom[aa@qq.com]-->2-->1423929600000
2-->Jack[bb@sina.edu]-->5-->1425139200000
5-->jerry[dd@gmail.com]-->8-->1450108800000
6-->kitty[ee@163.com]-->4-->1440777600000
************************
reopen
2-->Jack[bb@sina.edu]-->5-->1425139200000
5-->jerry[dd@gmail.com]-->8-->1450108800000
6-->kitty[ee@163.com]-->4-->1440777600000
************************
2-->Jack[bb@sina.edu]-->5-->1425139200000
5-->jerry[dd@gmail.com]-->8-->1450108800000
6-->kitty[ee@163.com]-->4-->1440777600000
************************
reopen
2-->Jack[bb@sina.edu]-->5-->1425139200000
11-->Tom[aa@qq.com]-->null-->null
5-->jerry[dd@gmail.com]-->8-->1450108800000
6-->kitty[ee@163.com]-->4-->1440777600000
************************
2-->Jack[bb@sina.edu]-->5-->1425139200000
11-->Tom[aa@qq.com]-->null-->null
5-->jerry[dd@gmail.com]-->8-->1450108800000
6-->kitty[ee@163.com]-->4-->1440777600000
************************
这里我们是先进行查询,之后进行删除,同时在第三次查询的时候进行更新,更新其实就是将之前id
为1(删除的那条记录)更新为11,可以看到相应的结果。而此时我们再将删除和更新的部分注释掉,即:
util.delete();
if(i == 2){
util.update();
}
再次查询,发现并没有删除,这是因为删除只是在内存中进行,而并没有提交。这里要注意的是:这里之所以叫近实时搜索,就是这个更新的时间是由线程控制,这里我们可以将休眠时间分别该为1秒和2秒(同时将mgr.maybeReopen();
注释掉)来查看效果。当然在这个测试方法的最后加上
uti.commit();
才会将相关的更新持久化。而相比SearcherManager
,NRTManager
不需要提交就能被搜索到,这样我们就可以在一个统一的时间对索引进行更新了。
未完待续。。。