Hi Thomas.

I prepared a patch to allow in-memory fulltext search in H2. Also fixed a 
bug - on row delete lucene index was not committed. Please take a look.

Sergi

-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/h2-database/-/PnUlxxpttekJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/h2-database?hl=en.

Index: src/main/org/h2/fulltext/FullTextLucene.java
===================================================================
--- src/main/org/h2/fulltext/FullTextLucene.java	(revision 4240)
+++ src/main/org/h2/fulltext/FullTextLucene.java	(working copy)
@@ -48,6 +48,7 @@
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.store.FSDirectory;
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
 import org.apache.lucene.util.Version;
 import org.apache.lucene.index.IndexWriter;
 //*/
@@ -71,6 +72,8 @@
     private static final String LUCENE_FIELD_MODIFIED = "_modified";
     private static final String LUCENE_FIELD_COLUMN_PREFIX = "_";
 
+    private static final String IN_MEMORY_PERFIX = "mem:";
+
     /**
      * Initializes full text search functionality for this database. This adds
      * the following Java functions to the database:
@@ -262,8 +265,7 @@
                     access.modifier = new IndexModifier(path, analyzer, recreate);
                     //*/
                     //## LUCENE3 ##
-                    File f = new File(path);
-                    Directory indexDir = FSDirectory.open(f);
+                    Directory indexDir = path.startsWith(IN_MEMORY_PERFIX) ? new RAMDirectory() : FSDirectory.open(new File(path));
                     boolean recreate = !IndexReader.indexExists(indexDir);
                     Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
                     IndexWriter writer = new IndexWriter(indexDir, analyzer,
@@ -296,7 +298,12 @@
         rs.next();
         String path = rs.getString(1);
         if (path == null) {
-            throw throwException("Fulltext search for in-memory databases is not supported.");
+            /*## LUCENE2 ##
+            throw throwException("Fulltext search for in-memory databases is not supported with Lucene 2. Please use Lucene 3 instead.");
+    	    //*/
+            //## LUCENE3 ##
+            return IN_MEMORY_PERFIX + conn.getCatalog();
+            //*/
         }
         int index = path.lastIndexOf(':');
         // position 1 means a windows drive letter is used, ignore that
@@ -336,7 +343,9 @@
         if (access != null) {
             removeIndexAccess(access, path);
         }
-        FileUtils.deleteRecursive(path, false);
+        if (!path.startsWith(IN_MEMORY_PERFIX)) {
+            FileUtils.deleteRecursive(path, false);
+        }
     }
 
     /**
@@ -665,13 +674,7 @@
             try {
                 indexAccess.writer.addDocument(doc);
                 if (commitIndex) {
-                    indexAccess.writer.commit();
-                    // recreate Searcher with the IndexWriter's reader.
-                    indexAccess.searcher.close();
-                    indexAccess.reader.close();
-                    IndexReader reader = indexAccess.writer.getReader();
-                    indexAccess.reader = reader;
-                    indexAccess.searcher = new IndexSearcher(reader);
+                    commitIndex();
                 }
             } catch (IOException e) {
                 throw convertException(e);
@@ -693,6 +696,7 @@
                 //*/
                 //## LUCENE3 ##
                 indexAccess.writer.deleteDocuments(term);
+                commitIndex();
                 //*/
             } catch (IOException e) {
                 throw convertException(e);
Index: src/test/org/h2/test/db/TestFullText.java
===================================================================
--- src/test/org/h2/test/db/TestFullText.java	(revision 4244)
+++ src/test/org/h2/test/db/TestFullText.java	(working copy)
@@ -12,11 +12,14 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Random;
 import java.util.StringTokenizer;
 import java.util.UUID;
 import org.h2.fulltext.FullText;
 import org.h2.store.fs.FileUtils;
+import org.h2.test.TestAll;
 import org.h2.test.TestBase;
 import org.h2.util.Task;
 
@@ -45,9 +48,6 @@
         testNativeFeatures();
         testTransaction(false);
         testCreateDrop();
-        if (config.memory) {
-            return;
-        }
         testStreamLob();
         test(false, "VARCHAR");
         test(false, "CLOB");
@@ -76,34 +76,46 @@
         deleteDb("fullTextReopen");
     }
 
+    private void close(Collection<Connection> conns) throws SQLException {
+    	for (Connection conn : conns) {
+    		conn.close();
+    	}
+    }
+
+    private Connection getConnection(String name, Collection<Connection> conns) throws SQLException {
+    	Connection conn = getConnection(name);
+    	conns.add(conn);
+    	return conn;
+    }
+
     private void testAutoAnalyze() throws SQLException {
-        if (config.memory) {
-            return;
-        }
         deleteDb("fullTextNative");
         Connection conn;
         Statement stat;
 
-        conn = getConnection("fullTextNative");
+        ArrayList<Connection> conns = new ArrayList<Connection>();
+
+        conn = getConnection("fullTextNative", conns);
         stat = conn.createStatement();
         stat.execute("create alias if not exists ft_init for \"org.h2.fulltext.FullText.init\"");
         stat.execute("call ft_init()");
         stat.execute("create table test(id int primary key, name varchar)");
         stat.execute("call ft_create_index('PUBLIC', 'TEST', 'NAME')");
-        conn.close();
 
-        conn = getConnection("fullTextNative");
+        if (!config.memory) {
+        	conn.close();
+        }
+
+        conn = getConnection("fullTextNative", conns);
         stat = conn.createStatement();
         stat.execute("insert into test select x, 'x' from system_range(1, 3000)");
-        conn.close();
+        close(conns);
     }
 
     private void testNativeFeatures() throws SQLException {
-        if (config.memory) {
-            return;
-        }
         deleteDb("fullTextNative");
-        Connection conn = getConnection("fullTextNative");
+        ArrayList<Connection> conns = new ArrayList<Connection>();
+        Connection conn = getConnection("fullTextNative", conns);
         Statement stat = conn.createStatement();
         stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\"");
         stat.execute("CALL FT_INIT()");
