changeset 232:9ce18106f95a

more lucene work git-svn-id: https://luan-java.googlecode.com/svn/trunk@233 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Wed, 01 Oct 2014 06:55:14 +0000
parents a35417bf493a
children ef39bc4d3f70
files core/src/luan/LuanTable.java core/src/luan/LuanTableImpl.java lucene/src/luan/modules/lucene/Lucene.luan lucene/src/luan/modules/lucene/LuceneIndex.java lucene/src/luan/modules/lucene/LuceneSearcher.java
diffstat 5 files changed, 167 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/core/src/luan/LuanTable.java	Wed Oct 01 02:15:39 2014 +0000
+++ b/core/src/luan/LuanTable.java	Wed Oct 01 06:55:14 2014 +0000
@@ -6,6 +6,7 @@
 
 
 public interface LuanTable extends Iterable<Map.Entry<Object,Object>> {
+	public boolean isList();
 	public List<Object> asList();
 	public Map<Object,Object> asMap();
 	public Object get(Object key);
--- a/core/src/luan/LuanTableImpl.java	Wed Oct 01 02:15:39 2014 +0000
+++ b/core/src/luan/LuanTableImpl.java	Wed Oct 01 06:55:14 2014 +0000
@@ -79,7 +79,7 @@
 			clone.metatable = cloner.get(metatable);
 	}
 
-	public boolean isList() {
+	@Override public boolean isList() {
 		return map==null || map.isEmpty();
 	}
 
--- a/lucene/src/luan/modules/lucene/Lucene.luan	Wed Oct 01 02:15:39 2014 +0000
+++ b/lucene/src/luan/modules/lucene/Lucene.luan	Wed Oct 01 06:55:14 2014 +0000
@@ -2,12 +2,12 @@
 import "luan.modules.lucene.LuceneIndex"
 
 standard_fields = {
-	"type" = "type index";
-	"id" = "id index";
+	type = "type index";
+	id = "id index";
 }
 
 function Index(indexDir)
-	local index LuceneIndex.new(indexDir).table()
+	local index = LuceneIndex.new(indexDir).table()
 
 	function index.save_document(doc)
 		index.Writer( function(writer)
@@ -21,5 +21,17 @@
 		end )
 	end
 
+	function index.get_document(query)
+		index.Searcher( function(searcher)
+			local results, _, total_hits = searcher.search(query,1)
+			if total_hits == 0 then
+				return nil
+			elseif total_hits > 1 then
+				error "found " .. total_hits .. " documents"
+			end
+			return results()
+		end )
+	end
+
 	return index
 end
--- a/lucene/src/luan/modules/lucene/LuceneIndex.java	Wed Oct 01 02:15:39 2014 +0000
+++ b/lucene/src/luan/modules/lucene/LuceneIndex.java	Wed Oct 01 06:55:14 2014 +0000
@@ -88,7 +88,7 @@
 	private long idLim = 0;
 	private final int idBatch = 10;
 
-	private void initId() {
+	private void initId() throws IOException {
 		TopDocs td = searcher.search(new TermQuery(new Term(FLD_TYPE,"next_id")),1);
 		switch(td.totalHits) {
 		case 0:
@@ -119,27 +119,6 @@
 		}
 	}
 
-	public LuanTable getDocument(String id) {
-		return getDocument(new Term(LuceneWriter.FLD_ID,id));
-	}
-
-	public LuanTable getDocument(Term term) {
-		LuceneSearcher searcher = openSearcher();
-		try {
-			TopDocs td = searcher.search(new TermQuery(term),1);
-			switch(td.totalHits) {
-			case 0:
-				return null;
-			case 1:
-				return searcher.doc(td.scoreDocs[0].doc);
-			default:
-				throw new RuntimeException();
-			}
-		} finally {
-			searcher.close();
-		}
-	}
-
 
 	public void backup(String zipFile) {
 		if( !zipFile.endsWith(".zip") )
@@ -180,6 +159,15 @@
 		}
 	}
 
+	public void Searcher(LuanState luan,LuanFunction fn) throws LuanException, IOException {
+		LuceneSearcher searcher = openSearcher();
+		try {
+			luan.call( fn, new Object[]{searcher.table()} );
+		} finally {
+			searcher.close();
+		}
+	}
+
 	private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
 		t.put( method, new LuanJavaFunction(LuceneIndex.class.getMethod(method,parameterTypes),this) );
 	}
