Author: epbernard
Date: 2010-04-16 12:06:40 -0400 (Fri, 16 Apr 2010)
New Revision: 19242
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FieldCustomization.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FuzzyContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermTermination.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/Termination.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/WildcardContext.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/ConnectedSingleTermQueryBuilder.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/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java
Removed:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermCustomization.java
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/BooleanJunction.java
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/QueryCustomization.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermFuzzy.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermMatchingContext.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/QueryCustomizer.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java
Log:
HSEARCH-414 use new approach asking for the type of query first
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/BooleanJunction.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/BooleanJunction.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/BooleanJunction.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -7,7 +7,7 @@
*
* @author Emmanuel Bernard
*/
-public interface BooleanJunction<T extends BooleanJunction> extends
QueryCustomization<T> {
+public interface BooleanJunction<T extends BooleanJunction> extends
QueryCustomization<T>, Termination {
/**
* The boolean query results should match the subquery
*/
@@ -18,9 +18,4 @@
* Call the .not() method to ensure results of the boolean query do NOT match the
subquery.
*/
MustJunction must(Query query);
-
- /**
- * Return the lucene query representing the boolean operation
- */
- Query createQuery();
}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FieldCustomization.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FieldCustomization.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FieldCustomization.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,23 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface FieldCustomization<T> {
+ /**
+ * Boost the field to a given value
+ * Most of the time positive float:
+ * - lower than 1 to diminish the weight
+ * - higher than 1 to increase the weight
+ *
+ * Could be negative but not unless you understand what is going on (advanced)
+ */
+ T boostedTo(float boost);
+
+ /**
+ * Advanced
+ * Do not execute the analyzer on the text.
+ * (It is usually a good idea to apply the analyzer)
+ */
+ T ignoreAnalyzer();
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FuzzyContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FuzzyContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/FuzzyContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,26 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface FuzzyContext extends QueryCustomization<FuzzyContext> {
+ /**
+ * field / property the term query is executed on
+ */
+ TermMatchingContext onField(String field);
+
+ /**
+ * Threshold above which two terms are considered similar enough.
+ * Value between 0 and 1 (1 excluded)
+ * Defaults to .5
+ */
+ FuzzyContext threshold(float threshold);
+
+ /**
+ * Size of the prefix ignored by the fuzzyness.
+ * A non zero value is recommended if the index contains a huge amount of distinct
terms
+ *
+ * Defaults to 0
+ */
+ FuzzyContext prefixLength(int prefixLength);
+}
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-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -7,10 +7,23 @@
/**
* build a term query
*/
- TermContext term();
+ TermContext exact();
+ /**
+ * Use a fuzzy search approximation (aka edit distance)
+ */
+ FuzzyContext fuzzy();
/**
+ * Treat the query as a wildcard:
+ * - ? represents any single character
+ * - * represents any character sequence
+ * For faster results, it is recommended that the query text does not
+ * start with ? or *
+ */
+ WildcardContext wildcard();
+
+ /**
* Boolean query
*/
BooleanJunction<BooleanJunction> bool();
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryCustomization.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryCustomization.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryCustomization.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -32,9 +32,4 @@
T filter(Filter filter);
//TODO filter(String) + parameters
-
- /**
- * Create a Lucene query
- */
- Query createQuery();
}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -5,10 +5,10 @@
/**
* @author Emmanuel Bernard
*/
-public interface TermContext {
+public interface TermContext extends QueryCustomization<TermContext> {
/**
* field / property the term query is executed on
*/
- TermMatchingContext on(String field);
+ TermMatchingContext onField(String field);
}
Deleted:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermCustomization.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermCustomization.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermCustomization.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -1,31 +0,0 @@
-package org.hibernate.search.query.dsl.v2;
-
-import org.apache.lucene.search.Query;
-
-/**
-* @author Emmanuel Bernard
-*/
-public interface TermCustomization extends QueryCustomization<TermCustomization> {
- /**
- * Advanced
- * Do not execute the analyzer on the text.
- * (It is usually a good idea to apply the analyzer)
- */
- TermCustomization ignoreAnalyzer();
-
- /**
- * Use a fuzzy search approximation (aka edit distance)
- */
- TermFuzzy fuzzy();
-
- /**
- * Treat the query as a wildcard:
- * - ? represents any single character
- * - * represents any character sequence
- * For faster results, it is recommended that the query text does not
- * start with ? or *
- */
- //TODO make it mutually exclusive with fuzzy use (but that's much more complex)
- TermCustomization wildcard();
-
-}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermFuzzy.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermFuzzy.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermFuzzy.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -3,7 +3,7 @@
/**
* @author Emmanuel Bernard
*/
-public interface TermFuzzy extends TermCustomization {
+public interface TermFuzzy extends TermTermination {
/**
* Threshold above which two terms are considered similar enough.
* Value between 0 and 1 (1 excluded)
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermMatchingContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermMatchingContext.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermMatchingContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -3,9 +3,9 @@
/**
* @author Emmanuel Bernard
*/
-public interface TermMatchingContext {
+public interface TermMatchingContext extends
FieldCustomization<TermMatchingContext> {
/**
* text searched in the term query (the term is pre-analyzer unless ignoreAnalyzer is
called)
*/
- TermCustomization matches(String text);
+ TermTermination matches(String text);
}
Copied:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermTermination.java
(from rev 19212,
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermCustomization.java)
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermTermination.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermTermination.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,7 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+* @author Emmanuel Bernard
+*/
+public interface TermTermination extends Termination<TermTermination> {
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/Termination.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/Termination.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/Termination.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,13 @@
+package org.hibernate.search.query.dsl.v2;
+
+import org.apache.lucene.search.Query;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface Termination<T> {
+ /**
+ * Return the lucene query representing the operation
+ */
+ Query createQuery();
+}
Copied:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/WildcardContext.java
(from rev 19212,
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java)
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/WildcardContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/WildcardContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,12 @@
+package org.hibernate.search.query.dsl.v2;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface WildcardContext extends QueryCustomization<WildcardContext> {
+ /**
+ * field / property the term query is executed on
+ */
+ TermMatchingContext onField(String field);
+
+}
\ No newline at end of file
Copied:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java
(from rev 19212,
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/ConnectedFuzzyContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedFuzzyContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,56 @@
+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.FuzzyContext;
+import org.hibernate.search.query.dsl.v2.TermContext;
+import org.hibernate.search.query.dsl.v2.TermMatchingContext;
+
+/**
+ * @author Emmanuel Bernard
+ */
+class ConnectedFuzzyContext implements FuzzyContext {
+ private final SearchFactory factory;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private final QueryContext context;
+
+ public ConnectedFuzzyContext(Analyzer queryAnalyzer, SearchFactory factory) {
+ this.factory = factory;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = new QueryCustomizer();
+ this.context = new QueryContext( QueryContext.Approximation.FUZZY);
+ }
+
+ public TermMatchingContext onField(String field) {
+ return new ConnectedTermMatchingContext(context, field, queryCustomizer, queryAnalyzer,
factory);
+ }
+
+ public ConnectedFuzzyContext threshold(float threshold) {
+ context.setThreshold( threshold );
+ return this;
+ }
+
+ public ConnectedFuzzyContext prefixLength(int prefixLength) {
+ context.setPrefixLength( prefixLength );
+ return this;
+ }
+
+ public FuzzyContext boostedTo(float boost) {
+ queryCustomizer.boostedTo( boost );
+ return this;
+ }
+
+ public FuzzyContext constantScore() {
+ queryCustomizer.constantScore();
+ return this;
+ }
+
+ public FuzzyContext filter(Filter filter) {
+ queryCustomizer.filter(filter);
+ return this;
+ }
+
+}
\ No newline at end of file
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-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -4,8 +4,10 @@
import org.hibernate.search.SearchFactory;
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.TermContext;
+import org.hibernate.search.query.dsl.v2.WildcardContext;
/**
* Assuming connection with the search factory
@@ -21,10 +23,19 @@
this.factory = factory;
}
- public TermContext term() {
- return new ConnectedTermContext( queryAnalyzer, factory);
+ public TermContext exact() {
+ return new ConnectedTermContext(queryAnalyzer, factory);
}
+ public FuzzyContext fuzzy() {
+ return new ConnectedFuzzyContext(queryAnalyzer, factory);
+ }
+
+ public WildcardContext wildcard() {
+ return new ConnectedWildcardContext(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/ConnectedSingleTermQueryBuilder.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedSingleTermQueryBuilder.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedSingleTermQueryBuilder.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,127 @@
+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;
+import org.apache.lucene.search.FuzzyQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.WildcardQuery;
+
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.query.dsl.v2.TermTermination;
+
+/**
+* @author Emmanuel Bernard
+*/
+public class ConnectedSingleTermQueryBuilder implements TermTermination {
+ private final SearchFactory factory;
+ private final String field;
+ private final String text;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private boolean ignoreAnalyzer;
+ private final QueryContext context;
+
+ public ConnectedSingleTermQueryBuilder(
+ QueryContext context,
+ boolean ignoreAnalyzer,
+ String text,
+ String field,
+ QueryCustomizer queryCustomizer,
+ Analyzer queryAnalyzer,
+ SearchFactory factory) {
+ this.context = context;
+ this.factory = factory;
+ this.field = field;
+ this.text = text;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = queryCustomizer;
+ this.ignoreAnalyzer = ignoreAnalyzer;
+ }
+
+ public Query createQuery() {
+ final Query result;
+ if ( ignoreAnalyzer ) {
+ result = createTermQuery( text );
+ }
+ else {
+ List<String> terms;
+ try {
+ terms = getAllTermsFromText( field, text, queryAnalyzer );
+ }
+ catch ( IOException e ) {
+ throw new AssertionFailure("IO exception while reading String stream??",
e);
+ }
+ if ( terms.size() == 0 ) {
+ throw new SearchException("try to search with an empty string: " + field);
+ }
+ else if (terms.size() == 1 ) {
+ result = createTermQuery( terms.get( 0 ) );
+ }
+ else {
+ BooleanQuery booleanQuery = new BooleanQuery();
+ for (String term : terms) {
+ Query termQuery = createTermQuery(term);
+ booleanQuery.add( termQuery, BooleanClause.Occur.SHOULD );
+ }
+ result = booleanQuery;
+ }
+ }
+ return queryCustomizer.setWrappedQuery( result ).createQuery();
+ }
+
+ private Query createTermQuery(String term) {
+ Query query;
+ switch ( context.getApproximation() ) {
+ case EXACT:
+ query = new TermQuery( new Term(field, term) );
+ break;
+ case WILDCARD:
+ query = new WildcardQuery( new Term(field, term) );
+ break;
+ case FUZZY:
+ query = new FuzzyQuery( new Term(field, term), context.getThreshold(),
context.getPrefixLength() );
+ break;
+ default:
+ throw new AssertionFailure( "Unknown approximation: " +
context.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
+ List<String> terms = new ArrayList<String>();
+ if ( context.getApproximation() == QueryContext.Approximation.WILDCARD ) {
+ terms.add( text );
+ }
+ 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();
+ }
+ return terms;
+ }
+
+}
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-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -1,29 +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;
import org.apache.lucene.search.Filter;
-import org.apache.lucene.search.FuzzyQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.WildcardQuery;
-import org.hibernate.annotations.common.AssertionFailure;
-import org.hibernate.search.SearchException;
import org.hibernate.search.SearchFactory;
import org.hibernate.search.query.dsl.v2.TermContext;
-import org.hibernate.search.query.dsl.v2.TermCustomization;
-import org.hibernate.search.query.dsl.v2.TermFuzzy;
import org.hibernate.search.query.dsl.v2.TermMatchingContext;
/**
@@ -32,177 +13,32 @@
class ConnectedTermContext implements TermContext {
private final SearchFactory factory;
private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private final QueryContext context;
public ConnectedTermContext(Analyzer queryAnalyzer, SearchFactory factory) {
this.factory = factory;
this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = new QueryCustomizer();
+ this.context = new QueryContext( QueryContext.Approximation.EXACT);
}
- public TermMatchingContext on(String field) {
- return new ConnectedTermMatchingContext(field, queryAnalyzer, factory);
+ public TermMatchingContext onField(String field) {
+ return new ConnectedTermMatchingContext(context, field, queryCustomizer, queryAnalyzer,
factory);
}
- public static class ConnectedTermMatchingContext implements TermMatchingContext {
- private final SearchFactory factory;
- private final String field;
- private final Analyzer queryAnalyzer;
+ public TermContext boostedTo(float boost) {
+ queryCustomizer.boostedTo( boost );
+ return this;
+ }
- public ConnectedTermMatchingContext(String field, Analyzer queryAnalyzer, SearchFactory
factory) {
- this.factory = factory;
- this.field = field;
- this.queryAnalyzer = queryAnalyzer;
- }
-
- public TermCustomization matches(String text) {
- return new ConnectedTermCustomization(text, field, queryAnalyzer, factory);
- }
+ public TermContext constantScore() {
+ queryCustomizer.constantScore();
+ return this;
}
- public static class ConnectedTermCustomization implements TermCustomization, TermFuzzy
{
- private final SearchFactory factory;
- private final String field;
- private final String text;
- private final Analyzer queryAnalyzer;
- private final QueryCustomizer queryCustomizer;
-
- private boolean ignoreAnalyzer;
- private Approximation approximation = Approximation.EXACT;
- private float threshold = .5f;
- private int prefixLength = 0;
-
- public ConnectedTermCustomization(String text, String field, Analyzer queryAnalyzer,
SearchFactory factory) {
- this.factory = factory;
- this.field = field;
- this.text = text;
- this.queryAnalyzer = queryAnalyzer;
- this.queryCustomizer = new QueryCustomizer();
- }
-
- public TermCustomization ignoreAnalyzer() {
- ignoreAnalyzer = true;
- return this;
- }
-
- public TermFuzzy fuzzy() {
- if (approximation != Approximation.EXACT) {
- throw new IllegalStateException( "Cannot call fuzzy() and wildcard() on the same
term query" );
- }
- approximation = Approximation.FUZZY;
- return this;
- }
-
- public TermCustomization wildcard() {
- if (approximation != Approximation.EXACT) {
- throw new IllegalStateException( "Cannot call fuzzy() and wildcard() on the same
term query" );
- }
- approximation = Approximation.WILDCARD;
- return this;
- }
-
- public TermCustomization boostedTo(float boost) {
- queryCustomizer.boostedTo( boost );
- return this;
- }
-
- public TermCustomization constantScore() {
- queryCustomizer.constantScore();
- return this;
- }
-
- public TermCustomization filter(Filter filter) {
- queryCustomizer.filter( filter );
- return this;
- }
-
- public Query createQuery() {
- final Query result;
- if ( ignoreAnalyzer ) {
- result = createTermQuery( text );
- }
- else {
- List<String> terms;
- try {
- terms = getAllTermsFromText( field, text, queryAnalyzer );
- }
- catch ( IOException e ) {
- throw new AssertionFailure("IO exception while reading String stream??",
e);
- }
- if ( terms.size() == 0 ) {
- throw new SearchException("try to search with an empty string: " +
field);
- }
- else if (terms.size() == 1 ) {
- result = createTermQuery( terms.get( 0 ) );
- }
- else {
- BooleanQuery booleanQuery = new BooleanQuery();
- for (String term : terms) {
- Query termQuery = createTermQuery(term);
- //termQuery.setBoost( boost );
- booleanQuery.add( termQuery, BooleanClause.Occur.SHOULD );
- }
- result = booleanQuery;
- }
- }
- return queryCustomizer.setWrappedQuery( result ).createQuery();
- }
-
- private Query createTermQuery(String term) {
- Query query;
- switch ( approximation ) {
- case EXACT:
- query = new TermQuery( new Term(field, term) );
- break;
- case WILDCARD:
- query = new WildcardQuery( new Term(field, term) );
- break;
- case FUZZY:
- query = new FuzzyQuery( new Term(field, term), threshold, prefixLength );
- break;
- default:
- throw new AssertionFailure( "Unknown approximation: " + approximation);
-
- }
- 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
- List<String> terms = new ArrayList<String>();
- if ( approximation == Approximation.WILDCARD ) {
- terms.add( text );
- }
- 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();
- }
- return terms;
- }
-
- public TermFuzzy threshold(float threshold) {
- this.threshold = threshold;
- return this;
- }
-
- public TermFuzzy prefixLength(int prefixLength) {
- this.prefixLength = prefixLength;
- return this;
- }
-
- private static enum Approximation {
- EXACT,
- WILDCARD,
- FUZZY
- }
+ public TermContext filter(Filter filter) {
+ queryCustomizer.filter(filter);
+ return this;
}
}
Added:
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
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermMatchingContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,42 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import org.apache.lucene.analysis.Analyzer;
+
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.query.dsl.v2.TermMatchingContext;
+import org.hibernate.search.query.dsl.v2.TermTermination;
+
+/**
+* @author Emmanuel Bernard
+*/
+public class ConnectedTermMatchingContext implements TermMatchingContext {
+ private final SearchFactory factory;
+ private final String field;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private boolean ignoreAnalyzer;
+ private final QueryContext context;
+
+ public ConnectedTermMatchingContext(QueryContext context,
+ String field, QueryCustomizer queryCustomizer, Analyzer queryAnalyzer, SearchFactory
factory) {
+ this.factory = factory;
+ this.field = field;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = queryCustomizer;
+ this.context = context;
+ }
+
+ public TermTermination matches(String text) {
+ return new ConnectedSingleTermQueryBuilder(context, ignoreAnalyzer, text, field,
queryCustomizer, queryAnalyzer, factory);
+ }
+
+ public TermMatchingContext boostedTo(float boost) {
+ queryCustomizer.boostedTo( boost );
+ return this;
+ }
+
+ public TermMatchingContext ignoreAnalyzer() {
+ this.ignoreAnalyzer = true;
+ return this;
+ }
+}
Copied:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java
(from rev 19212,
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/ConnectedWildcardContext.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedWildcardContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,45 @@
+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.TermContext;
+import org.hibernate.search.query.dsl.v2.TermMatchingContext;
+import org.hibernate.search.query.dsl.v2.WildcardContext;
+
+/**
+ * @author Emmanuel Bernard
+ */
+class ConnectedWildcardContext implements WildcardContext {
+ private final SearchFactory factory;
+ private final Analyzer queryAnalyzer;
+ private final QueryCustomizer queryCustomizer;
+ private final QueryContext context;
+
+ public ConnectedWildcardContext(Analyzer queryAnalyzer, SearchFactory factory) {
+ this.factory = factory;
+ this.queryAnalyzer = queryAnalyzer;
+ this.queryCustomizer = new QueryCustomizer();
+ this.context = new QueryContext( QueryContext.Approximation.WILDCARD);
+ }
+
+ public TermMatchingContext onField(String field) {
+ return new ConnectedTermMatchingContext(context, field, queryCustomizer, queryAnalyzer,
factory);
+ }
+
+ public WildcardContext boostedTo(float boost) {
+ queryCustomizer.boostedTo( boost );
+ return this;
+ }
+
+ public WildcardContext constantScore() {
+ queryCustomizer.constantScore();
+ return this;
+ }
+
+ public WildcardContext filter(Filter filter) {
+ queryCustomizer.filter(filter);
+ return this;
+ }
+}
\ No newline at end of file
Added:
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
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryContext.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -0,0 +1,40 @@
+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
+ }
+}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryCustomizer.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryCustomizer.java 2010-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/QueryCustomizer.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -20,7 +20,7 @@
private Filter filter;
public QueryCustomizer boostedTo(float boost) {
- this.boost = boost;
+ this.boost = boost * this.boost;
return this;
}
@@ -44,7 +44,7 @@
if (wrappedQuery == null) {
throw new AssertionFailure( "wrapped query not set" );
}
- finalQuery.setBoost( boost );
+ finalQuery.setBoost( boost * finalQuery.getBoost() );
if (filter != null) {
finalQuery = new FilteredQuery(finalQuery, filter);
}
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-04-16
10:11:32 UTC (rev 19241)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/query/dsl/DSLTest.java 2010-04-16
16:06:40 UTC (rev 19242)
@@ -35,31 +35,31 @@
.buildQueryBuilder().forEntity( Month.class ).get();
Query
//regular term query
- query = monthQb.term().on( "mythology" ).matches( "cold"
).createQuery();
+ query = monthQb.exact().onField( "mythology" ).matches( "cold"
).createQuery();
assertEquals( 0, fts.createFullTextQuery( query, Month.class ).getResultSize() );
//term query based on several words
- query = monthQb.term().on( "mythology" ).matches( "colder darker"
).createQuery();
+ query = monthQb.exact().onField( "mythology" ).matches( "colder
darker" ).createQuery();
assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
//term query applying the analyzer and generating one term per word
- query = monthQb.term().on( "mythology_stem" ).matches( "snowboard"
).createQuery();
+ query = monthQb.exact().onField( "mythology_stem" ).matches(
"snowboard" ).createQuery();
assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
//term query applying the analyzer and generating several terms per word
- query = monthQb.term().on( "mythology_ngram" ).matches( "snobored"
).createQuery();
+ query = monthQb.exact().onField( "mythology_ngram" ).matches(
"snobored" ).createQuery();
assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
//term query not using analyzers
- query = monthQb.term().on( "mythology" ).matches( "Month"
).ignoreAnalyzer().createQuery();
+ query = monthQb.exact().onField( "mythology" ).ignoreAnalyzer().matches(
"Month" ).createQuery();
assertEquals( 0, fts.createFullTextQuery( query, Month.class ).getResultSize() );
- query = monthQb.term().on( "mythology" ).matches( "Month"
).createQuery();
+ query = monthQb.exact().onField( "mythology" ).matches( "Month"
).createQuery();
transaction.commit();
@@ -73,22 +73,25 @@
final QueryBuilder monthQb = fts.getSearchFactory()
.buildQueryBuilder().forEntity( Month.class ).get();
Query
+
//fuzzy search with custom threshold and prefix
query = monthQb
- .term().on( "mythology" ).matches( "calder" )
- .fuzzy()
- .threshold( .8f )
- .prefixLength( 1 )
- .createQuery();
+ .fuzzy()
+ .threshold( .8f )
+ .prefixLength( 1 )
+ .onField( "mythology" )
+ .matches( "calder" )
+ .createQuery();
assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
//wildcard query
query = monthQb
- .term().on( "mythology" ).matches( "mon*" )
- .wildcard()
- .createQuery();
- System.out.println(query.toString( ));
+ .wildcard()
+ .onField( "mythology" )
+ .matches( "mon*" )
+ .createQuery();
+
assertEquals( 2, fts.createFullTextQuery( query, Month.class ).getResultSize() );
transaction.commit();
@@ -107,8 +110,8 @@
//combined query, January and february both contain whitening but February in a longer
text
query = monthQb
.bool()
- .should( monthQb.term().on( "mythology" ).matches( "whitening"
).createQuery() )
- .should( monthQb.term().on( "history" ).matches( "whitening"
).createQuery() )
+ .should( monthQb.exact().onField( "mythology" ).matches(
"whitening" ).createQuery() )
+ .should( monthQb.exact().onField( "history" ).matches(
"whitening" ).createQuery() )
.createQuery();
List<Month> results = fts.createFullTextQuery( query, Month.class ).list();
@@ -119,8 +122,8 @@
//since history is boosted, February should come first though
query = monthQb
.bool()
- .should( monthQb.term().on( "mythology" ).matches( "whitening"
).createQuery() )
- .should( monthQb.term().on( "history" ).matches( "whitening"
).boostedTo( 30 ).createQuery() )
+ .should( monthQb.exact().onField( "mythology" ).matches(
"whitening" ).createQuery() )
+ .should( monthQb.exact().onField( "history" ).boostedTo( 30 ).matches(
"whitening" ).createQuery() )
.createQuery();
results = fts.createFullTextQuery( query, Month.class ).list();
@@ -134,6 +137,114 @@
cleanData( fts );
}
+
+// public void testTermQueryOnAnalyzer() throws Exception {
+// FullTextSession fts = initData();
+//
+// Transaction transaction = fts.beginTransaction();
+// final QueryBuilder monthQb = fts.getSearchFactory()
+// .buildQueryBuilder().forEntity( Month.class ).get();
+// Query
+// //regular term query
+// query = monthQb.term().on( "mythology" ).matches( "cold"
).createQuery();
+//
+// assertEquals( 0, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// //term query based on several words
+// query = monthQb.term().on( "mythology" ).matches( "colder darker"
).createQuery();
+//
+// assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// //term query applying the analyzer and generating one term per word
+// query = monthQb.term().on( "mythology_stem" ).matches(
"snowboard" ).createQuery();
+//
+// assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// //term query applying the analyzer and generating several terms per word
+// query = monthQb.term().on( "mythology_ngram" ).matches(
"snobored" ).createQuery();
+//
+// assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// //term query not using analyzers
+// query = monthQb.term().on( "mythology" ).matches( "Month"
).ignoreAnalyzer().createQuery();
+//
+// assertEquals( 0, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// query = monthQb.term().on( "mythology" ).matches( "Month"
).createQuery();
+//
+// transaction.commit();
+//
+// cleanData( fts );
+// }
+//
+// public void testFuzzyAndWildcardQuery() throws Exception {
+// FullTextSession fts = initData();
+//
+// Transaction transaction = fts.beginTransaction();
+// final QueryBuilder monthQb = fts.getSearchFactory()
+// .buildQueryBuilder().forEntity( Month.class ).get();
+// Query
+// //fuzzy search with custom threshold and prefix
+// query = monthQb
+// .term().on( "mythology" ).matches( "calder" )
+// .fuzzy()
+// .threshold( .8f )
+// .prefixLength( 1 )
+// .createQuery();
+//
+// assertEquals( 1, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// //wildcard query
+// query = monthQb
+// .term().on( "mythology" ).matches( "mon*" )
+// .wildcard()
+// .createQuery();
+// System.out.println(query.toString( ));
+// assertEquals( 2, fts.createFullTextQuery( query, Month.class ).getResultSize() );
+//
+// transaction.commit();
+//
+// cleanData( fts );
+// }
+//
+// public void testQueryCustomization() throws Exception {
+// FullTextSession fts = initData();
+//
+// Transaction transaction = fts.beginTransaction();
+// final QueryBuilder monthQb = fts.getSearchFactory()
+// .buildQueryBuilder().forEntity( Month.class ).get();
+// Query
+//
+// //combined query, January and february both contain whitening but February in a
longer text
+// query = monthQb
+// .bool()
+// .should( monthQb.term().on( "mythology" ).matches( "whitening"
).createQuery() )
+// .should( monthQb.term().on( "history" ).matches( "whitening"
).createQuery() )
+// .createQuery();
+//
+// List<Month> results = fts.createFullTextQuery( query, Month.class ).list();
+// assertEquals( 2, results.size() );
+// assertEquals( "January", results.get( 0 ).getName() );
+//
+// //boosted query, January and february both contain whitening but February in a longer
text
+// //since history is boosted, February should come first though
+// query = monthQb
+// .bool()
+// .should( monthQb.term().on( "mythology" ).matches( "whitening"
).createQuery() )
+// .should( monthQb.term().on( "history" ).matches( "whitening"
).boostedTo( 30 ).createQuery() )
+// .createQuery();
+//
+// results = fts.createFullTextQuery( query, Month.class ).list();
+// assertEquals( 2, results.size() );
+// assertEquals( "February", results.get( 0 ).getName() );
+//
+// //FIXME add other method tests besides boostedTo
+//
+// transaction.commit();
+//
+// cleanData( fts );
+// }
+
//FIXME add boolean tests
private void cleanData(FullTextSession fts) {