@@ -137,8 +149,10 @@
         rs = stat.executeQuery("SELECT * FROM FT_SEARCH('this', 0, 0)");
         assertFalse(rs.next());
 
-        conn.close();
-        conn = getConnection("fullTextNative");
+        if (!config.memory) {
+        	conn.close();
+        }
+        conn = getConnection("fullTextNative", conns);
         stat = conn.createStatement();
         conn.setAutoCommit(false);
         stat.execute("delete from test");
@@ -148,8 +162,7 @@
         rs = stat.executeQuery("SELECT * FROM FT_SEARCH_DATA('Welcome', 0, 0)");
         assertTrue(rs.next());
         conn.setAutoCommit(true);
-
-        conn.close();
+        close(conns);
     }
 
     private void testUuidPrimaryKey(boolean lucene) throws SQLException {
@@ -178,13 +191,11 @@
     }
 
     private void testTransaction(boolean lucene) throws SQLException {
-        if (config.memory) {
-            return;
-        }
         String prefix = lucene ? "FTL" : "FT";
         deleteDb("fullTextTransaction");
         FileUtils.deleteRecursive(getBaseDir() + "/fullTextTransaction", false);
-        Connection conn = getConnection("fullTextTransaction");
+        ArrayList<Connection> conns = new ArrayList<Connection>();
+        Connection conn = getConnection("fullTextTransaction", conns);
         Statement stat = conn.createStatement();
         String className = lucene ? "FullTextLucene" : "FullText";
         stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
@@ -199,15 +210,17 @@
         conn.setAutoCommit(false);
         stat.execute("insert into test values(2, 'Hello Moon!')");
         conn.rollback();
-        conn.close();
-        conn = getConnection("fullTextTransaction");
+        if (!config.memory) {
+        	conn.close();
+        }
+        conn = getConnection("fullTextTransaction", conns);
         stat = conn.createStatement();
         rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
         assertTrue(rs.next());
         rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Moon', 0, 0)");
         assertFalse(rs.next());
         FullText.dropAll(conn);
-        conn.close();
+        close(conns);
         deleteDb("fullTextTransaction");
         FileUtils.deleteRecursive(getBaseDir() + "/fullTextTransaction", false);
     }
@@ -216,12 +229,13 @@
         final String prefix = lucene ? "FTL" : "FT";
         trace("Testing multithreaded " + prefix);
         deleteDb("fullText");
+        ArrayList<Connection> conns = new ArrayList<Connection>();
         int len = 2;
         Task[] task = new Task[len];
         for (int i = 0; i < len; i++) {
             // final Connection conn =
             // getConnection("fullText;MULTI_THREADED=1;LOCK_TIMEOUT=10000");
-            final Connection conn = getConnection("fullText");
+            final Connection conn = getConnection("fullText", conns);
             Statement stat = conn.createStatement();
             String className = lucene ? "FullTextLucene" : "FullText";
             stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
@@ -257,7 +271,9 @@
                         }
                     }
                     trace("closing connection");
-                    conn.close();
+                    if (!config.memory) {
+                    	conn.close();
+                    }
                     trace("completed thread " + Thread.currentThread());
                 }
             };
@@ -274,6 +290,7 @@
             t.get();
             trace("done joining " + t);
         }
+        close(conns);
     }
 
     private void testStreamLob() throws SQLException {
@@ -331,6 +348,9 @@
     }
 
     private void testReopen(boolean lucene) throws SQLException {
+    	if (config.memory) {
+        	return;
+        }
         String prefix = lucene ? "FTL" : "FT";
         deleteDb("fullTextReopen");
         FileUtils.deleteRecursive(getBaseDir() + "/fullTextReopen", false);
@@ -408,7 +428,8 @@
             return;
         }
         deleteDb("fullText");
-        Connection conn = getConnection("fullText");
+        ArrayList<Connection> conns = new ArrayList<Connection>();
+        Connection conn = getConnection("fullText", conns);
         String prefix = lucene ? "FTL_" : "FT_";
         Statement stat = conn.createStatement();
         String className = lucene ? "FullTextLucene" : "FullText";
@@ -491,15 +512,16 @@
             assertFalse(rs.next());
         }
 
-        conn.close();
+        if (!config.memory) {
+        	conn.close();
+        }
 
-        conn = getConnection("fullText");
+        conn = getConnection("fullText", conns);
         stat = conn.createStatement();
         stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 0, 0)");
 
         stat.execute("CALL " + prefix + "DROP_ALL()");
 
-        conn.close();
-
+        close(conns);
     }
 }

Reply via email to