提交 560d0380 authored 作者: Thomas Mueller's avatar Thomas Mueller

Lucene 3.x support was added in the source code, however it is not yet enabled by default.

上级 55d3d9e1
...@@ -16,17 +16,14 @@ import java.sql.SQLException; ...@@ -16,17 +16,14 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.DateTools; import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.Searcher; import org.apache.lucene.search.Searcher;
...@@ -42,6 +39,19 @@ import org.h2.util.New; ...@@ -42,6 +39,19 @@ import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
//## Java 1.4 end ## //## Java 1.4 end ##
//## LUCENE2 begin ##
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.search.Hits;
//## LUCENE2 end ##
/*## LUCENE3 begin ##
import java.io.File;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;
import org.apache.lucene.index.IndexWriter;
//## LUCENE3 end ##*/
/** /**
* This class implements the full text search based on Apache Lucene. * This class implements the full text search based on Apache Lucene.
...@@ -55,7 +65,7 @@ public class FullTextLucene extends FullText { ...@@ -55,7 +65,7 @@ public class FullTextLucene extends FullText {
protected static final boolean STORE_DOCUMENT_TEXT_IN_INDEX = Boolean.getBoolean("h2.storeDocumentTextInIndex"); protected static final boolean STORE_DOCUMENT_TEXT_IN_INDEX = Boolean.getBoolean("h2.storeDocumentTextInIndex");
//## Java 1.4 begin ## //## Java 1.4 begin ##
private static final HashMap<String, IndexModifier> INDEX_MODIFIERS = New.hashMap(); private static final HashMap<String, IndexAccess> INDEX_ACCESS = New.hashMap();
private static final String TRIGGER_PREFIX = "FTL_"; private static final String TRIGGER_PREFIX = "FTL_";
private static final String SCHEMA = "FTL"; private static final String SCHEMA = "FTL";
private static final String LUCENE_FIELD_DATA = "_DATA"; private static final String LUCENE_FIELD_DATA = "_DATA";
...@@ -98,7 +108,7 @@ public class FullTextLucene extends FullText { ...@@ -98,7 +108,7 @@ public class FullTextLucene extends FullText {
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_REINDEX FOR \"" + FullTextLucene.class.getName() + ".reindex\""); stat.execute("CREATE ALIAS IF NOT EXISTS FTL_REINDEX FOR \"" + FullTextLucene.class.getName() + ".reindex\"");
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_DROP_ALL FOR \"" + FullTextLucene.class.getName() + ".dropAll\""); stat.execute("CREATE ALIAS IF NOT EXISTS FTL_DROP_ALL FOR \"" + FullTextLucene.class.getName() + ".dropAll\"");
try { try {
getIndexModifier(conn); getIndexAccess(conn);
} catch (SQLException e) { } catch (SQLException e) {
throw convertException(e); throw convertException(e);
} }
...@@ -140,7 +150,7 @@ public class FullTextLucene extends FullText { ...@@ -140,7 +150,7 @@ public class FullTextLucene extends FullText {
removeAllTriggers(conn, TRIGGER_PREFIX); removeAllTriggers(conn, TRIGGER_PREFIX);
removeIndexFiles(conn); removeIndexFiles(conn);
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM "+SCHEMA+".INDEXES"); ResultSet rs = stat.executeQuery("SELECT * FROM " + SCHEMA + ".INDEXES");
while (rs.next()) { while (rs.next()) {
String schema = rs.getString("SCHEMA"); String schema = rs.getString("SCHEMA");
String table = rs.getString("TABLE"); String table = rs.getString("TABLE");
...@@ -247,28 +257,43 @@ public class FullTextLucene extends FullText { ...@@ -247,28 +257,43 @@ public class FullTextLucene extends FullText {
} }
/** /**
* Get the index modifier for the given connection. * Get the index writer/searcher wrapper for the given connection.
* *
* @param conn the connection * @param conn the connection
* @return the index modifier * @return the index access wrapper
*/ */
protected static IndexModifier getIndexModifier(Connection conn) throws SQLException { protected static IndexAccess getIndexAccess(Connection conn) throws SQLException {
String path = getIndexPath(conn); String path = getIndexPath(conn);
IndexModifier indexer; synchronized (INDEX_ACCESS) {
synchronized (INDEX_MODIFIERS) { IndexAccess access = INDEX_ACCESS.get(path);
indexer = INDEX_MODIFIERS.get(path); if (access == null) {
if (indexer == null) {
try { try {
//## LUCENE2 begin ##
boolean recreate = !IndexReader.indexExists(path); boolean recreate = !IndexReader.indexExists(path);
Analyzer analyzer = new StandardAnalyzer(); Analyzer analyzer = new StandardAnalyzer();
indexer = new IndexModifier(path, analyzer, recreate); access = new IndexAccess();
access.modifier = new IndexModifier(path, analyzer, recreate);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
File f = new File(path);
Directory indexDir = FSDirectory.open(f);
boolean recreate = !IndexReader.indexExists(indexDir);
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter writer = new IndexWriter(indexDir, analyzer,
recreate, IndexWriter.MaxFieldLength.UNLIMITED);
//see http://wiki.apache.org/lucene-java/NearRealtimeSearch
IndexReader reader = writer.getReader();
access = new IndexAccess();
access.writer = writer;
access.searcher = new IndexSearcher(reader);
//## LUCENE3 end ##*/
} catch (IOException e) { } catch (IOException e) {
throw convertException(e); throw convertException(e);
} }
INDEX_MODIFIERS.put(path, indexer); INDEX_ACCESS.put(path, access);
} }
return access;
} }
return indexer;
} }
/** /**
...@@ -318,25 +343,31 @@ public class FullTextLucene extends FullText { ...@@ -318,25 +343,31 @@ public class FullTextLucene extends FullText {
private static void removeIndexFiles(Connection conn) throws SQLException { private static void removeIndexFiles(Connection conn) throws SQLException {
String path = getIndexPath(conn); String path = getIndexPath(conn);
IndexModifier index = INDEX_MODIFIERS.get(path); IndexAccess access = INDEX_ACCESS.get(path);
if (index != null) { if (access != null) {
removeIndexModifier(index, path); removeIndexAccess(access, path);
} }
FileSystem.getInstance(path).deleteRecursive(path, false); FileSystem.getInstance(path).deleteRecursive(path, false);
} }
/** /**
* Close the index modifier and remove it from the index modifier set. * Close the index writer and searcher and remove them from the index access set.
* *
* @param indexModifier the index modifier * @param access the index writer/searcher wrapper
* @param indexPath the index path * @param indexPath the index path
*/ */
protected static void removeIndexModifier(IndexModifier indexModifier, String indexPath) throws SQLException { protected static void removeIndexAccess(IndexAccess access, String indexPath) throws SQLException {
synchronized (INDEX_MODIFIERS) { synchronized (INDEX_ACCESS) {
try { try {
INDEX_MODIFIERS.remove(indexPath); INDEX_ACCESS.remove(indexPath);
indexModifier.flush(); //## LUCENE2 begin ##
indexModifier.close(); access.modifier.flush();
access.modifier.close();
//## LUCENE2 end ##
/*## LUCENE3 begin ##
access.searcher.close();
access.writer.close();
//## LUCENE3 end ##*/
} catch (Exception e) { } catch (Exception e) {
throw convertException(e); throw convertException(e);
} }
...@@ -362,10 +393,11 @@ public class FullTextLucene extends FullText { ...@@ -362,10 +393,11 @@ public class FullTextLucene extends FullText {
if (text == null || text.trim().length() == 0) { if (text == null || text.trim().length() == 0) {
return result; return result;
} }
String path = getIndexPath(conn);
try { try {
IndexModifier indexer = getIndexModifier(conn); IndexAccess access = getIndexAccess(conn);
indexer.flush(); //## LUCENE2 begin ##
access.modifier.flush();
String path = getIndexPath(conn);
IndexReader reader = IndexReader.open(path); IndexReader reader = IndexReader.open(path);
Analyzer analyzer = new StandardAnalyzer(); Analyzer analyzer = new StandardAnalyzer();
Searcher searcher = new IndexSearcher(reader); Searcher searcher = new IndexSearcher(reader);
...@@ -379,6 +411,31 @@ public class FullTextLucene extends FullText { ...@@ -379,6 +411,31 @@ public class FullTextLucene extends FullText {
for (int i = 0; i < limit && i + offset < max; i++) { for (int i = 0; i < limit && i + offset < max; i++) {
Document doc = hits.doc(i + offset); Document doc = hits.doc(i + offset);
float score = hits.score(i + offset); float score = hits.score(i + offset);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
// take a reference as the searcher may change
Searcher searcher = access.searcher;
// reuse the same analyzer; it's thread-safe;
// also allows subclasses to control the analyzer used.
Analyzer analyzer = access.writer.getAnalyzer();
QueryParser parser = new QueryParser(Version.LUCENE_30,
LUCENE_FIELD_DATA, analyzer);
Query query = parser.parse(text);
// Lucene 3 insists on a hard limit and will not provide
// a total hits value. Take at least 100 which is
// an optimal limit for Lucene as any more
// will trigger writing results to disk.
int maxResults = (limit == 0 ? 100 : limit) + offset;
TopDocs docs = searcher.search(query, maxResults);
if (limit == 0) {
limit = docs.totalHits;
}
for (int i = 0; i < limit && i + offset < docs.totalHits
&& i + offset < docs.scoreDocs.length; i++) {
ScoreDoc sd = docs.scoreDocs[i + offset];
Document doc = searcher.doc(sd.doc);
float score = sd.score;
//## LUCENE3 end ##*/
String q = doc.get(LUCENE_FIELD_QUERY); String q = doc.get(LUCENE_FIELD_QUERY);
if (data) { if (data) {
int idx = q.indexOf(" WHERE "); int idx = q.indexOf(" WHERE ");
...@@ -401,8 +458,10 @@ public class FullTextLucene extends FullText { ...@@ -401,8 +458,10 @@ public class FullTextLucene extends FullText {
result.addRow(q, score); result.addRow(q, score);
} }
} }
//## LUCENE2 begin ##
// TODO keep it open if possible // TODO keep it open if possible
reader.close(); reader.close();
//## LUCENE2 end ##
} catch (Exception e) { } catch (Exception e) {
throw convertException(e); throw convertException(e);
} }
...@@ -427,7 +486,7 @@ public class FullTextLucene extends FullText { ...@@ -427,7 +486,7 @@ public class FullTextLucene extends FullText {
protected String[] columns; protected String[] columns;
protected int[] columnTypes; protected int[] columnTypes;
protected String indexPath; protected String indexPath;
protected IndexModifier indexModifier; protected IndexAccess indexAccess;
//## Java 1.4 end ## //## Java 1.4 end ##
/** /**
...@@ -439,7 +498,7 @@ public class FullTextLucene extends FullText { ...@@ -439,7 +498,7 @@ public class FullTextLucene extends FullText {
this.schema = schemaName; this.schema = schemaName;
this.table = tableName; this.table = tableName;
this.indexPath = getIndexPath(conn); this.indexPath = getIndexPath(conn);
this.indexModifier = getIndexModifier(conn); this.indexAccess = getIndexAccess(conn);
ArrayList<String> keyList = New.arrayList(); ArrayList<String> keyList = New.arrayList();
DatabaseMetaData meta = conn.getMetaData(); DatabaseMetaData meta = conn.getMetaData();
ResultSet rs = meta.getColumns(null, ResultSet rs = meta.getColumns(null,
...@@ -525,9 +584,9 @@ public class FullTextLucene extends FullText { ...@@ -525,9 +584,9 @@ public class FullTextLucene extends FullText {
*/ */
//## Java 1.4 begin ## //## Java 1.4 begin ##
public void close() throws SQLException { public void close() throws SQLException {
if (indexModifier != null) { if (indexAccess != null) {
removeIndexModifier(indexModifier, indexPath); removeIndexAccess(indexAccess, indexPath);
indexModifier = null; indexAccess = null;
} }
} }
//## Java 1.4 end ## //## Java 1.4 end ##
...@@ -545,11 +604,15 @@ public class FullTextLucene extends FullText { ...@@ -545,11 +604,15 @@ public class FullTextLucene extends FullText {
* @param row the row * @param row the row
*/ */
protected void insert(Object[] row) throws SQLException { protected void insert(Object[] row) throws SQLException {
//## LUCENE2 begin ##
String query = getQuery(row); String query = getQuery(row);
Document doc = new Document(); Document doc = new Document();
doc.add(new Field(LUCENE_FIELD_QUERY, query, Field.Store.YES, Field.Index.UN_TOKENIZED)); doc.add(new Field(LUCENE_FIELD_QUERY, query,
Field.Store.YES, Field.Index.UN_TOKENIZED));
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
doc.add(new Field(LUCENE_FIELD_MODIFIED, DateTools.timeToString(time, DateTools.Resolution.SECOND), Field.Store.YES, Field.Index.UN_TOKENIZED)); doc.add(new Field(LUCENE_FIELD_MODIFIED,
DateTools.timeToString(time, DateTools.Resolution.SECOND),
Field.Store.YES, Field.Index.UN_TOKENIZED));
StatementBuilder buff = new StatementBuilder(); StatementBuilder buff = new StatementBuilder();
for (int index : indexColumns) { for (int index : indexColumns) {
String columnName = columns[index]; String columnName = columns[index];
...@@ -559,18 +622,59 @@ public class FullTextLucene extends FullText { ...@@ -559,18 +622,59 @@ public class FullTextLucene extends FullText {
if (columnName.startsWith(LUCENE_FIELD_COLUMN_PREFIX)) { if (columnName.startsWith(LUCENE_FIELD_COLUMN_PREFIX)) {
columnName = LUCENE_FIELD_COLUMN_PREFIX + columnName; columnName = LUCENE_FIELD_COLUMN_PREFIX + columnName;
} }
doc.add(new Field(columnName, data, Field.Store.NO, Field.Index.TOKENIZED)); doc.add(new Field(columnName, data,
Field.Store.NO, Field.Index.TOKENIZED));
buff.appendExceptFirst(" "); buff.appendExceptFirst(" ");
buff.append(data); buff.append(data);
} }
Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ? Field.Store.YES : Field.Store.NO; Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ?
Field.Store.YES : Field.Store.NO;
doc.add(new Field(LUCENE_FIELD_DATA, buff.toString(), storeText, doc.add(new Field(LUCENE_FIELD_DATA, buff.toString(), storeText,
Field.Index.TOKENIZED)); Field.Index.TOKENIZED));
try { try {
indexModifier.addDocument(doc); indexAccess.modifier.addDocument(doc);
} catch (IOException e) { } catch (IOException e) {
throw convertException(e); throw convertException(e);
} }
//## LUCENE2 end ##
/*## LUCENE3 begin ##
String query = getQuery(row);
Document doc = new Document();
doc.add(new Field(LUCENE_FIELD_QUERY, query,
Field.Store.YES, Field.Index.NOT_ANALYZED));
long time = System.currentTimeMillis();
doc.add(new Field(LUCENE_FIELD_MODIFIED,
DateTools.timeToString(time, DateTools.Resolution.SECOND),
Field.Store.YES, Field.Index.NOT_ANALYZED));
StatementBuilder buff = new StatementBuilder();
for (int index : indexColumns) {
String columnName = columns[index];
String data = asString(row[index], columnTypes[index]);
// column names that start with _
// must be escaped to avoid conflicts
// with internal field names (_DATA, _QUERY, _modified)
if (columnName.startsWith(LUCENE_FIELD_COLUMN_PREFIX)) {
columnName = LUCENE_FIELD_COLUMN_PREFIX + columnName;
}
doc.add(new Field(columnName, data,
Field.Store.NO, Field.Index.ANALYZED));
buff.appendExceptFirst(" ");
buff.append(data);
}
Field.Store storeText = STORE_DOCUMENT_TEXT_IN_INDEX ?
Field.Store.YES : Field.Store.NO;
doc.add(new Field(LUCENE_FIELD_DATA, buff.toString(), storeText,
Field.Index.ANALYZED));
try {
indexAccess.writer.addDocument(doc);
indexAccess.writer.commit();
//Recreate Searcher with the IndexWriter's reader.
IndexReader reader = indexAccess.writer.getReader();
indexAccess.searcher = new IndexSearcher(reader);
} catch (IOException e) {
throw convertException(e);
}
//## LUCENE3 end ##*/
} }
/** /**
...@@ -582,7 +686,12 @@ public class FullTextLucene extends FullText { ...@@ -582,7 +686,12 @@ public class FullTextLucene extends FullText {
String query = getQuery(row); String query = getQuery(row);
try { try {
Term term = new Term(LUCENE_FIELD_QUERY, query); Term term = new Term(LUCENE_FIELD_QUERY, query);
indexModifier.deleteDocuments(term); //## LUCENE2 begin ##
indexAccess.modifier.deleteDocuments(term);
//## LUCENE2 end ##
/*## LUCENE3 begin ##
indexAccess.writer.deleteDocuments(term);
//## LUCENE3 end ##*/
} catch (IOException e) { } catch (IOException e) {
throw convertException(e); throw convertException(e);
} }
...@@ -608,4 +717,31 @@ public class FullTextLucene extends FullText { ...@@ -608,4 +717,31 @@ public class FullTextLucene extends FullText {
} }
} }
/**
* A wrapper for the Lucene writer and searcher.
*/
static class IndexAccess {
/**
* The index modified.
*/
//## LUCENE2 begin ##
IndexModifier modifier;
//## LUCENE2 end ##
/**
* The index writer.
*/
/*## LUCENE3 begin ##
IndexWriter writer;
//## LUCENE3 end ##*/
/**
* The index searcher.
*/
/*## LUCENE3 begin ##
Searcher searcher;
//## LUCENE3 end ##*/
}
} }
...@@ -23,6 +23,11 @@ import org.h2.test.TestBase; ...@@ -23,6 +23,11 @@ import org.h2.test.TestBase;
*/ */
public class TestFullText extends TestBase { public class TestFullText extends TestBase {
/**
* The words used in this test.
*/
static final String[] KNOWN_WORDS = { "skiing", "balance", "storage", "water", "train" };
/** /**
* Run just this test. * Run just this test.
* *
...@@ -38,7 +43,8 @@ public class TestFullText extends TestBase { ...@@ -38,7 +43,8 @@ public class TestFullText extends TestBase {
if (config.memory) { if (config.memory) {
return; return;
} }
testMultiThreaded(); testMultiThreaded(true);
testMultiThreaded(false);
testStreamLob(); testStreamLob();
test(false, "VARCHAR"); test(false, "VARCHAR");
test(false, "CLOB"); test(false, "CLOB");
...@@ -79,6 +85,8 @@ public class TestFullText extends TestBase { ...@@ -79,6 +85,8 @@ public class TestFullText extends TestBase {
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)"); stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello World')"); stat.execute("INSERT INTO TEST VALUES(1, 'Hello World')");
stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', 'TEST', NULL)"); stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', 'TEST', NULL)");
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
assertTrue(rs.next());
stat.execute("UPDATE TEST SET NAME=NULL WHERE ID=1"); stat.execute("UPDATE TEST SET NAME=NULL WHERE ID=1");
stat.execute("UPDATE TEST SET NAME='Hello World' WHERE ID=1"); stat.execute("UPDATE TEST SET NAME='Hello World' WHERE ID=1");
conn.setAutoCommit(false); conn.setAutoCommit(false);
...@@ -87,7 +95,7 @@ public class TestFullText extends TestBase { ...@@ -87,7 +95,7 @@ public class TestFullText extends TestBase {
conn.close(); conn.close();
conn = getConnection("fullTextTransaction"); conn = getConnection("fullTextTransaction");
stat = conn.createStatement(); stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)"); rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
assertTrue(rs.next()); assertTrue(rs.next());
rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Moon', 0, 0)"); rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Moon', 0, 0)");
assertFalse(rs.next()); assertFalse(rs.next());
...@@ -97,7 +105,9 @@ public class TestFullText extends TestBase { ...@@ -97,7 +105,9 @@ public class TestFullText extends TestBase {
FileSystem.getInstance(getBaseDir()).deleteRecursive(getBaseDir() + "/fullTextTransaction", false); FileSystem.getInstance(getBaseDir()).deleteRecursive(getBaseDir() + "/fullTextTransaction", false);
} }
private void testMultiThreaded() throws Exception { private void testMultiThreaded(boolean lucene) throws Exception {
final String prefix = lucene ? "FTL" : "FT";
trace("Testing multithreaded " + prefix);
deleteDb("fullText"); deleteDb("fullText");
final boolean[] stop = { false }; final boolean[] stop = { false };
final Exception[] exception = { null }; final Exception[] exception = { null };
...@@ -108,49 +118,67 @@ public class TestFullText extends TestBase { ...@@ -108,49 +118,67 @@ public class TestFullText extends TestBase {
// getConnection("fullText;MULTI_THREADED=1;LOCK_TIMEOUT=10000"); // getConnection("fullText;MULTI_THREADED=1;LOCK_TIMEOUT=10000");
final Connection conn = getConnection("fullText"); final Connection conn = getConnection("fullText");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\""); String className = lucene ? "FullTextLucene" : "FullText";
stat.execute("CALL FT_INIT()"); stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\""); stat.execute("CALL " + prefix + "_INIT()");
stat.execute("CALL FT_INIT()"); stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
stat.execute("CALL " + prefix + "_INIT()");
final String tableName = "TEST" + i; final String tableName = "TEST" + i;
stat.execute("CREATE TABLE " + tableName + "(ID INT PRIMARY KEY, DATA VARCHAR)"); stat.execute("CREATE TABLE " + tableName + "(ID INT PRIMARY KEY, DATA VARCHAR)");
FullText.createIndex(conn, "PUBLIC", tableName, null); stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', '" + tableName + "', NULL)");
threads[i] = new Thread() { threads[i] = new Thread() {
public void run() { public void run() {
trace("starting thread " + Thread.currentThread());
try { try {
PreparedStatement prep = conn.prepareStatement("INSERT INTO " + tableName + " VALUES(?, ?)"); PreparedStatement prep = conn.prepareStatement("INSERT INTO " + tableName + " VALUES(?, ?)");
Statement stat = conn.createStatement();
Random random = new Random(); Random random = new Random();
int x = 0; int x = 0;
while (!stop[0]) { while (!stop[0]) {
trace("stop[0] = " + stop[0] + " for " + Thread.currentThread());
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
for (int j = 0; j < 1000; j++) { for (int j = 0; j < 1000; j++) {
buff.append(" " + random.nextInt(10000)); buff.append(" ").append(random.nextInt(10000));
buff.append(" x" + j); buff.append(" x").append(j);
buff.append(" ").append(KNOWN_WORDS[j % KNOWN_WORDS.length]);
} }
prep.setInt(1, x); prep.setInt(1, x);
prep.setString(2, buff.toString()); prep.setString(2, buff.toString());
prep.execute(); prep.execute();
x++; x++;
for (String knownWord : KNOWN_WORDS) {
trace("searching for " + knownWord + " with " + Thread.currentThread());
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('" + knownWord + "', 0, 0)");
assertTrue(rs.next());
}
} }
trace("closing connection");
conn.close(); conn.close();
} catch (SQLException e) { } catch (SQLException e) {
exception[0] = e; exception[0] = e;
} finally {
trace("completed thread " + Thread.currentThread());
} }
} }
}; };
} }
for (Thread t : threads) { for (Thread t : threads) {
t.setDaemon(true);
t.start(); t.start();
} }
trace("sleeping");
Thread.sleep(1000); Thread.sleep(1000);
trace("setting stop to true");
stop[0] = true; stop[0] = true;
for (Thread t : threads) { for (Thread t : threads) {
trace("joining " + t);
t.join(); t.join();
trace("done joining " + t);
} }
if (exception[0] != null) { if (exception[0] != null) {
throw exception[0]; throw exception[0];
} }
} }
private void testStreamLob() throws SQLException { private void testStreamLob() throws SQLException {
...@@ -374,8 +402,6 @@ public class TestFullText extends TestBase { ...@@ -374,8 +402,6 @@ public class TestFullText extends TestBase {
stat = conn.createStatement(); stat = conn.createStatement();
rs = stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 0, 0)"); rs = stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 0, 0)");
stat.execute("CALL " + prefix + "DROP_ALL()");
stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('World', 2, 1)");
stat.execute("CALL " + prefix + "DROP_ALL()"); stat.execute("CALL " + prefix + "DROP_ALL()");
conn.close(); conn.close();
......
...@@ -105,7 +105,7 @@ public class Build extends BuildBase { ...@@ -105,7 +105,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/emma-2.0.5312.jar" + File.pathSeparator + "ext/emma-2.0.5312.jar" +
File.pathSeparator + "ext/postgresql-8.3-603.jdbc3.jar" + File.pathSeparator + "ext/postgresql-8.3-603.jdbc3.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" + File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar"; File.pathSeparator + "ext/slf4j-api-1.5.0.jar";
exec("java", args("-Xmx128m", "-cp", cp, "emma", "run", exec("java", args("-Xmx128m", "-cp", cp, "emma", "run",
...@@ -127,6 +127,9 @@ public class Build extends BuildBase { ...@@ -127,6 +127,9 @@ public class Build extends BuildBase {
} else { } else {
SwitchSource.main("-dir", "src", "-version", version); SwitchSource.main("-dir", "src", "-version", version);
} }
if (System.getProperty("lucene") != null) {
SwitchSource.main("-dir", "src", "-LUCENE2", "-LUCENE3", "+LUCENE" + getLuceneVersion());
}
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
...@@ -139,7 +142,7 @@ public class Build extends BuildBase { ...@@ -139,7 +142,7 @@ public class Build extends BuildBase {
download(); download();
String classpath = "temp" + String classpath = "temp" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" + File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" + File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" +
File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar"; File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar";
...@@ -218,9 +221,15 @@ public class Build extends BuildBase { ...@@ -218,9 +221,15 @@ public class Build extends BuildBase {
download("ext/servlet-api-2.4.jar", download("ext/servlet-api-2.4.jar",
"http://repo1.maven.org/maven2/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar", "http://repo1.maven.org/maven2/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar",
"3fc542fe8bb8164e8d3e840fe7403bc0518053c0"); "3fc542fe8bb8164e8d3e840fe7403bc0518053c0");
download("ext/lucene-core-2.2.0.jar", if (getLuceneVersion() == 3) {
"http://repo1.maven.org/maven2/org/apache/lucene/lucene-core/2.2.0/lucene-core-2.2.0.jar", download("ext/lucene-core-3.0.2.jar",
"47b6eee2e17bd68911e7045896a1c09de0b2dda8"); "http://repo1.maven.org/maven2/org/apache/lucene/lucene-core/3.0.2/lucene-core-3.0.2.jar",
"c2b48995ab855c1b9ea13867a0f976c994e0105d");
} else {
download("ext/lucene-core-2.2.0.jar",
"http://repo1.maven.org/maven2/org/apache/lucene/lucene-core/2.2.0/lucene-core-2.2.0.jar",
"47b6eee2e17bd68911e7045896a1c09de0b2dda8");
}
download("ext/slf4j-api-1.5.0.jar", download("ext/slf4j-api-1.5.0.jar",
"http://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.5.0/slf4j-api-1.5.0.jar", "http://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.5.0/slf4j-api-1.5.0.jar",
"b2df265d02350ecfe87b6c1773c7c4fab2b33505"); "b2df265d02350ecfe87b6c1773c7c4fab2b33505");
...@@ -240,6 +249,14 @@ public class Build extends BuildBase { ...@@ -240,6 +249,14 @@ public class Build extends BuildBase {
return getStaticValue("org.h2.engine.Constants", "getVersion"); return getStaticValue("org.h2.engine.Constants", "getVersion");
} }
private String getLuceneJar() {
return "lucene-core-" + (getLuceneVersion() == 2 ? "2.2.0" : "3.0.2") + ".jar";
}
private int getLuceneVersion() {
return Integer.parseInt(System.getProperty("lucene", "2"));
}
private String getJarSuffix() { private String getJarSuffix() {
return "-" + getVersion() + ".jar"; return "-" + getVersion() + ".jar";
} }
...@@ -382,7 +399,7 @@ public class Build extends BuildBase { ...@@ -382,7 +399,7 @@ public class Build extends BuildBase {
mkdir("docs/javadoc"); mkdir("docs/javadoc");
javadoc("-sourcepath", "src/main", "org.h2.jdbc", "org.h2.jdbcx", javadoc("-sourcepath", "src/main", "org.h2.jdbc", "org.h2.jdbcx",
"org.h2.tools", "org.h2.api", "org.h2.constant", "org.h2.fulltext", "org.h2.tools", "org.h2.api", "org.h2.constant", "org.h2.fulltext",
"-classpath", "ext/lucene-core-2.2.0.jar", "-classpath", "ext/" + getLuceneJar(),
"-docletpath", "bin" + File.pathSeparator + "temp", "-docletpath", "bin" + File.pathSeparator + "temp",
"-doclet", "org.h2.build.doclet.Doclet"); "-doclet", "org.h2.build.doclet.Doclet");
copy("docs/javadoc", files("src/docsrc/javadoc"), "src/docsrc/javadoc"); copy("docs/javadoc", files("src/docsrc/javadoc"), "src/docsrc/javadoc");
...@@ -402,7 +419,7 @@ public class Build extends BuildBase { ...@@ -402,7 +419,7 @@ public class Build extends BuildBase {
"/../lib/tools.jar" + "/../lib/tools.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" + File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar", File.pathSeparator + "ext/org.osgi.core-1.2.0.jar",
"-subpackages", "org.h2", "-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu"); "-exclude", "org.h2.test.jaqu:org.h2.jaqu");
...@@ -412,7 +429,7 @@ public class Build extends BuildBase { ...@@ -412,7 +429,7 @@ public class Build extends BuildBase {
"-classpath", System.getProperty("java.home") + "/../lib/tools.jar" + "-classpath", System.getProperty("java.home") + "/../lib/tools.jar" +
File.pathSeparator + "ext/slf4j-api-1.5.0.jar" + File.pathSeparator + "ext/slf4j-api-1.5.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/lucene-core-2.2.0.jar" + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar", File.pathSeparator + "ext/org.osgi.core-1.2.0.jar",
"-subpackages", "org.h2", "-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu", "-exclude", "org.h2.test.jaqu:org.h2.jaqu",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论