diff lucene/src/luan/modules/lucene/LuceneIndex.java @ 545:ddcd4296107a

clean up lucene search
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 14 Jun 2015 01:34:42 -0600
parents c5a93767cc5c
children eaef1005ab87
line wrap: on
line diff
--- a/lucene/src/luan/modules/lucene/LuceneIndex.java	Fri Jun 12 19:11:44 2015 -0600
+++ b/lucene/src/luan/modules/lucene/LuceneIndex.java	Sun Jun 14 01:34:42 2015 -0600
@@ -18,6 +18,7 @@
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.SnapshotDeletionPolicy;
+import org.apache.lucene.index.AtomicReaderContext;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.FSDirectory;
 import org.apache.lucene.util.Version;
@@ -27,6 +28,10 @@
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.TotalHitCountCollector;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.Scorer;
 import sane.lucene.queryparser.SaneQueryParser;
 import sane.lucene.queryparser.FieldParser;
 import sane.lucene.queryparser.MultiFieldParser;
@@ -41,6 +46,7 @@
 import luan.LuanJavaFunction;
 import luan.LuanException;
 import luan.LuanMeta;
+import luan.LuanRuntimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,16 +58,19 @@
 	private static final Analyzer analyzer = new KeywordAnalyzer();
 	public static final FieldParser STRING_FIELD_PARSER = new StringFieldParser(analyzer);
 
+	final LuanTable myTable;
 	final Lock writeLock = new ReentrantLock();
 	private final File indexDir;
 	final SnapshotDeletionPolicy snapshotDeletionPolicy;
 	final IndexWriter writer;
 	private DirectoryReader reader;
-	private LuceneSearcher searcher;
+	private IndexSearcher searcher;
+	private final ThreadLocal<IndexSearcher> threadLocalSearcher = new ThreadLocal<IndexSearcher>();
 	private boolean isClosed = false;
 	private final MultiFieldParser mfp = new MultiFieldParser();
 
-	public LuceneIndex(LuanState luan,String indexDirStr) throws LuanException, IOException {
+	public LuceneIndex(LuanState luan,String indexDirStr,LuanTable myTable) throws LuanException, IOException {
+		this.myTable = myTable;
 		mfp.fields.put( "type", STRING_FIELD_PARSER );
 		mfp.fields.put( "id", NumberFieldParser.LONG );
 		File indexDir = new File(indexDirStr);
@@ -75,7 +84,7 @@
 		writer.commit();  // commit index creation
 		reader = DirectoryReader.open(dir);
 		luan.onClose(this);
-		searcher = new LuceneSearcher(this,reader);
+		searcher = new IndexSearcher(reader);
 		initId(luan);
 	}
 
@@ -87,17 +96,22 @@
 		return new LuceneWriter(this);
 	}
 
