mirror of
https://github.com/querydsl/querydsl.git
synced 2026-07-03 21:07:49 +08:00
Initial LuceneSession with callbacks
This commit is contained in:
parent
12d068c5eb
commit
af6f9df171
@ -18,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.mysema.query.lucene.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
|
||||
/**
|
||||
* General interface on using Lucene.
|
||||
*
|
||||
* @author laimw
|
||||
*/
|
||||
public interface LuceneSession {
|
||||
|
||||
/**
|
||||
* Lucene query callback for querying
|
||||
*
|
||||
* @param clazz
|
||||
* @param callback
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws CorruptIndexException
|
||||
*/
|
||||
<T> T query(QueryCallback<T> callback) throws CorruptIndexException, IOException;
|
||||
|
||||
/**
|
||||
* Creates a new index, adds updates to it and publishes the new index to
|
||||
* all readers after callback finishes.
|
||||
*
|
||||
* @param callback
|
||||
* @throws IOException
|
||||
*/
|
||||
void updateNew(WriteCallback callback) throws IOException;
|
||||
|
||||
/**
|
||||
* Updates the current index and publishes it to all readers after callback
|
||||
* finishes.
|
||||
*
|
||||
* @param callback
|
||||
* @throws IOException
|
||||
*/
|
||||
void update(WriteCallback callback) throws IOException;
|
||||
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
package com.mysema.query.lucene.session;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.SimpleFSDirectory;
|
||||
import org.apache.lucene.util.Version;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.mysema.query.lucene.LuceneQuery;
|
||||
import com.mysema.query.lucene.LuceneSerializer;
|
||||
|
||||
/**
|
||||
* Lucene session implementation for single dto per index.
|
||||
*
|
||||
* @author laimw
|
||||
*
|
||||
*/
|
||||
public class LuceneSessionImpl implements LuceneSession {
|
||||
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LuceneSessionImpl.class);
|
||||
|
||||
private Directory directory;
|
||||
|
||||
private final AtomicReference<IndexSearcher> searcher = new AtomicReference<IndexSearcher>();
|
||||
|
||||
private LuceneSerializer serializer = new LuceneSerializer(true, true);
|
||||
|
||||
public LuceneSessionImpl(String indexPath) throws IOException {
|
||||
File folder = new File(indexPath);
|
||||
if (!folder.exists() && !folder.mkdirs()) {
|
||||
throw new IOException("Could not create directory: " + folder.getAbsolutePath());
|
||||
}
|
||||
|
||||
try {
|
||||
directory = new SimpleFSDirectory(folder);
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not create lucene directory to " + folder.getAbsolutePath());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public LuceneSessionImpl(Directory directory) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T query(QueryCallback<T> callback) throws CorruptIndexException, IOException {
|
||||
|
||||
IndexSearcher is = getSearcher();
|
||||
T results = null;
|
||||
try {
|
||||
// Incrementing the reference count
|
||||
is.getIndexReader().incRef();
|
||||
results = callback.query(new LuceneQuery(serializer, is));
|
||||
|
||||
} finally {
|
||||
// Releasing the reference count
|
||||
// This can be the last to actually close the reader
|
||||
is.getIndexReader().decRef();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private IndexSearcher getSearcher() throws CorruptIndexException, IOException {
|
||||
if (searcher.get() == null) {
|
||||
createNewSearcher(null);
|
||||
}
|
||||
|
||||
// Checking do we need to refresh the reader
|
||||
IndexSearcher is = searcher.get();
|
||||
if (!is.getIndexReader().isCurrent()) {
|
||||
// Underlying index has changed
|
||||
|
||||
// Decreasing the reference counter so that
|
||||
// count can go to zero either here or
|
||||
// when final searcher has done it's job
|
||||
is.getIndexReader().decRef();
|
||||
|
||||
createNewSearcher(is);
|
||||
}
|
||||
|
||||
return searcher.get();
|
||||
}
|
||||
|
||||
private IndexSearcher createNewSearcher(IndexSearcher expected) throws IOException {
|
||||
IndexSearcher is = new IndexSearcher(directory);
|
||||
if (!searcher.compareAndSet(expected, is)) {
|
||||
// Some thread already created a new one so just close this
|
||||
is.close();
|
||||
} else {
|
||||
// Incrementing the reference count first time
|
||||
// We want to keep using the same reader until the index is changed
|
||||
is.getIndexReader().incRef();
|
||||
}
|
||||
return searcher.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNew(WriteCallback callback) throws IOException {
|
||||
update(callback, true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(WriteCallback callback) throws IOException {
|
||||
update(callback, false);
|
||||
}
|
||||
|
||||
private void update(WriteCallback callback, boolean create) throws IOException {
|
||||
IndexWriter writer =
|
||||
new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_CURRENT), create,
|
||||
MaxFieldLength.LIMITED);
|
||||
|
||||
try {
|
||||
callback.write(writer);
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Writer close failed", e);
|
||||
try {
|
||||
if (IndexWriter.isLocked(directory)) {
|
||||
IndexWriter.unlock(directory);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
logger.error("Lock release failed", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.mysema.query.lucene.session;
|
||||
|
||||
import com.mysema.query.lucene.LuceneQuery;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author laimw
|
||||
*
|
||||
*/
|
||||
public interface QueryCallback<T> {
|
||||
T query(LuceneQuery query);
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.mysema.query.lucene.session;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
|
||||
/**
|
||||
* Callback which has Lucene Writer instance.
|
||||
*
|
||||
* @author laimw
|
||||
*
|
||||
*/
|
||||
public interface WriteCallback {
|
||||
|
||||
void write(IndexWriter writer) throws CorruptIndexException, IOException;
|
||||
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
package com.mysema.query.lucene.session;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Field.Index;
|
||||
import org.apache.lucene.document.Field.Store;
|
||||
import org.apache.lucene.document.NumericField;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.RAMDirectory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mysema.query.lucene.LuceneQuery;
|
||||
import com.mysema.query.lucene.LuceneSerializer;
|
||||
import com.mysema.query.types.PathMetadataFactory;
|
||||
import com.mysema.query.types.path.EntityPathBase;
|
||||
import com.mysema.query.types.path.NumberPath;
|
||||
import com.mysema.query.types.path.StringPath;
|
||||
|
||||
public class LuceneSessionImplTest {
|
||||
|
||||
public class QDocument extends EntityPathBase<Document> {
|
||||
|
||||
private static final long serialVersionUID = -4872833626508344081L;
|
||||
|
||||
public QDocument(final String var) {
|
||||
super(Document.class, PathMetadataFactory.forVariable(var));
|
||||
}
|
||||
|
||||
public final NumberPath<Integer> year = createNumber("year", Integer.class);
|
||||
|
||||
public final StringPath title = createString("title");
|
||||
|
||||
public final NumberPath<Double> gross = createNumber("gross", Double.class);
|
||||
}
|
||||
|
||||
private LuceneSession session;
|
||||
|
||||
private Directory directory;
|
||||
|
||||
private StringPath title;
|
||||
|
||||
private NumberPath<Integer> year;
|
||||
|
||||
private NumberPath<Double> gross;
|
||||
|
||||
@Before
|
||||
public void before() throws IOException {
|
||||
directory = new RAMDirectory();
|
||||
session = new LuceneSessionImpl(directory);
|
||||
final QDocument entityPath = new QDocument("doc");
|
||||
title = entityPath.title;
|
||||
year = entityPath.year;
|
||||
gross = entityPath.gross;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate() throws IOException {
|
||||
|
||||
session.updateNew(new WriteCallback() {
|
||||
public void write(IndexWriter writer) throws CorruptIndexException, IOException {
|
||||
|
||||
writer.addDocument(createDocument(
|
||||
"Jurassic Park",
|
||||
"Michael Crichton",
|
||||
"It's a UNIX system! I know this!",
|
||||
1990,
|
||||
90.00));
|
||||
writer.addDocument(createDocument(
|
||||
"Nummisuutarit",
|
||||
"Aleksis Kivi",
|
||||
"ESKO. Ja iloitset ja riemuitset?",
|
||||
1864,
|
||||
10.00));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
List<Document> results = session.query(new QueryCallback<List<Document>>() {
|
||||
public List<Document> query(LuceneQuery query) {
|
||||
|
||||
return query.where(title.eq("Jurassic Park")).list();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(1, results.size());
|
||||
assertEquals("Jurassic Park", results.get(0).getField("title").stringValue());
|
||||
|
||||
Long count = session.query(new QueryCallback<Long>() {
|
||||
public Long query(LuceneQuery query) {
|
||||
|
||||
//TODO Tästä tulee 0 eikä 2!!
|
||||
//return query.where(title.ne("AA")).count();
|
||||
|
||||
return query.where(title.startsWith("Nummi")).count();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(1, (long) count);
|
||||
}
|
||||
|
||||
private Document createDocument(
|
||||
final String docTitle,
|
||||
final String docAuthor,
|
||||
final String docText,
|
||||
final int docYear,
|
||||
final double docGross) {
|
||||
final Document doc = new Document();
|
||||
|
||||
doc.add(new Field("title", docTitle, Store.YES, Index.ANALYZED));
|
||||
doc.add(new Field("author", docAuthor, Store.YES, Index.ANALYZED));
|
||||
doc.add(new Field("text", docText, Store.YES, Index.ANALYZED));
|
||||
doc.add(new NumericField("year", Store.YES, true).setIntValue(docYear));
|
||||
doc.add(new NumericField("gross", Store.YES, true).setDoubleValue(docGross));
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user