mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-21 21:14:12 +08:00
Implemented LuceneQuery.list, LuceneQuery.uniqueResult and LuceneQuery.count, created tests for these as well.
This commit is contained in:
parent
9a1cb7bc00
commit
845b7dd5d4
@ -1,13 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Mysema Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package com.mysema.query.search;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.Searcher;
|
||||
import org.apache.lucene.search.Sort;
|
||||
import org.apache.lucene.search.SortField;
|
||||
|
||||
import com.mysema.query.QueryException;
|
||||
import com.mysema.query.QueryModifiers;
|
||||
import com.mysema.query.SearchResults;
|
||||
import com.mysema.query.SimpleProjectable;
|
||||
import com.mysema.query.SimpleQuery;
|
||||
import com.mysema.query.support.QueryMixin;
|
||||
@ -18,47 +30,148 @@ import com.mysema.query.types.expr.EBoolean;
|
||||
/**
|
||||
* @author tiwe
|
||||
*
|
||||
* @param <T>
|
||||
* @param <Document>
|
||||
*/
|
||||
public abstract class LuceneQuery<T> implements SimpleQuery<LuceneQuery<T>>, SimpleProjectable<T>{
|
||||
|
||||
private final Path<?> entityPath;
|
||||
|
||||
private final QueryMixin<LuceneQuery<T>> queryMixin;
|
||||
|
||||
private final Session session;
|
||||
|
||||
public LuceneQuery(Session session, Path<?> entityPath) {
|
||||
this.session = session;
|
||||
this.entityPath = entityPath;
|
||||
this.queryMixin = new QueryMixin<LuceneQuery<T>>(this);
|
||||
public class LuceneQuery implements SimpleQuery<LuceneQuery>, SimpleProjectable<Document>{
|
||||
|
||||
// private final Path<?> entityPath;
|
||||
|
||||
private final QueryMixin<LuceneQuery> queryMixin;
|
||||
|
||||
private final LuceneSerializer serializer;
|
||||
|
||||
private final Searcher searcher;
|
||||
|
||||
// TODO Is there an alternative for this?
|
||||
private static final int MAX_RESULT_COUNT = 30000;
|
||||
|
||||
public LuceneQuery(Path<?> entityPath, LuceneSerializer serializer, Searcher searcher) {
|
||||
// this.entityPath = entityPath;
|
||||
this.queryMixin = new QueryMixin<LuceneQuery>(this);
|
||||
this.serializer = serializer;
|
||||
this.searcher = searcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuceneQuery<T> limit(long limit) {
|
||||
public LuceneQuery limit(long limit) {
|
||||
return queryMixin.limit(limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuceneQuery<T> offset(long offset) {
|
||||
public LuceneQuery offset(long offset) {
|
||||
return queryMixin.offset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuceneQuery<T> orderBy(OrderSpecifier<?>... o) {
|
||||
public LuceneQuery orderBy(OrderSpecifier<?>... o) {
|
||||
return queryMixin.orderBy(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuceneQuery<T> restrict(QueryModifiers modifiers) {
|
||||
public LuceneQuery restrict(QueryModifiers modifiers) {
|
||||
return queryMixin.restrict(modifiers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LuceneQuery<T> where(EBoolean... e) {
|
||||
public LuceneQuery where(EBoolean... e) {
|
||||
return queryMixin.where(e);
|
||||
}
|
||||
|
||||
// TODO : implementations of Projectable methods
|
||||
|
||||
private Query createQuery() {
|
||||
return serializer.toQuery(queryMixin.getMetadata().getWhere());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
try {
|
||||
return searcher.search(createQuery(), MAX_RESULT_COUNT).totalHits;
|
||||
} catch (IOException e) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countDistinct() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> list() {
|
||||
List<OrderSpecifier<?>> orderBys = queryMixin.getMetadata().getOrderBy();
|
||||
if (!orderBys.isEmpty()) {
|
||||
return listSorted(orderBys);
|
||||
}
|
||||
|
||||
List<Document> documents = new ArrayList<Document>();
|
||||
try {
|
||||
ScoreDoc[] scoreDocs = searcher.search(createQuery(), MAX_RESULT_COUNT).scoreDocs;
|
||||
for (ScoreDoc scoreDoc : scoreDocs) {
|
||||
documents.add(searcher.doc(scoreDoc.doc));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO ?
|
||||
}
|
||||
return documents;
|
||||
}
|
||||
|
||||
private List<Document> listSorted(List<OrderSpecifier<?>> orderBys) {
|
||||
List<Document> documents = new ArrayList<Document>();
|
||||
List<SortField> sortFields = new ArrayList<SortField>();
|
||||
for (OrderSpecifier<?> orderSpecifier : orderBys) {
|
||||
if (!(orderSpecifier.getTarget() instanceof Path<?>)) {
|
||||
throw new IllegalArgumentException("argument was not of type Path.");
|
||||
}
|
||||
sortFields.add(new SortField(toField((Path<?>)orderSpecifier.getTarget()), Locale.ENGLISH, !orderSpecifier.isAscending()));
|
||||
}
|
||||
Sort sort = new Sort();
|
||||
sort.setSort(sortFields.toArray(new SortField[sortFields.size()]));
|
||||
try {
|
||||
ScoreDoc[] scoreDocs = searcher.search(createQuery(), null, MAX_RESULT_COUNT, sort).scoreDocs;
|
||||
for (ScoreDoc scoreDoc : scoreDocs) {
|
||||
documents.add(searcher.doc(scoreDoc.doc));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO ?
|
||||
}
|
||||
return documents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> listDistinct() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResults<Document> listDistinctResults() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResults<Document> listResults() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document uniqueResult() {
|
||||
try {
|
||||
ScoreDoc[] scoreDocs = searcher.search(createQuery(), MAX_RESULT_COUNT).scoreDocs;
|
||||
if (scoreDocs.length > 1) {
|
||||
throw new QueryException("More than one result found!");
|
||||
}
|
||||
return searcher.doc(scoreDocs[0].doc);
|
||||
} catch (IOException e) {
|
||||
// TODO ?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String toField(Path<?> path) {
|
||||
return path.getMetadata().getExpression().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,169 @@
|
||||
package com.mysema.query.search;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||
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.index.IndexWriter;
|
||||
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Searcher;
|
||||
import org.apache.lucene.store.RAMDirectory;
|
||||
import org.apache.lucene.util.Version;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mysema.query.QueryException;
|
||||
import com.mysema.query.types.path.PString;
|
||||
import com.mysema.query.types.path.PathBuilder;
|
||||
|
||||
/*
|
||||
* TODO Refactor SimpleTest and LuceneQuery into same test class, lot of the setUp stuff is similar?
|
||||
*/
|
||||
public class LuceneQueryTest {
|
||||
private LuceneQuery query;
|
||||
private PathBuilder<Object> entityPath;
|
||||
private PString title;
|
||||
private PString year;
|
||||
|
||||
private RAMDirectory idx;
|
||||
private IndexWriter writer;
|
||||
private Searcher searcher;
|
||||
|
||||
private Document createDocument(String docTitle, String docAuthor, String docText, String docYear) {
|
||||
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 Field("year", docYear, Store.YES, Index.ANALYZED));
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
entityPath = new PathBuilder<Object>(Object.class, "obj");
|
||||
title = entityPath.getString("title");
|
||||
year = entityPath.getString("year");
|
||||
|
||||
idx = new RAMDirectory();
|
||||
writer = new IndexWriter(idx, new StandardAnalyzer(Version.LUCENE_CURRENT), true, MaxFieldLength.UNLIMITED);
|
||||
|
||||
writer.addDocument(createDocument("Jurassic Park", "Michael Crichton",
|
||||
"It's a UNIX system! I know this!", "1990"));
|
||||
writer.addDocument(createDocument("Nummisuutarit", "Aleksis Kivi",
|
||||
"ESKO. Ja iloitset ja riemuitset?", "1864"));
|
||||
writer.addDocument(createDocument(
|
||||
"The Lord of the Rings",
|
||||
"John R. R. Tolkien",
|
||||
"One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them",
|
||||
"1954"));
|
||||
writer.addDocument(createDocument(
|
||||
"Introduction to Algorithms",
|
||||
"Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein",
|
||||
"Bubble sort",
|
||||
"1990"));
|
||||
|
||||
writer.optimize();
|
||||
writer.close();
|
||||
|
||||
searcher = new IndexSearcher(idx);
|
||||
query = new LuceneQuery(null, new LuceneSerializer(true), searcher);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
searcher.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void count() {
|
||||
query.where(title.eq("Jurassic Park"));
|
||||
assertEquals(1, query.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list() {
|
||||
query.where(year.between("1800", "2000"));
|
||||
query.orderBy(year.asc());
|
||||
List<Document> documents = query.list();
|
||||
assertFalse(documents.isEmpty());
|
||||
assertEquals(4, documents.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list_Sorted_Ascending_By_Year() {
|
||||
query.where(year.between("1800", "2000"));
|
||||
query.orderBy(year.asc());
|
||||
List<Document> documents = query.list();
|
||||
assertFalse(documents.isEmpty());
|
||||
assertEquals(4, documents.size());
|
||||
assertEquals("1864", documents.get(0).get("year"));
|
||||
assertEquals("1954", documents.get(1).get("year"));
|
||||
assertEquals("1990", documents.get(2).get("year"));
|
||||
assertEquals("1990", documents.get(3).get("year"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list_Sorted_Descending_By_Year() {
|
||||
query.where(year.between("1800", "2000"));
|
||||
query.orderBy(year.desc());
|
||||
List<Document> documents = query.list();
|
||||
assertFalse(documents.isEmpty());
|
||||
assertEquals(4, documents.size());
|
||||
assertEquals("1990", documents.get(0).get("year"));
|
||||
assertEquals("1990", documents.get(1).get("year"));
|
||||
assertEquals("1954", documents.get(2).get("year"));
|
||||
assertEquals("1864", documents.get(3).get("year"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list_Sorted_Descending_By_Year_And_Ascending_By_Title() {
|
||||
query.where(year.between("1800", "2000"));
|
||||
query.orderBy(year.desc());
|
||||
query.orderBy(title.asc());
|
||||
List<Document> documents = query.list();
|
||||
assertFalse(documents.isEmpty());
|
||||
assertEquals(4, documents.size());
|
||||
assertEquals("1990", documents.get(0).get("year"));
|
||||
assertEquals("1990", documents.get(1).get("year"));
|
||||
assertEquals("Introduction to Algorithms", documents.get(0).get("title"));
|
||||
assertEquals("Jurassic Park", documents.get(1).get("title"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list_Sorted_Descending_By_Year_And_Descending_By_Title() {
|
||||
query.where(year.between("1800", "2000"));
|
||||
query.orderBy(year.desc());
|
||||
query.orderBy(title.desc());
|
||||
List<Document> documents = query.list();
|
||||
assertFalse(documents.isEmpty());
|
||||
assertEquals(4, documents.size());
|
||||
assertEquals("1990", documents.get(0).get("year"));
|
||||
assertEquals("1990", documents.get(1).get("year"));
|
||||
assertEquals("Jurassic Park", documents.get(0).get("title"));
|
||||
assertEquals("Introduction to Algorithms", documents.get(1).get("title"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uniqueResult() {
|
||||
query.where(title.startsWith("Nummi"));
|
||||
Document document = query.uniqueResult();
|
||||
assertEquals("Nummisuutarit", document.get("title"));
|
||||
}
|
||||
|
||||
@Test(expected = QueryException.class)
|
||||
public void uniqueResult_Finds_More_Than_One_Result() {
|
||||
query.where(year.eq("1990"));
|
||||
query.uniqueResult();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user