Author: epbernard
Date: 2010-05-23 05:11:49 -0400 (Sun, 23 May 2010)
New Revision: 19589
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeMatchingContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeTerminationExcludable.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsRangeQueryBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeMatchingContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/Helper.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/RangeQueryContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/TermQueryContext.java
Removed:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsTermQueryBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermMatchingContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/Month.java
Log:
HSEARCH-414 Add support for range query
Add support for range queries including the special case of below and above
range().onField("property").from(a).exclude().to(b).createQuery()
range().onField("property").above(a).exclude().createQuery()
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -31,6 +31,11 @@
BooleanJunction<BooleanJunction> bool();
/**
+ * find matching elements within a range
+ */
+ RangeContext range();
+
+ /**
* Query matching all documents
* Typically mixed with a boolean query.
*/
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,11 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface RangeContext extends QueryCustomization<RangeContext> {
+ /**
+ * field / property the term query is executed on
+ */
+ RangeMatchingContext onField(String fieldName);
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeMatchingContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeMatchingContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeMatchingContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,34 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface RangeMatchingContext extends
FieldCustomization<RangeMatchingContext> {
+ /**
+ * field / property the term query is executed on
+ */
+ RangeMatchingContext andField(String field);
+
+ //TODO what about numeric range query, I guess we can detect it automatically based on
the field bridge
+ //TODO get info on precisionStepDesc (index time info)
+ //FIXME: Is <T> correct or should we specialize to String and Numeric (or all the
numeric types?
+ <T> FromRangeContext<T> from(T from);
+
+ public interface FromRangeContext<T> {
+ RangeTerminationExcludable to(T to);
+ FromRangeContext<T> exclude();
+ }
+
+ /**
+ * The field value must be below <code>below</code>
+ * You can exclude the value <code>below</code> by calling
<code>.exclude()</code>
+ */
+ RangeTerminationExcludable below(Object below);
+
+ /**
+ * The field value must be above <code>above</code>
+ * You can exclude the value <code>above</code> by calling
<code>.exclude()</code>
+ */
+ RangeTerminationExcludable above(Object above);
+
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeTerminationExcludable.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeTerminationExcludable.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/RangeTerminationExcludable.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,8 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface RangeTerminationExcludable extends
Termination<RangeTerminationExcludable> {
+ RangeTerminationExcludable exclude();
+}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -5,7 +5,6 @@
import org.hibernate.search.SearchFactory;
import org.hibernate.search.query.dsl.v2.FuzzyContext;
-import org.hibernate.search.query.dsl.v2.TermContext;
import org.hibernate.search.query.dsl.v2.TermMatchingContext;
/**
@@ -15,13 +14,13 @@
private final SearchFactory factory;
private final Analyzer queryAnalyzer;
private final QueryCustomizer queryCustomizer;
- private final QueryContext context;
+ private final TermQueryContext context;
public ConnectedFuzzyContext(Analyzer queryAnalyzer, SearchFactory factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
this.queryCustomizer = new QueryCustomizer();
- this.context = new QueryContext( QueryContext.Approximation.FUZZY);
+ this.context = new TermQueryContext( TermQueryContext.Approximation.FUZZY);
}
public TermMatchingContext onField(String field) {
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsRangeQueryBuilder.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsRangeQueryBuilder.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsRangeQueryBuilder.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,82 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.FuzzyQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TermRangeQuery;
+import org.apache.lucene.search.WildcardQuery;
+
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.query.dsl.v2.RangeTerminationExcludable;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ConnectedMultiFieldsRangeQueryBuilder implements RangeTerminationExcludable
{
+ private final RangeQueryContext queryContext;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private final List<FieldContext> fieldContexts;
+
+ public ConnectedMultiFieldsRangeQueryBuilder(RangeQueryContext queryContext, Analyzer
queryAnalyzer, QueryCustomizer queryCustomizer, List<FieldContext> fieldContexts) {
+ this.queryContext = queryContext;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = queryCustomizer;
+ this.fieldContexts = fieldContexts;
+ }
+
+ public RangeTerminationExcludable exclude() {
+ if ( queryContext.getFrom() != null && queryContext.getTo() != null ) {
+ queryContext.setExcludeTo( true );
+ }
+ else if ( queryContext.getFrom() != null ) {
+ queryContext.setExcludeTo( true );
+ }
+ else if ( queryContext.getTo() != null ) {
+ queryContext.setExcludeTo( true );
+ }
+ else {
+ throw new AssertionFailure( "Both from and to clause of a range query are
null" );
+ }
+ return this;
+ }
+
+ public Query createQuery() {
+ final int size = fieldContexts.size();
+ if ( size == 1 ) {
+ return queryCustomizer.setWrappedQuery( createQuery( fieldContexts.get( 0 ) )
).createQuery();
+ }
+ else {
+ BooleanQuery aggregatedFieldsQuery = new BooleanQuery( );
+ for ( FieldContext fieldContext : fieldContexts ) {
+ aggregatedFieldsQuery.add( createQuery( fieldContext ), BooleanClause.Occur.SHOULD
);
+ }
+ return queryCustomizer.setWrappedQuery( aggregatedFieldsQuery ).createQuery();
+ }
+ }
+
+ public Query createQuery(FieldContext fieldContext) {
+ final Query perFieldQuery;
+ final String fieldName = fieldContext.getField();
+ final Object from = queryContext.getFrom();
+ final String lowerTerm = from == null ? null : Helper.getAnalyzedTerm( fieldName, from,
"from", queryAnalyzer );
+ final Object to = queryContext.getTo();
+ final String upperTerm = to == null ? null : Helper.getAnalyzedTerm( fieldName, to,
"to", queryAnalyzer );
+ perFieldQuery = new TermRangeQuery(
+ fieldName,
+ lowerTerm,
+ upperTerm,
+ queryContext.isExcludeFrom(),
+ queryContext.isExcludeTo()
+ );
+ return fieldContext.getFieldCustomizer().setWrappedQuery( perFieldQuery
).createQuery();
+ }
+}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsTermQueryBuilder.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsTermQueryBuilder.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedMultiFieldsTermQueryBuilder.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -1,14 +1,10 @@
package org.hibernate.search.query.dsl.v2.impl;
import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.analysis.tokenattributes.TermAttribute;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
@@ -29,10 +25,10 @@
private final String text;
private final Analyzer queryAnalyzer;
private final QueryCustomizer queryCustomizer;
- private final QueryContext queryContext;
+ private final TermQueryContext queryContext;
private final List<FieldContext> fieldContexts;
- public ConnectedMultiFieldsTermQueryBuilder(QueryContext queryContext,
+ public ConnectedMultiFieldsTermQueryBuilder(TermQueryContext queryContext,
String text,
List<FieldContext> fieldContexts,
QueryCustomizer queryCustomizer,
@@ -80,8 +76,8 @@
}
else {
BooleanQuery booleanQuery = new BooleanQuery();
- for (String term : terms) {
- Query termQuery = createTermQuery(fieldContext, term);
+ for (String localTerm : terms) {
+ Query termQuery = createTermQuery(fieldContext, localTerm);
booleanQuery.add( termQuery, BooleanClause.Occur.SHOULD );
}
perFieldQuery = booleanQuery;
@@ -92,45 +88,34 @@
private Query createTermQuery(FieldContext fieldContext, String term) {
Query query;
+ final String fieldName = fieldContext.getField();
switch ( queryContext.getApproximation() ) {
case EXACT:
- query = new TermQuery( new Term( fieldContext.getField(), term ) );
+ query = new TermQuery( new Term( fieldName, term ) );
break;
case WILDCARD:
- query = new WildcardQuery( new Term( fieldContext.getField(), term ) );
+ query = new WildcardQuery( new Term( fieldName, term ) );
break;
case FUZZY:
query = new FuzzyQuery(
- new Term( fieldContext.getField(), term ),
+ new Term( fieldName, term ),
queryContext.getThreshold(),
queryContext.getPrefixLength() );
break;
default:
- throw new AssertionFailure( "Unknown approximation: " +
queryContext.getApproximation());
+ throw new AssertionFailure( "Unknown approximation: " +
queryContext.getApproximation() );
}
return query;
}
- private List<String> getAllTermsFromText(String fieldName, String text, Analyzer
analyzer) throws IOException {
- //it's better not to apply the analyzer with windcards as * and ? can be mistakenly
removed
+ private List<String> getAllTermsFromText(String fieldName, String localText,
Analyzer analyzer) throws IOException {
+ //it's better not to apply the analyzer with wildcard as * and ? can be mistakenly
removed
List<String> terms = new ArrayList<String>();
- if ( queryContext.getApproximation() == QueryContext.Approximation.WILDCARD ) {
- terms.add( text );
+ if ( queryContext.getApproximation() == TermQueryContext.Approximation.WILDCARD ) {
+ terms.add( localText );
}
else {
- Reader reader = new StringReader(text);
- TokenStream stream = analyzer.reusableTokenStream( fieldName, reader);
- TermAttribute attribute = (TermAttribute) stream.addAttribute( TermAttribute.class );
- stream.reset();
-
- while ( stream.incrementToken() ) {
- if ( attribute.termLength() > 0 ) {
- String term = attribute.term();
- terms.add( term );
- }
- }
- stream.end();
- stream.close();
+ terms = Helper.getAllTermsFromText( fieldName, localText, analyzer );
}
return terms;
}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -7,6 +7,7 @@
import org.hibernate.search.query.dsl.v2.BooleanJunction;
import org.hibernate.search.query.dsl.v2.FuzzyContext;
import org.hibernate.search.query.dsl.v2.QueryBuilder;
+import org.hibernate.search.query.dsl.v2.RangeContext;
import org.hibernate.search.query.dsl.v2.TermContext;
import org.hibernate.search.query.dsl.v2.WildcardContext;
@@ -36,6 +37,10 @@
return new ConnectedWildcardContext(queryAnalyzer, factory);
}
+ public RangeContext range() {
+ return new ConnectedRangeContext( queryAnalyzer, factory );
+ }
+
//fixme Have to use raw types but would be nice to not have to
public BooleanJunction bool() {
return new BooleanQueryBuilder();
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,136 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.search.Filter;
+
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.query.dsl.v2.RangeContext;
+import org.hibernate.search.query.dsl.v2.RangeMatchingContext;
+
+/**
+ * @author Emmanuel Bernard
+ */
+class ConnectedRangeContext implements RangeContext {
+ private final SearchFactory factory;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+
+ public ConnectedRangeContext(Analyzer queryAnalyzer, SearchFactory factory) {
+ this.factory = factory;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = new QueryCustomizer();
+ }
+
+ public RangeMatchingContext onField(String fieldName) {
+ return new ConnectedRangeMatchingContext(fieldName, queryCustomizer, queryAnalyzer,
factory);
+ }
+
+ public RangeContext boostedTo(float boost) {
+ queryCustomizer.boostedTo( boost );
+ return this;
+ }
+
+ public RangeContext constantScore() {
+ queryCustomizer.constantScore();
+ return this;
+ }
+
+ public RangeContext filter(Filter filter) {
+ queryCustomizer.filter(filter);
+ return this;
+ }
+
+
+//
+// public <T> FromRangeContext<T> from(T from) {
+// context.setFrom( from );
+// return new ConnectedFromRangeContext<T>(this);
+// }
+//
+//
+//
+// SearchFactory getFactory() {
+// return factory;
+// }
+//
+// Analyzer getQueryAnalyzer() {
+// return queryAnalyzer;
+// }
+//
+// QueryCustomizer getQueryCustomizer() {
+// return queryCustomizer;
+// }
+//
+// static class ConnectedFromRangeContext<T> implements FromRangeContext<T>
{
+// private ConnectedRangeContext mother;
+//
+// public ConnectedFromRangeContext(ConnectedRangeContext mother) {
+// this.mother = mother;
+// }
+//
+// public ToRangeContext to(Object to) {
+// mother.getContext().setTo( to );
+// return new ConnectedToRangeContext(mother);
+// }
+//
+// public FromRangeContext<T> exclude() {
+// mother.getContext().setExcludeFrom( true );
+// return this;
+// }
+//
+// public FromRangeContext<T> boostedTo(float boost) {
+// mother.boostedTo( boost );
+// return this;
+// }
+//
+// public FromRangeContext<T> constantScore() {
+// mother.constantScore();
+// return this;
+// }
+//
+// public FromRangeContext<T> filter(Filter filter) {
+// mother.filter( filter );
+// return this;
+// }
+// }
+//
+// static class ConnectedToRangeContext implements ToRangeContext {
+// private ConnectedRangeContext mother;
+//
+// public ConnectedToRangeContext(ConnectedRangeContext mother) {
+// this.mother = mother;
+// }
+//
+// public TermMatchingContext onField(String field) {
+// return new ConnectedTermMatchingContext(
+// mother.getContext(),
+// field,
+// mother.getQueryCustomizer(),
+// mother.getQueryAnalyzer(),
+// mother.getFactory()
+// );
+// }
+//
+// public ToRangeContext exclude() {
+// mother.getContext().setExcludeTo( true );
+// return this;
+// }
+//
+// public ToRangeContext boostedTo(float boost) {
+// mother.boostedTo( boost );
+// return this;
+// }
+//
+// public ToRangeContext constantScore() {
+// mother.constantScore();
+// return this;
+// }
+//
+// public ToRangeContext filter(Filter filter) {
+// mother.filter( filter );
+// return this;
+// }
+// }
+
+
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeMatchingContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeMatchingContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedRangeMatchingContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,97 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.analysis.Analyzer;
+
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.query.dsl.v2.RangeMatchingContext;
+import org.hibernate.search.query.dsl.v2.RangeTerminationExcludable;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ConnectedRangeMatchingContext implements RangeMatchingContext {
+ private final SearchFactory factory;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private final RangeQueryContext queryContext;
+ private final List<FieldContext> fieldContexts;
+ //when a varargs of fields are passed, apply the same customization for all.
+ //keep the index of the first context in this queue
+ private int firstOfContext = 0;
+
+ public ConnectedRangeMatchingContext(String fieldName,
+ QueryCustomizer queryCustomizer,
+ Analyzer queryAnalyzer,
+ SearchFactory factory) {
+ this.factory = factory;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = queryCustomizer;
+ this.queryContext = new RangeQueryContext();
+ this.fieldContexts = new ArrayList<FieldContext>(4);
+ this.fieldContexts.add( new FieldContext( fieldName ) );
+ }
+
+ public RangeMatchingContext andField(String field) {
+ this.fieldContexts.add( new FieldContext( field ) );
+ this.firstOfContext = fieldContexts.size() - 1;
+ return this;
+ }
+
+ public <T> FromRangeContext<T> from(T from) {
+ queryContext.setFrom( from );
+ return new ConnectedFromRangeContext<T>(this);
+ }
+
+ static class ConnectedFromRangeContext<T> implements FromRangeContext<T> {
+ private ConnectedRangeMatchingContext mother;
+
+ ConnectedFromRangeContext(ConnectedRangeMatchingContext mother) {
+ this.mother = mother;
+ }
+
+ public RangeTerminationExcludable to(T to) {
+ mother.queryContext.setTo(to);
+ return new ConnectedMultiFieldsRangeQueryBuilder(
+ mother.queryContext,
+ mother.queryAnalyzer,
+ mother.queryCustomizer,
+ mother.fieldContexts);
+ }
+
+ public FromRangeContext<T> exclude() {
+ mother.queryContext.setExcludeFrom( true );
+ return this;
+ }
+ }
+
+ public RangeTerminationExcludable below(Object below) {
+ queryContext.setTo( below );
+ return new ConnectedMultiFieldsRangeQueryBuilder(queryContext, queryAnalyzer,
queryCustomizer, fieldContexts);
+ }
+
+ public RangeTerminationExcludable above(Object above) {
+ queryContext.setFrom( above );
+ return new ConnectedMultiFieldsRangeQueryBuilder(queryContext, queryAnalyzer,
queryCustomizer, fieldContexts);
+ }
+
+ public RangeMatchingContext boostedTo(float boost) {
+ for ( FieldContext fieldContext : getCurrentFieldContexts() ) {
+ fieldContext.getFieldCustomizer().boostedTo( boost );
+ }
+ return this;
+ }
+
+ private List<FieldContext> getCurrentFieldContexts() {
+ return fieldContexts.subList( firstOfContext, fieldContexts.size() );
+ }
+
+ public RangeMatchingContext ignoreAnalyzer() {
+ for ( FieldContext fieldContext : getCurrentFieldContexts() ) {
+ fieldContext.setIgnoreAnalyzer( true );
+ }
+ return this;
+ }
+}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -14,13 +14,13 @@
private final SearchFactory factory;
private final Analyzer queryAnalyzer;
private final QueryCustomizer queryCustomizer;
- private final QueryContext context;
+ private final TermQueryContext context;
public ConnectedTermContext(Analyzer queryAnalyzer, SearchFactory factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
this.queryCustomizer = new QueryCustomizer();
- this.context = new QueryContext( QueryContext.Approximation.EXACT);
+ this.context = new TermQueryContext( TermQueryContext.Approximation.EXACT);
}
public TermMatchingContext onField(String field) {
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermMatchingContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermMatchingContext.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermMatchingContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -16,13 +16,13 @@
private final SearchFactory factory;
private final Analyzer queryAnalyzer;
private final QueryCustomizer queryCustomizer;
- private final QueryContext queryContext;
+ private final TermQueryContext queryContext;
private final List<FieldContext> fieldContexts;
//when a varargs of fields are passed, apply the same customization for all.
//keep the index of the first context in this queue
private int firstOfContext = 0;
- public ConnectedTermMatchingContext(QueryContext queryContext,
+ public ConnectedTermMatchingContext(TermQueryContext queryContext,
String field, QueryCustomizer queryCustomizer, Analyzer queryAnalyzer, SearchFactory
factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
@@ -32,7 +32,7 @@
this.fieldContexts.add( new FieldContext( field ) );
}
- public ConnectedTermMatchingContext(QueryContext queryContext,
+ public ConnectedTermMatchingContext(TermQueryContext queryContext,
String[] fields, QueryCustomizer queryCustomizer, Analyzer queryAnalyzer,
SearchFactory factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -4,7 +4,6 @@
import org.apache.lucene.search.Filter;
import org.hibernate.search.SearchFactory;
-import org.hibernate.search.query.dsl.v2.TermContext;
import org.hibernate.search.query.dsl.v2.TermMatchingContext;
import org.hibernate.search.query.dsl.v2.WildcardContext;
@@ -15,13 +14,13 @@
private final SearchFactory factory;
private final Analyzer queryAnalyzer;
private final QueryCustomizer queryCustomizer;
- private final QueryContext context;
+ private final TermQueryContext context;
public ConnectedWildcardContext(Analyzer queryAnalyzer, SearchFactory factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
this.queryCustomizer = new QueryCustomizer();
- this.context = new QueryContext( QueryContext.Approximation.WILDCARD);
+ this.context = new TermQueryContext( TermQueryContext.Approximation.WILDCARD);
}
public TermMatchingContext onField(String field) {
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/Helper.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/Helper.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/Helper.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,57 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.tokenattributes.TermAttribute;
+
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.search.SearchException;
+
+/**
+ * @author Emmanuel Bernard
+ */
+class Helper {
+ /**
+ * return the analyzed value for a given field. If several terms are created, an
exception is raised.
+ */
+ static String getAnalyzedTerm(String fieldName, Object value, String name, Analyzer
queryAnalyzer) {
+ try {
+ final List<String> termsFromText = getAllTermsFromText(
+ fieldName, value.toString(), queryAnalyzer
+ );
+ if (termsFromText.size() > 1) {
+ throw new SearchException( "The " + name + " parameter leads to
several terms when analyzed");
+ }
+ return termsFromText.size() == 0 ? null : termsFromText.get( 0 );
+ }
+ catch ( IOException e ) {
+ throw new AssertionFailure("IO exception while reading String stream??",
e);
+ }
+ }
+
+ static List<String> getAllTermsFromText(String fieldName, String localText,
Analyzer analyzer) throws IOException {
+ //it's better not to apply the analyzer with wildcard as * and ? can be mistakenly
removed
+ List<String> terms = new ArrayList<String>();
+
+ Reader reader = new StringReader(localText);
+ TokenStream stream = analyzer.reusableTokenStream( fieldName, reader);
+ TermAttribute attribute = (TermAttribute) stream.addAttribute( TermAttribute.class );
+ stream.reset();
+
+ while ( stream.incrementToken() ) {
+ if ( attribute.termLength() > 0 ) {
+ String term = attribute.term();
+ terms.add( term );
+ }
+ }
+ stream.end();
+ stream.close();
+ return terms;
+ }
+}
Deleted:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -1,40 +0,0 @@
-package org.hibernate.search.query.dsl.v2.impl;
-
-/**
-* @author Emmanuel Bernard
-*/
-public class QueryContext {
- private final Approximation approximation;
- private float threshold = .5f;
- private int prefixLength = 0;
-
- public QueryContext(Approximation approximation) {
- this.approximation = approximation;
- }
-
- public void setThreshold(float threshold) {
- this.threshold = threshold;
- }
-
- public void setPrefixLength(int prefixLength) {
- this.prefixLength = prefixLength;
- }
-
- public Approximation getApproximation() {
- return approximation;
- }
-
- public float getThreshold() {
- return threshold;
- }
-
- public int getPrefixLength() {
- return prefixLength;
- }
-
- public static enum Approximation {
- EXACT,
- WILDCARD,
- FUZZY
- }
-}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/RangeQueryContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/RangeQueryContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/RangeQueryContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,44 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class RangeQueryContext {
+ //RANGE
+ private Object from;
+ private Object to;
+ private boolean excludeFrom;
+ private boolean excludeTo;
+
+ public Object getFrom() {
+ return from;
+ }
+
+ public void setFrom(Object from) {
+ this.from = from;
+ }
+
+ public Object getTo() {
+ return to;
+ }
+
+ public void setTo(Object to) {
+ this.to = to;
+ }
+
+ public boolean isExcludeFrom() {
+ return excludeFrom;
+ }
+
+ public void setExcludeFrom(boolean excludeFrom) {
+ this.excludeFrom = excludeFrom;
+ }
+
+ public boolean isExcludeTo() {
+ return excludeTo;
+ }
+
+ public void setExcludeTo(boolean excludeTo) {
+ this.excludeTo = excludeTo;
+ }
+}
Copied:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/TermQueryContext.java
(from rev 19569,
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java)
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/TermQueryContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/TermQueryContext.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -0,0 +1,43 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+/**
+* @author Emmanuel Bernard
+*/
+class TermQueryContext {
+ private final Approximation approximation;
+ //FUZZY
+ private float threshold = .5f;
+
+ //WILDCARD
+ private int prefixLength = 0;
+
+ public TermQueryContext(Approximation approximation) {
+ this.approximation = approximation;
+ }
+
+ public void setThreshold(float threshold) {
+ this.threshold = threshold;
+ }
+
+ public void setPrefixLength(int prefixLength) {
+ this.prefixLength = prefixLength;
+ }
+
+ public Approximation getApproximation() {
+ return approximation;
+ }
+
+ public float getThreshold() {
+ return threshold;
+ }
+
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+
+ public static enum Approximation {
+ EXACT,
+ WILDCARD,
+ FUZZY
+ }
+}
Modified:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -1,6 +1,11 @@
package org.hibernate.search.test.query.dsl;
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
import java.util.List;
+import java.util.TimeZone;
import org.apache.lucene.search.Query;
import org.apache.solr.analysis.LowerCaseFilterFactory;
@@ -14,6 +19,7 @@
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.annotations.Factory;
@@ -237,7 +243,60 @@
cleanData( fts );
}
+ public void testRangeQuery() throws Exception {
+ FullTextSession fts = initData();
+ Transaction transaction = fts.beginTransaction();
+ final QueryBuilder monthQb = fts.getSearchFactory()
+ .buildQueryBuilder().forEntity( Month.class ).get();
+
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+ calendar.set(0 + 1900, 2, 12, 0, 0, 0);
+ Date from = calendar.getTime();
+ calendar.set(10 + 1900, 2, 12, 0, 0, 0);
+ Date to = calendar.getTime();
+ final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMdd" );
+
+ Query
+
+ query = monthQb.
+ range()
+ .onField( "estimatedCreation" )
+ .andField( "justfortest" )
+ .from( dateFormat.format( from ) )
+ .to( dateFormat.format( to ) ).exclude()
+ .createQuery();
+
+ assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+
+ query = monthQb.
+ range()
+ .onField( "estimatedCreation" )
+ .andField( "justfortest" )
+ .below( dateFormat.format( to ) )
+ .createQuery();
+
+ FullTextQuery hibQuery = fts.createFullTextQuery( query, Month.class );
+ assertEquals( 1, hibQuery.getResultSize() );
+ assertEquals( "January", ( (Month) hibQuery.list().get( 0 ) ).getName() );
+
+ query = monthQb.
+ range()
+ .onField( "estimatedCreation" )
+ .andField( "justfortest" )
+ .above( dateFormat.format( to ) )
+ .createQuery();
+ hibQuery = fts.createFullTextQuery( query, Month.class );
+ assertEquals( 1, hibQuery.getResultSize() );
+ assertEquals( "February", ( (Month) hibQuery.list().get( 0 ) ).getName() );
+
+ transaction.commit();
+
+ cleanData( fts );
+ }
+
+
// public void testTermQueryOnAnalyzer() throws Exception {
// FullTextSession fts = initData();
//
@@ -363,8 +422,20 @@
Session session = openSession();
FullTextSession fts = Search.getFullTextSession( session );
Transaction tx = fts.beginTransaction();
- fts.persist( new Month("January", "Month of colder and whitening",
"Historically colder than any other month in the northern hemisphere") );
- fts.persist( new Month("February", "Month of snowboarding",
"Historically, the month where we make babies while watching the whitening
landscape") );
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+ calendar.set(0 + 1900, 2, 12, 0, 0, 0);
+ fts.persist( new Month(
+ "January",
+ "Month of colder and whitening",
+ "Historically colder than any other month in the northern hemisphere",
+ calendar.getTime() ) );
+ calendar.set(100 + 1900, 2, 12, 0, 0, 0);
+ fts.persist( new Month(
+ "February",
+ "Month of snowboarding",
+ "Historically, the month where we make babies while watching the whitening
landscape",
+ calendar.getTime() ) );
tx.commit();
fts.clear();
return fts;
Modified:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/Month.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/Month.java 2010-05-22
12:31:15 UTC (rev 19588)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/Month.java 2010-05-23
09:11:49 UTC (rev 19589)
@@ -1,13 +1,17 @@
package org.hibernate.search.test.query.dsl;
+import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.search.annotations.Analyzer;
+import org.hibernate.search.annotations.DateBridge;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Fields;
+import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.Resolution;
/**
* @author Emmanuel Bernard
@@ -17,10 +21,11 @@
public class Month {
public Month() {}
- public Month(String name, String mythology, String history) {
+ public Month(String name, String mythology, String history, Date estimatedCreation) {
this.name = name;
this.mythology = mythology;
this.history = history;
+ this.estimatedCreation = estimatedCreation;
}
@Id @GeneratedValue
@@ -47,5 +52,10 @@
public void setHistory(String history) { this.history = history; }
private String history;
+ @Field(index = Index.UN_TOKENIZED) @DateBridge(resolution = Resolution.MINUTE)
+ public Date getEstimatedCreation() { return estimatedCreation; }
+ public void setEstimatedCreation(Date estimatedCreation) { this.estimatedCreation =
estimatedCreation; }
+ private Date estimatedCreation;
+
}