@@ -189,6 +177,8 @@
 		try {
 			add( tbl, "to_string" );
 			add( tbl, "backup", String.class );
+			add( tbl, "Writer", LuanState.class, LuanFunction.class );
+			add( tbl, "Searcher", LuanState.class, LuanFunction.class );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
--- a/lucene/src/luan/modules/lucene/LuceneSearcher.java	Wed Oct 01 02:15:39 2014 +0000
+++ b/lucene/src/luan/modules/lucene/LuceneSearcher.java	Wed Oct 01 06:55:14 2014 +0000
@@ -1,17 +1,27 @@
 package luan.modules.lucene;
 
 import java.io.IOException;
-import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Map;
+import java.util.List;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.document.Document;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.search.TopFieldDocs;
 import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.BooleanClause;
+import luan.Luan;
+import luan.LuanState;
 import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanJavaFunction;
+import luan.LuanException;
 
 
 public final class LuceneSearcher {
@@ -22,7 +32,7 @@
 	}
 
 	// call in finally block
-	public void close() {
+	void close() {
 		try {
 			searcher.getIndexReader().decRef();
 		} catch(IOException e) {
@@ -30,56 +40,143 @@
 		}
 	}
 
-	private Document rawDoc(int docID) {
-		try {
-			return searcher.doc(docID);
-		} catch(IOException e) {
-			throw new RuntimeException(e);
+	public LuanTable doc(int docID) throws IOException {
+		return LuceneDocument.toTable(searcher.doc(docID));
+	}
+
+	TopDocs search(Query query,int n) throws IOException {
+		return searcher.search(query,n);
+	}
+
+	TopFieldDocs search(Query query,int n,Sort sort) throws IOException {
+		return searcher.search(query,n,sort);
+	}
+
+	// luan
+
+	private Query termQuery(Map<Object,Object> map) {
+		if( map.size() != 1 )
+			return null;
+		Map.Entry<Object,Object> entry = map.entrySet().iterator().next();
+		Object key = entry.getKey();
+		Object value = entry.getValue();
+		if( key instanceof String && value instanceof String ) {
+			return new TermQuery(new Term( (String)key, (String)value ));
 		}
+		return null;
 	}
 
-	public LuanTable doc(int docID) {
-		return LuceneDocument.toTable(rawDoc(docID));
+	private Query booleanQuery(Map<Object,Object> map) {
+		BooleanQuery query = new BooleanQuery();
+		for( Map.Entry<Object,Object> entry : map.entrySet() ) {
+			Object key = entry.getKey();
+			Object value = entry.getValue();
+			if( !(key instanceof String && value instanceof LuanTable) )
+				return null;
+			Query subQuery = query( (LuanTable)value );
+			if( subQuery == null )
+				return null;
+			BooleanClause.Occur occur;
+			try {
+				occur = BooleanClause.Occur.valueOf( ((String)key).toUpperCase() );
+			} catch(IllegalArgumentException e) {
+				return null;
+			}
+			query.add(subQuery,occur);
+		}
+		return query;
+	}
+
+	private Query query(LuanTable queryTbl) {
+		Map<Object,Object> map = queryTbl.asMap();
+		if( map.isEmpty() )
+			return null;
+		Query query;
+		query = termQuery(map);  if(query!=null) return query;
+		query = booleanQuery(map);  if(query!=null) return query;
+		return null;
 	}
 
-	public TopDocs search(Query query,int n) {
+	private SortField sortField(LuanState luan,List<Object> list,String pos) throws LuanException {
+		int size = list.size();
+		if( size < 2 || size > 3 )
+			throw luan.exception("invalid sort field"+pos);
+		Object obj0 = list.get(0);
+		Object obj1 = list.get(1);
+		if( !(obj0 instanceof String && obj1 instanceof String) )
+			throw luan.exception("invalid sort field"+pos);
+		String field = (String)obj0;
+		SortField.Type type;
 		try {
-			return searcher.search(query,n);
-		} catch(IOException e) {
-			throw new RuntimeException(e);
+			type = SortField.Type.valueOf( ((String)obj1).toUpperCase() );
+		} catch(IllegalArgumentException e) {
+			throw luan.exception("invalid sort field type"+pos);
 		}
+		if( size == 2 )
+			return new SortField(field,type);
+		Object obj2 = list.get(2);
+		if( !(obj2 instanceof Boolean) )
+			throw luan.exception("invalid sort field"+pos+", 'reverse' must be boolean");
+		boolean reverse = (Boolean)obj2;
+		return new SortField(field,type,reverse);
 	}
 
-	public TopFieldDocs search(Query query,int n,Sort sort) {
+	private Sort sort(LuanState luan,LuanTable sortTbl) throws LuanException {
+		if( !sortTbl.isList() )
+			throw luan.exception("invalid sort, must be list");
+		List<Object> list = sortTbl.asList();
+		if( list.isEmpty() )
+			throw luan.exception("sort cannot be empty");
+		if( list.get(0) instanceof String )
+			return new Sort(sortField(luan,list,""));
+		SortField[] flds = new SortField[list.size()];
+		for( int i=0; i<flds.length; i++ ) {
+			Object obj = list.get(i);
+			if( !(obj instanceof LuanTable) )
+				throw luan.exception("invalid sort parameter at position "+(i+1));
+			LuanTable fldTbl = (LuanTable)obj;
+			if( !fldTbl.isList() )
+				throw luan.exception("invalid sort field at position "+(i+1)+", must be list");
+			flds[i] = sortField(luan,fldTbl.asList()," at position "+(i+1));
+		}
+		return new Sort(flds);
+	}
+
+	public Object[] search( LuanState luan, LuanTable queryTbl, int n, LuanTable sortTbl ) throws LuanException, IOException {
+		Query query = query(queryTbl);
+		if( query == null )
+			throw luan.exception("invalid query");
+		TopDocs td = sortTbl==null ? searcher.search(query,n) : searcher.search(query,n,sort(luan,sortTbl));
+		final ScoreDoc[] scoreDocs = td.scoreDocs;
+		LuanFunction results = new LuanFunction() {
+			int i = 0;
+
+			@Override public Object call(LuanState luan,Object[] args) throws LuanException {
+				if( i >= scoreDocs.length )
+					return LuanFunction.NOTHING;
+				try {
+					LuanTable doc = doc(scoreDocs[i++].doc);
+					return doc;
+				} catch(IOException e) {
+					throw luan.exception(e);
+				}
+			}
+		};
+		return new Object[]{ results, scoreDocs.length, td.totalHits };
+	}
+
+	private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
+		t.put( method, new LuanJavaFunction(LuceneSearcher.class.getMethod(method,parameterTypes),this) );
+	}
+
+	LuanTable table() {
+		LuanTable tbl = Luan.newTable();
 		try {
-			return searcher.search(query,n,sort);
-		} catch(IOException e) {
+			add( tbl, "search", LuanState.class, LuanTable.class, Integer.TYPE, LuanTable.class );
+		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
+		return tbl;
 	}
 
-	public Iterable<LuanTable> docs(TopDocs td) {
-		final ScoreDoc[] scoreDocs = td.scoreDocs;
-		return new Iterable<LuanTable>() {
-			public Iterator<LuanTable> iterator() {
-				return new Iterator<LuanTable>() {
-					private int i = 0;
-
-					public boolean hasNext() {
-						return i < scoreDocs.length;
-					}
-
-					public LuanTable next() {
-						if( !hasNext() )
-							throw new NoSuchElementException();
-						return doc(scoreDocs[i++].doc);
-					}
-
-					public void remove() {
-						throw new UnsupportedOperationException();
-					}
-				};
-			}
-		};
-	}
 }