近实时搜索SearcherManager和NRTManager的使用 - 学习笔记 - 博客频道 - CSDN.NET

标签: 实时 搜索 searchermanager | 发表时间:2017-06-18 15:32 | 作者:
出处:http://blog.csdn.net

lucene通过NRTManager这个类来实现近实时搜索,所谓近实时搜索即在索引发生改变时,通

过线程跟踪,在相对很短的时间反映给给用户程序的调用

NRTManager通过管理IndexWriter对象,并将IndexWriter的一些方法(增删改)例如

addDocument,deleteDocument等方法暴露给客户调用,它的操作全部在内存里面,所以如果

你不调用IndexWriter的commit方法,通过以上的操作,用户硬盘里面的索引库是不会变化的,所

以你每次更新完索引库请记得commit掉,这样才能将变化的索引一起写到硬盘中,实现索引更新后的同步

用户每次获取最新索引(IndexSearcher),可以通过两种方式,第一种是通过调用

NRTManagerReopenThread对象,该线程负责实时跟踪索引内存的变化,每次变化就调用

maybeReopen方法,保持最新代索引,打开一个新的IndexSearcher对象,而用户所要的

IndexSearcher对象是NRTManager通过调用getSearcherManager方法获得SearcherManager对

象,然后通过SearcherManager对象获取IndexSearcher对象返回个客户使用,用户使用完之

后调用SearcherManager的release释放IndexSearcher对象,最后记得关闭NRTManagerReopenThread;

第二种方式是不通过NRTManagerReopenThread对象,而是直接调用NRTManager的

maybeReopen方法来获取最新的IndexSearcher对象来获取最新索引

1、工程目录



2、只使用SearcherManager,不使用NRTManager的方式搜索

package org.itat.index;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.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.util.Version;

/**
 * 只使用SearcherManager,不使用NRTManager
 * 
 * SearcherManager的maybeReopen会自动检查是否需要重新打开,比如重复执行search02几次,
 * 中间的一次删除一条数据这个删除的数据需要对writer进行commit才行,这样硬盘上的索引才会生效
 * 那么使用maybeReopen就可以检测到硬盘中的索引是否改变,并在下次查询的时候就进行生效
 * 
 * 但是:
 * 光使用SearcherManager的话做不到实时搜索,为什么呢?
 * 因为使用SearcherManager需要进行writer.commit才会检测到,但是我们知道writer的commit是非常
 * 消耗性能的,我们不能经常性的commit,那需要怎么做呢?
 * 我们只能把添加修改删除的操作在内存中生效,然后使用内存中的索引信息并且在搜索时能起到效果,
 * 过一段时间累计到一定程序才进行writer.commit
 */
public class IndexUtil1 {
	private String[] ids = {"1","2","3","4","5","6"};
	private String[] emails = {"[email protected]","[email protected]","[email protected]","[email protected]","[email protected]","[email protected]"};
	private String[] contents = {
			"welcome to visited the space,I like book",
			"hello boy, I like pingpeng ball",
			"my name is cc I like game",
			"I like football",
			"I like football and I like basketball too",
			"I like movie and swim"
	};
	private int[] attachs = {2,3,1,4,5,5};
	private String[] names = {"zhangsan","lisi","john","jetty","mike","jake"};
	private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
	private SearcherManager mgr = null;//是线程安全的
	
	private Directory directory = null;
	