-	synchronized LuceneSearcher openSearcher() throws IOException {
+	private synchronized IndexSearcher openSearcher() throws IOException {
 		DirectoryReader newReader = DirectoryReader.openIfChanged(reader);
 		if( newReader != null ) {
 			reader.decRef();
 			reader = newReader;
-			searcher = new LuceneSearcher(this,reader);
+			searcher = new IndexSearcher(reader);
 		}
 		reader.incRef();
 		return searcher;
 	}
 
+	// call in finally block
+	private static void close(IndexSearcher searcher) throws IOException {
+		searcher.getIndexReader().decRef();
+	}
+
 	LuceneSnapshot openSnapshot() throws IOException {
 		return new LuceneSnapshot(this);
 	}
@@ -119,7 +133,6 @@
 	private final int idBatch = 10;
 
 	private void initId(LuanState luan) throws LuanException, IOException {
-		IndexSearcher searcher = this.searcher.searcher;
 		TopDocs td = searcher.search(new TermQuery(new Term("type","next_id")),1);
 		switch(td.totalHits) {
 		case 0:
@@ -172,7 +185,7 @@
 		return writer.getDirectory().toString();
 	}
 
-	public void Writer(LuanState luan,LuanFunction fn) throws LuanException, IOException {
+	public void writer(LuanState luan,LuanFunction fn) throws LuanException, IOException {
 		LuceneWriter writer = openWriter();
 		try {
 			luan.call( fn, new Object[]{writer.table()} );
@@ -182,15 +195,6 @@
 		}
 	}
 
-	public Object Searcher(LuanState luan,LuanFunction fn) throws LuanException, IOException {
-		LuceneSearcher searcher = openSearcher();
-		try {
-			return luan.call( fn, new Object[]{searcher.table()} );
-		} finally {
-			searcher.close();
-		}
-	}
-
 	public void close() throws IOException {
 		if( !isClosed ) {
 			writer.close();
@@ -209,6 +213,100 @@
 
 
 
+	private static class DocFn extends LuanFunction {
+		final IndexSearcher searcher;
+		int docID;
+
+		DocFn(IndexSearcher searcher) {
+			this.searcher = searcher;
+		}
+
+		@Override public Object call(LuanState luan,Object[] args) throws LuanException {
+			try {
+				return LuceneDocument.toTable(luan,searcher.doc(docID));
+			} catch(IOException e) {
+				throw luan.exception(e);
+			}
+		}
+	}
+
+	private static abstract class MyCollector extends Collector {
+		int docBase;
+		int i = 0;
+
+		@Override public void setScorer(Scorer scorer) {}
+		@Override public void setNextReader(AtomicReaderContext context) {
+			this.docBase = context.docBase;
+		}
+		@Override public boolean acceptsDocsOutOfOrder() {
+			return true;
+		}
+	}
+
+	public int advanced_search( final LuanState luan, String queryStr, LuanFunction fn, Integer n, String sortStr ) throws LuanException, IOException, ParseException {
+		Utils.checkNotNull(luan,queryStr);
+		Query query = parseQuery(queryStr);
+		IndexSearcher searcher = threadLocalSearcher.get();
+		boolean inTransaction = searcher != null;
+		if( !inTransaction )
+			searcher = openSearcher();
+		try {
+			if( fn!=null && n==null ) {
+				if( sortStr != null )
+					throw luan.exception("sort must be nil when n is nil");
+				final DocFn docFn = new DocFn(searcher);
+				MyCollector col = new MyCollector() {
+					@Override public void collect(int doc) {
+						try {
+							docFn.docID = doc;
+							luan.call(fn,new Object[]{++i,docFn});
+						} catch(LuanException e) {
+							throw new LuanRuntimeException(e);
+						}
+					}
+				};
+				try {
+					searcher.search(query,col);
+				} catch(LuanRuntimeException e) {
+					throw (LuanException)e.getCause();
+				}
+				return col.i;
+			}
+			if( fn==null || n==0 ) {
+				TotalHitCountCollector thcc = new TotalHitCountCollector();
+				searcher.search(query,thcc);
+				return thcc.getTotalHits();
+			}
+			Sort sort = sortStr==null ? null : parseSort(sortStr);
+			TopDocs td = sort==null ? searcher.search(query,n) : searcher.search(query,n,sort);
+			final ScoreDoc[] scoreDocs = td.scoreDocs;
+			DocFn docFn = new DocFn(searcher);
+			for( int i=0; i<scoreDocs.length; i++ ) {
+				docFn.docID = scoreDocs[i].doc;
+				luan.call(fn,new Object[]{i+1,docFn});
+			}
+			return td.totalHits;
+		} finally {
+			if( !inTransaction )
+				close(searcher);
+		}
+	}
+
+	public Object search_in_transaction(LuanState luan,LuanFunction fn) throws LuanException, IOException {
+		if( threadLocalSearcher.get() != null )
+			throw luan.exception("can't nest search_in_transaction calls");
+		IndexSearcher searcher = openSearcher();
+		threadLocalSearcher.set(searcher);
+		try {
+			return luan.call(fn);
+		} finally {
+			threadLocalSearcher.set(null);
+			close(searcher);
+		}
+	}
+
+
+
 	public final LuanMeta indexedFieldsMeta = new LuanMeta() {
 
 		@Override public boolean canNewindex() {