提交 9b9a5e9f authored 作者: Thomas Mueller's avatar Thomas Mueller

Lucene fulltext search: the Lucene field names now match the table column names.

上级 5ebbd9a8
...@@ -18,7 +18,10 @@ Change Log ...@@ -18,7 +18,10 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>The shell tool now has a very simple statement history. <ul><li>Lucene fulltext search: the Lucene field names now match the table column names,
except if the column names start with _ (in which case another _ is prepended).
Unfortunately this change means existing fulltext indexes need to be re-built.
</li><li>The shell tool now has a very simple statement history.
</li><li>The zip file system implementation now supports the '~' home directory prefix. </li><li>The zip file system implementation now supports the '~' home directory prefix.
Example database URL: jdbc:h2:zip:~/test.zip!/test Example database URL: jdbc:h2:zip:~/test.zip!/test
</li><li>Right outer joins on tables that were already 'inner joined' was processed incorrectly. </li><li>Right outer joins on tables that were already 'inner joined' was processed incorrectly.
......
...@@ -255,6 +255,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -255,6 +255,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Better document the source code </li><li>Better document the source code
</li><li>Support select * from dual a left join dual b on b.x=(select max(x) from dual) </li><li>Support select * from dual a left join dual b on b.x=(select max(x) from dual)
</li><li>Optimization: don't lock when the database is read-only </li><li>Optimization: don't lock when the database is read-only
</li><li>Issue 146: Support merge join.
</li><li>Integrate spatial functions from http://geosysin.iict.ch/irstv-trac/wiki/H2spatial/Download </li><li>Integrate spatial functions from http://geosysin.iict.ch/irstv-trac/wiki/H2spatial/Download
</li><li>Support COSH, SINH, and TANH functions </li><li>Support COSH, SINH, and TANH functions
</li><li>Oracle: support DECODE method (convert to CASE WHEN). </li><li>Oracle: support DECODE method (convert to CASE WHEN).
...@@ -288,7 +289,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -288,7 +289,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Space reuse: after init, scan all storages and free those that don't belong to a live database object </li><li>Space reuse: after init, scan all storages and free those that don't belong to a live database object
</li><li>Use FilterIn / FilterOut putStream? </li><li>Use FilterIn / FilterOut putStream?
</li><li>Access rights: add missing features (users should be 'owner' of objects; missing rights for sequences; dropping objects) </li><li>Access rights: add missing features (users should be 'owner' of objects; missing rights for sequences; dropping objects)
</li><li>Support NOCACHE table option (Oracle) </li><li>Support NOCACHE table option (Oracle).
</li><li>Support table partitioning. </li><li>Support table partitioning.
</li><li>Index usage for UPDATE ... WHERE .. IN (SELECT...) </li><li>Index usage for UPDATE ... WHERE .. IN (SELECT...)
</li><li>Add regular javadocs (using the default doclet, but another css) to the homepage. </li><li>Add regular javadocs (using the default doclet, but another css) to the homepage.
...@@ -314,7 +315,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -314,7 +315,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>HSQLDB compatibility: automatic data type for SUM if value is the value is too big (by default use the same type as the data). </li><li>HSQLDB compatibility: automatic data type for SUM if value is the value is too big (by default use the same type as the data).
</li><li>Improve the optimizer to select the right index for special cases: where id between 2 and 4 and booleanColumn </li><li>Improve the optimizer to select the right index for special cases: where id between 2 and 4 and booleanColumn
</li><li>Linked tables: make hidden columns available (Oracle: rowid and ora_rowscn columns). </li><li>Linked tables: make hidden columns available (Oracle: rowid and ora_rowscn columns).
</li><li>Support merge join.
</li><li>H2 Console: in-place autocomplete. </li><li>H2 Console: in-place autocomplete.
</li><li>Support large databases: split LOB (BLOB, CLOB) to multiple directories / disks (similar to tablespaces). </li><li>Support large databases: split LOB (BLOB, CLOB) to multiple directories / disks (similar to tablespaces).
</li><li>Support to assign a primary key index a user defined name. </li><li>Support to assign a primary key index a user defined name.
......
...@@ -69,11 +69,6 @@ public class FullText { ...@@ -69,11 +69,6 @@ public class FullText {
*/ */
protected static final String FIELD_KEYS = "KEYS"; protected static final String FIELD_KEYS = "KEYS";
/**
* The column name of the result set returned by the search method.
*/
protected static final String FIELD_QUERY = "QUERY";
/** /**
* The hit score. * The hit score.
*/ */
...@@ -84,6 +79,11 @@ public class FullText { ...@@ -84,6 +79,11 @@ public class FullText {
private static final String SELECT_MAP_BY_WORD_ID = "SELECT ROWID FROM " + SCHEMA + ".MAP WHERE WORDID=?"; private static final String SELECT_MAP_BY_WORD_ID = "SELECT ROWID FROM " + SCHEMA + ".MAP WHERE WORDID=?";
private static final String SELECT_ROW_BY_ID = "SELECT KEY, INDEXID FROM " + SCHEMA + ".ROWS WHERE ID=?"; private static final String SELECT_ROW_BY_ID = "SELECT KEY, INDEXID FROM " + SCHEMA + ".ROWS WHERE ID=?";
/**
* The column name of the result set returned by the search method.
*/
private static final String FIELD_QUERY = "QUERY";
/** /**
* Initializes full text search functionality for this database. This adds * Initializes full text search functionality for this database. This adds
* the following Java functions to the database: * the following Java functions to the database:
......
...@@ -59,8 +59,10 @@ public class FullTextLucene extends FullText { ...@@ -59,8 +59,10 @@ public class FullTextLucene extends FullText {
private static final HashMap<String, IndexModifier> INDEX_MODIFIERS = New.hashMap(); private static final HashMap<String, IndexModifier> INDEX_MODIFIERS = 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 FIELD_DATA = "DATA"; private static final String LUCENE_FIELD_DATA = "_DATA";
private static final String FIELD_COLUMN_PREFIX = "_"; private static final String LUCENE_FIELD_QUERY = "_QUERY";
private static final String LUCENE_FIELD_MODIFIED = "_modified";
private static final String LUCENE_FIELD_COLUMN_PREFIX = "_";
//## Java 1.4 end ## //## Java 1.4 end ##
/** /**
...@@ -361,7 +363,7 @@ public class FullTextLucene extends FullText { ...@@ -361,7 +363,7 @@ public class FullTextLucene extends FullText {
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);
QueryParser parser = new QueryParser(FIELD_DATA, analyzer); QueryParser parser = new QueryParser(LUCENE_FIELD_DATA, analyzer);
Query query = parser.parse(text); Query query = parser.parse(text);
Hits hits = searcher.search(query); Hits hits = searcher.search(query);
int max = hits.length(); int max = hits.length();
...@@ -371,7 +373,7 @@ public class FullTextLucene extends FullText { ...@@ -371,7 +373,7 @@ 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);
String q = doc.get(FIELD_QUERY); String q = doc.get(LUCENE_FIELD_QUERY);
if (data) { if (data) {
int idx = q.indexOf(" WHERE "); int idx = q.indexOf(" WHERE ");
JdbcConnection c = (JdbcConnection) conn; JdbcConnection c = (JdbcConnection) conn;
...@@ -539,19 +541,24 @@ public class FullTextLucene extends FullText { ...@@ -539,19 +541,24 @@ public class FullTextLucene extends FullText {
protected void insert(Object[] row) throws SQLException { protected void insert(Object[] row) throws SQLException {
String query = getQuery(row); String query = getQuery(row);
Document doc = new Document(); Document doc = new Document();
doc.add(new Field(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("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];
String data = asString(row[index], columnTypes[index]); String data = asString(row[index], columnTypes[index]);
doc.add(new Field(FIELD_COLUMN_PREFIX + columnName, data, Field.Store.NO, Field.Index.TOKENIZED)); // 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.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(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); indexModifier.addDocument(doc);
...@@ -568,7 +575,7 @@ public class FullTextLucene extends FullText { ...@@ -568,7 +575,7 @@ public class FullTextLucene extends FullText {
protected void delete(Object[] row) throws SQLException { protected void delete(Object[] row) throws SQLException {
String query = getQuery(row); String query = getQuery(row);
try { try {
Term term = new Term(FIELD_QUERY, query); Term term = new Term(LUCENE_FIELD_QUERY, query);
indexModifier.deleteDocuments(term); indexModifier.deleteDocuments(term);
} catch (IOException e) { } catch (IOException e) {
throw convertException(e); throw convertException(e);
......
...@@ -68,7 +68,8 @@ public class TestFullText extends TestBase { ...@@ -68,7 +68,8 @@ public class TestFullText extends TestBase {
int len = 2; int len = 2;
Thread[] threads = new Thread[len]; Thread[] threads = new Thread[len];
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
// final Connection conn = getConnection("fullText;MULTI_THREADED=1;LOCK_TIMEOUT=10000"); // final Connection conn =
// 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\""); stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\"");
...@@ -307,6 +308,14 @@ public class TestFullText extends TestBase { ...@@ -307,6 +308,14 @@ public class TestFullText extends TestBase {
rs.next(); rs.next();
assertEquals("\"PUBLIC\".\"TEST\" WHERE \"ID\"=1", rs.getString(1)); assertEquals("\"PUBLIC\".\"TEST\" WHERE \"ID\"=1", rs.getString(1));
assertFalse(rs.next()); assertFalse(rs.next());
if (lucene) {
rs = stat.executeQuery("SELECT * FROM " + prefix + "SEARCH('NAME:Hallo', 0, 0)");
rs.next();
assertEquals("\"PUBLIC\".\"TEST\" WHERE \"ID\"=2", rs.getString(1));
assertFalse(rs.next());
}
conn.close(); conn.close();
conn = getConnection("fullText"); conn = getConnection("fullText");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论