	public IndexUtil1() {
		try {
			directory = FSDirectory.open(new File("D:\\Workspaces\\realtime\\index"));
			mgr = new SearcherManager(
				directory, 
				new SearcherWarmer() {
				/**
				 * 索引一更新就要重新获取searcher,那获取searcher的时候就会调用这个方法
				 * 执行maybeReopen的时候会执行warm方法,在这里可以对资源等进行控制
				 */
					@Override
					public void warm(IndexSearcher search) throws IOException {
						System.out.println("has change");
					}
				}, 
				Executors.newCachedThreadPool()
			);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除索引数据,默认不会完全删除,被放入索引回收站
	 */
	public void delete(String id) {
		IndexWriter writer = null;
		
		try {
			writer = new IndexWriter(directory,
					new IndexWriterConfig(Version.LUCENE_35,analyzer));
			//参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
			//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
			//执行完这个操作,索引文件夹下就会多出一个名叫_0_1.del的文件,也就是删除的文件在这个文件中记录了
			writer.deleteDocuments(new Term("id",id));
			writer.commit();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer!=null) writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void query() {
		try {
			IndexReader reader = IndexReader.open(directory);
			//通过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();
		}
	}
	/**
	 *	索引文件后缀为.fmn为保存的是域的名称等
	 * .fdt和.fdx保存的是Store.YES的信息,保存域里面存储的数据
	 * .frq表示这里的域哪些出现多少次,哪些单词出现多少次,
	 * .nrm存储一些评分信息
	 * .prx存储一些偏移量等
	 * .tii和.tis专门存储索引里面的所有内容信息
	 */
	public void index() {
		IndexWriter writer = null;
		try {
			//在2.9版本之后,lucene的就不是全部的索引格式都兼容的了,所以在使用的时候必须写明版本号
			writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, analyzer));
			writer.deleteAll();//清空索引
			Document doc = null;
			for(int i=0;i<ids.length;i++) {
				doc = new Document();
				doc.add(new Field("id",ids[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("email","test"+i+"@test.com",Field.Store.YES,Field.Index.NOT_ANALYZED));
				doc.add(new Field("content",contents[i],Field.Store.NO,Field.Index.ANALYZED));
				doc.add(new Field("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
				//存储数字
				//NumberTools.stringToLong("");已经被标记为过时了
				doc.add(new NumericField("attach",Field.Store.YES,true).setIntValue(attachs[i]));
				String et = emails[i].substring(emails[i].lastIndexOf("@")+1);
				writer.addDocument(doc);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer!=null)writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void search02() {
		IndexSearcher searcher = mgr.acquire();//获得一个searcher
		try {
			/**
			 * maybeReopen会自动检查是否需要重新打开
			 * 比如重复执行search02几次,中间一次删除一条数据
			 * 这个删除的数据需要对writer进行commit才行
			 * 那么使用maybeReopen就可以检测到硬盘中的索引是否改变
			 * 并在下次查询的时候把删除的这条给去掉
			 */
			mgr.maybeReopen();
			TermQuery query = new TermQuery(new Term("content","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("id")+","+
						doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);
			}
			searcher.close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				mgr.release(searcher);//释放一个searcher
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}


3、SearcherManager和NRTManager联合使用

package org.itat.index;

import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.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.util.Version;

/**
 * SearcherManager和NRTManager联合使用
 * 
 * SearcherManager的maybeReopen会自动检查是否需要重新打开,比如重复执行search02几次,
 * 中间的一次删除一条数据这个删除的数据需要对writer进行commit才行,这样硬盘上的索引才会生效
 * 那么使用maybeReopen就可以检测到硬盘中的索引是否改变,并在下次查询的时候就进行生效
 * 
 * 但是:
 * 光使用SearcherManager的话做不到实时搜索,为什么呢?
 * 因为使用SearcherManager需要进行writer.commit才会检测到,但是我们知道writer的commit是非常
 * 消耗性能的,我们不能经常性的commit,那需要怎么做呢?
 * 我们只能把添加修改删除的操作在内存中生效,然后使用内存中的索引信息并且在搜索时能起到效果,
 * 过一段时间累计到一定程序才进行writer.commit
 * NRTManage就是这样的功能,把更新的数据存储在内容中,但是lucene搜索的时候也可以搜索到,需要
 * writer进行commit才会把索引更新到硬盘中
 */
public class IndexUtil2 {
	private String[] ids = {"1","2","3","4","5","6"};
	private String[] emails = {"[email protected]","[email protected]","[email protected]","[email protected]","[email protected]","[email protected]"};
	private String[] contents = {
			"welcome to visited the space,I like book",
			"hello boy, I like pingpeng ball",
			"my name is cc I like game",
			"I like football",
			"I like football and I like basketball too",
			"I like movie and swim"
	};
	private int[] attachs = {2,3,1,4,5,5};
	private String[] names = {"zhangsan","lisi","john","jetty","mike","jake"};
	private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
	private SearcherManager mgr = null;//是线程安全的
	private NRTManager nrtMgr = null;//near real time  近实时搜索
	private Directory directory = null;
	private IndexWriter writer = null;
	
	public IndexUtil2() {
		try {
			directory = FSDirectory.open(new File("D:\\Workspaces\\realtime\\index"));
			writer = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35, analyzer));
			nrtMgr = new NRTManager(writer, 
						new SearcherWarmer() {
							/**
							 * 索引一更新就要重新获取searcher,那获取searcher的时候就会调用这个方法
							 * 执行maybeReopen的时候会执行warm方法,在这里可以对资源等进行控制
							 */
							@Override
							public void warm(IndexSearcher search) throws IOException {
								System.out.println("has open");
							}
						}
			);
			//启动NRTManager的Reopen线程
			//NRTManagerReopenThread会每隔25秒去检测一下索引是否更新并判断是否需要重新打开writer
			NRTManagerReopenThread reopen = new NRTManagerReopenThread(nrtMgr, 5.0, 0.025);//0.025为25秒
			reopen.setDaemon(true);//设为后台线程
			reopen.setName("NrtManager Reopen Thread");
			reopen.start();
			
			mgr = nrtMgr.getSearcherManager(true);//true为允许所有的更新
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除索引数据,默认不会完全删除,被放入索引回收站
	 */
	public void delete(String id) {
		
		try {
			//参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
			//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
			//执行完这个操作,索引文件夹下就会多出一个名叫_0_1.del的文件,也就是删除的文件在这个文件中记录了
			nrtMgr.deleteDocuments(new Term("id",id));//使用使用nrtMgr来删除
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}

	public void query() {
		try {
			IndexReader reader = IndexReader.open(directory);
			//通过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();
		}
	}
	/**
	 *	索引文件后缀为.fmn为保存的是域的名称等
	 * .fdt和.fdx保存的是Store.YES的信息,保存域里面存储的数据
	 * .frq表示这里的域哪些出现多少次,哪些单词出现多少次,
	 * .nrm存储一些评分信息
	 * .prx存储一些偏移量等
	 * .tii和.tis专门存储索引里面的所有内容信息
	 */
	public void index() {
		IndexWriter writer = null;
		try {
			//在2.9版本之后,lucene的就不是全部的索引格式都兼容的了,所以在使用的时候必须写明版本号
			writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, analyzer));
			writer.deleteAll();//清空索引
			Document doc = null;
			for(int i=0;i<ids.length;i++) {
				doc = new Document();
				doc.add(new Field("id",ids[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("email","test"+i+"@test.com",Field.Store.YES,Field.Index.NOT_ANALYZED));
				doc.add(new Field("content",contents[i],Field.Store.NO,Field.Index.ANALYZED));
				doc.add(new Field("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
				//存储数字
				//NumberTools.stringToLong("");已经被标记为过时了
				doc.add(new NumericField("attach",Field.Store.YES,true).setIntValue(attachs[i]));
				String et = emails[i].substring(emails[i].lastIndexOf("@")+1);
				writer.addDocument(doc);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer!=null)writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void search02() {
		IndexSearcher searcher = mgr.acquire();//获得一个searcher
		try {
			/**
			 * maybeReopen会自动检查是否需要重新打开
			 * 比如重复执行search02几次,中间一次删除一条数据
			 * 这个删除的数据需要对writer进行commit才行
			 * 那么使用maybeReopen就可以检测到硬盘中的索引是否改变
			 * 并在下次查询的时候把删除的这条给去掉
			 */
			TermQuery query = new TermQuery(new Term("content","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("id")+","+
						doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);
			}
			searcher.close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				mgr.release(searcher);//释放一个searcher
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

4、不使用SearcherManager和NRTManager

package org.itat.index;

import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
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.util.Version;

/**
 * 不使用SearcherManager和NRTManager
 * @author user
 */
public class IndexUtil {
	private String[] ids = {"1","2","3","4","5","6"};
	private String[] emails = {"[email protected]","[email protected]","[email protected]","[email protected]","[email protected]","[email protected]"};
	private String[] contents = {
			"welcome to visited the space,I like book",
			"hello boy, I like pingpeng ball",
			"my name is cc I like game",
			"I like football",
			"I like football and I like basketball too",
			"I like movie and swim"
	};
	private int[] attachs = {2,3,1,4,5,5};
	private String[] names = {"zhangsan","lisi","john","jetty","mike","jake"};
	
	private Directory directory = null;
	private static IndexReader reader = null;
	
	public IndexUtil() {
		try {
			directory = FSDirectory.open(new File("D:\\Workspaces\\realtime\\index"));
//			directory = new RAMDirectory();
//			index();
			reader = IndexReader.open(directory,false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 对于IndexReader而言,反复使用Index.open打开会有很大的开销,所以一般在整个程序的生命周期中
	 * 只会打开一个IndexReader,通过这个IndexReader来创建不同的IndexSearcher,如果使用单例模式,
	 * 可能出现的问题有:
	 * 1、当使用Writer修改了索引之后不会更新信息,所以需要使用IndexReader.openIfChange方法操作
	 * 如果IndexWriter在创建完成之后,没有关闭,需要进行commit操作之后才能提交
	 * @return
	 */
	public IndexSearcher getSearcher() {
		try {
			if(reader==null) {
				reader = IndexReader.open(directory,false);
			} else {
				IndexReader tr = IndexReader.openIfChanged(reader);
				//如果原来的reader没改变,返回null
				//如果原来的reader改变,则更新为新的索引
				if(tr!=null) {
					reader.close();
					reader = tr;
				}
			}
			return new IndexSearcher(reader);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
		
	}

	/**
	 * 删除索引数据,默认不会完全删除,被放入索引回收站
	 */
	public void delete() {
		IndexWriter writer = null;
		
		try {
			writer = new IndexWriter(directory,
					new IndexWriterConfig(Version.LUCENE_35,new StandardAnalyzer(Version.LUCENE_35)));
			//参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
			//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
			//执行完这个操作,索引文件夹下就会多出一个名叫_0_1.del的文件,也就是删除的文件在这个文件中记录了
			writer.deleteDocuments(new Term("id","1"));
			writer.commit();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer!=null) writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	
	public void query() {
		try {
			IndexReader reader = IndexReader.open(directory);
			//通过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();
		}
	}
	/**
	 *	索引文件后缀为.fmn为保存的是域的名称等
	 * .fdt和.fdx保存的是Store.YES的信息,保存域里面存储的数据
	 * .frq表示这里的域哪些出现多少次,哪些单词出现多少次,
	 * .nrm存储一些评分信息
	 * .prx存储一些偏移量等
	 * .tii和.tis专门存储索引里面的所有内容信息
	 */
	public void index() {
		IndexWriter writer = null;
		try {
			//在2.9版本之后,lucene的就不是全部的索引格式都兼容的了,所以在使用的时候必须写明版本号
			writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
			writer.deleteAll();//清空索引
			Document doc = null;
			for(int i=0;i<ids.length;i++) {
				doc = new Document();
				doc.add(new Field("id",ids[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("email","test"+i+"@test.com",Field.Store.YES,Field.Index.NOT_ANALYZED));
				doc.add(new Field("content",contents[i],Field.Store.NO,Field.Index.ANALYZED));
				doc.add(new Field("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
				//存储数字
				//NumberTools.stringToLong("");已经被标记为过时了
				doc.add(new NumericField("attach",Field.Store.YES,true).setIntValue(attachs[i]));
				String et = emails[i].substring(emails[i].lastIndexOf("@")+1);
				writer.addDocument(doc);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(writer!=null)writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void search02() {
		try {
			IndexSearcher searcher = getSearcher();
			TermQuery query = new TermQuery(new Term("content","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("id")+","+
						doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);
			}
			searcher.close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}


工程路径:http://download.csdn.net/detail/wxwzy738/5332972



相关 [实时 搜索 searchermanager] 推荐:

近实时搜索SearcherManager和NRTManager的使用 - 学习笔记 - 博客频道 - CSDN.NET

- -
lucene通过NRTManager这个类来实现近实时搜索,所谓近实时搜索即在索引发生改变时,通. 过线程跟踪,在相对很短的时间反映给给用户程序的调用. NRTManager通过管理IndexWriter对象,并将IndexWriter的一些方法(增删改)例如. addDocument,deleteDocument等方法暴露给客户调用,它的操作全部在内存里面,所以如果.

Twitter实时搜索系统EarlyBird

- - CSDN博客互联网推荐文章
twitter对存档的tweet使用lucene做全量索引,新发的推文则是实时索引,实时检索(10秒之内索引). 实时索引和检索系统叫EarlyBird. 感觉写得比较清楚简洁,只要这些信息足够真实可信,完全可以做实现参考. 1)基于lucene + java,michael busch是lucene committer.

[原]Lucene系列-近实时搜索

- - 文武天下
近实时搜索(near-real-time)可以搜索IndexWriter还未commit的内容,介于immediate和eventual之间,在数据比较大、更新较频繁的情况下使用. lucene的nrt可以控制更新生效的间隔时间. 从indexwriter中获得indexreader. 建立indexsearcher.

es近实时搜索原理

- - 企业架构 - ITeye博客
 随着按段(per-segment)搜索的发展, 一个新的文档从索引到可被搜索的延迟显著降低了. 新文档在几分钟之内即可被检索,但这样还是不够快.  提交(Commiting)一个新的段到磁盘需要一个 . fsync 来确保段被物理性地写入磁盘,这样在断电的时候就不会丢失数据. 但是  fsync 操作代价很大; 如果每次索引一个文档都去执行一次的话会造成很大的性能问题.

永远墙不住的Google实时搜索

- yun - 梭络
打开这个地址,然后输入你要的关键字.

缺少了 Twitter 实时搜索的 Google 确实是伤不起

- 珣子 - 谷奥——探寻谷歌的奥秘
Google+发布第二天,Google实时搜索突然不见让人感到很诧异,尽管Google开始说他们是想办法把Google+也整合进去,但那用不着整个关闭实时搜索吧. 后来才真相大白,是因为Google与Twitter的合作协议到期,所以Google无法获得实时Twitter接口“firehose”才无法继续提供实时搜索了.

分布式实时搜索方案介绍-senseidb

- - 五四陈科学院-坚信科学,分享技术
以下内容由 [五四陈科学院]提供. zoie:由linkedin开源的建立在lucene之上提供实时索引的系统. 它利用两 个内存索引一个硬盘索引来实现实时搜索. bobo-browse:由linkedin开源的基于lucene的分类浏览搜索系统. zookeeper:一个分布式的,开放源码的分布式应用程序协调服务,常用来做配置服务.

使用elasticsearch+simple_flow搭建实时日志搜索系统

- - ITeye博客
    在实际的系统中,我们经常会进行分布式的系统部署,但是这样会导致一个问题,系统日志也被分散开了,导致根据日志进行错误定位不太方便,所以,利用simple_flow实时流的特点,再配合elasticsearch建立索引,搭配构建一个实时日志搜索系统.具体流程图如下:. 1.启动elasticsearch, 这个参考官方文档  http://www.elasticsearch.org/.

LinkedIn公司Zoie实现实时搜索的原理

- - 非技术 - ITeye博客
原文: http://www.cnblogs.com/forfuture1978/archive/2010/11/29/1891476.html. Zoie是linkedin公司基于Lucene实现的实时搜索引擎系统,按照其官方wiki的描述为:. Zoie是一个实时的搜索引擎系统,其需要逻辑上独立的索引和搜索子系统相对紧密的结合在一起,从而使得一篇文档一经索引,就能够立刻被搜索的到.

从未降级的搜索技术-实时之刃

- - 搜索技术博客-淘宝
流量是互联网变现的基石,而流量的资源是有限的,如何实现资源的最大化利用(买家-商品的最高效的匹配)是此次双11搜索技术深度切入的使命,也是第一次在双11通过实时把握资源流动的脉搏来控制资源的收和放. 天猫的业务团队同学,通过针对去年双11细致认真的数据分析,发现了去年双11暴露的一些问题. 小部分商品预热过度,预热期吸引的加购量远超出商品库存能支撑的量,大部分用户虽然加了购物车但当天也抢不到,购物车转化率低;而大部分商品预热不足,没有充分曝光;.