[hibernate-commits] Hibernate SVN: r19011 - in search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl: v2 and 1 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Tue Mar 16 14:48:41 EDT 2010
Author: epbernard
Date: 2010-03-16 14:48:40 -0400 (Tue, 16 Mar 2010)
New Revision: 19011
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/
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/QueryContextBuilder.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/impl/
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/ConnectedQueryContextBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java
Log:
HSEARCH-414 first take at the query DSL (need tests)
Added: 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 (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryBuilder.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,13 @@
+package org.hibernate.search.query.dsl.v2;
+
+import org.hibernate.search.query.dsl.v2.TermContext;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface QueryBuilder {
+ /**
+ * build a term query
+ */
+ TermContext term();
+}
Added: search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryContextBuilder.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryContextBuilder.java (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/QueryContextBuilder.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,15 @@
+package org.hibernate.search.query.dsl.v2;
+
+import org.apache.lucene.analysis.Analyzer;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface QueryContextBuilder {
+ //TODO make a forEntities
+ EntityContext forEntity(Class<?> entityType);
+ interface EntityContext {
+ EntityContext overridesForField(String field, String analyzerName);
+ QueryBuilder get();
+ }
+}
Added: 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 (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/TermContext.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,68 @@
+package org.hibernate.search.query.dsl.v2;
+
+import org.apache.lucene.search.Query;
+
+import org.hibernate.search.query.dsl.v2.QueryBuilder;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface TermContext {
+ /**
+ * field / property the term query is executed on
+ */
+ TermMatchingContext on(String field);
+
+ interface TermMatchingContext {
+ /**
+ * text searched in the term query (the term is pre-analyzer unless ignoreAnalyzer is called)
+ */
+ TermCustomization matches(String text);
+ }
+
+ interface 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();
+
+ /**
+ * Create a Lucene query
+ */
+ Query createQuery();
+
+ interface TermFuzzy extends TermCustomization {
+ /**
+ * Threshold above which two terms are considered similar enough.
+ * Value between 0 and 1 (1 excluded)
+ * Defaults to .5
+ */
+ TermFuzzy 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
+ */
+ TermFuzzy prefixLength(int prefixLength);
+ }
+ }
+}
Added: 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 (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryBuilder.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,26 @@
+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.QueryBuilder;
+import org.hibernate.search.query.dsl.v2.TermContext;
+
+/**
+ * Assuming connection with the search factory
+ *
+ * @author Emmanuel Bernard
+ */
+public class ConnectedQueryBuilder implements QueryBuilder {
+ private final Analyzer queryAnalyzer;
+ private final SearchFactory factory;
+
+ public ConnectedQueryBuilder(Analyzer queryAnalyzer, SearchFactory factory) {
+ this.queryAnalyzer = queryAnalyzer;
+ this.factory = factory;
+ }
+
+ public TermContext term() {
+ return new ConnectedTermContext( queryAnalyzer, factory);
+ }
+}
Added: search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryContextBuilder.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryContextBuilder.java (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedQueryContextBuilder.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,43 @@
+package org.hibernate.search.query.dsl.v2.impl;
+
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.query.dsl.v2.QueryBuilder;
+import org.hibernate.search.query.dsl.v2.QueryContextBuilder;
+import org.hibernate.search.util.ScopedAnalyzer;
+
+/**
+ * Assuming connection with the search factory
+ *
+ * @author Emmanuel Bernard
+ */
+public class ConnectedQueryContextBuilder implements QueryContextBuilder {
+ private final SearchFactory factory;
+
+ public ConnectedQueryContextBuilder(SearchFactory factory) {
+ this.factory = factory;
+ }
+
+ public EntityContext forEntity(Class<?> entityType) {
+ return new HSearchEntityContext(entityType, factory );
+ }
+
+ public final class HSearchEntityContext implements QueryContextBuilder.EntityContext {
+ private final ScopedAnalyzer queryAnalyzer;
+ private final SearchFactory factory;
+
+ public HSearchEntityContext(Class<?> entityType, SearchFactory factory) {
+ this.factory = factory;
+ queryAnalyzer = new ScopedAnalyzer();
+ queryAnalyzer.setGlobalAnalyzer( factory.getAnalyzer( entityType ) );
+ }
+
+ public EntityContext overridesForField(String field, String analyzerName) {
+ queryAnalyzer.addScopedAnalyzer( field, factory.getAnalyzer( analyzerName ) );
+ return this;
+ }
+
+ public QueryBuilder get() {
+ return new ConnectedQueryBuilder(queryAnalyzer, factory);
+ }
+ }
+}
Added: 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 (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/dsl/v2/impl/ConnectedTermContext.java 2010-03-16 18:48:40 UTC (rev 19011)
@@ -0,0 +1,172 @@
+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.Token;
+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.TermContext;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ConnectedTermContext implements TermContext {
+ private final SearchFactory factory;
+ private final Analyzer queryAnalyzer;
+
+ public ConnectedTermContext(Analyzer queryAnalyzer, SearchFactory factory) {
+ this.factory = factory;
+ this.queryAnalyzer = queryAnalyzer;
+ }
+
+ public TermMatchingContext on(String field) {
+ return new ConnectedTermMatchingContext(field, queryAnalyzer, factory);
+ }
+
+ public static class ConnectedTermMatchingContext implements TermMatchingContext {
+ private final SearchFactory factory;
+ private final String field;
+ private final Analyzer queryAnalyzer;
+
+ 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 static class ConnectedTermCustomization implements TermCustomization, TermCustomization.TermFuzzy {
+ private final SearchFactory factory;
+ private final String field;
+ private final String text;
+ private final Analyzer queryAnalyzer;
+
+ 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;
+ }
+
+ 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 Query createQuery() {
+ if ( ignoreAnalyzer ) {
+ return 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);
+ }
+
+ BooleanQuery finalQuery = new BooleanQuery();
+ for (String term : terms) {
+ Query termQuery = createTermQuery(term);
+ //termQuery.setBoost( boost );
+ finalQuery.add( termQuery, BooleanClause.Occur.SHOULD );
+ }
+ return finalQuery;
+ }
+ }
+
+ 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 {
+ Reader reader = new StringReader(text);
+ TokenStream stream = analyzer.reusableTokenStream( fieldName, reader);
+ TermAttribute attribute = (TermAttribute) stream.addAttribute( TermAttribute.class );
+ stream.reset();
+ List<String> terms = new ArrayList<String>();
+ 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
+ }
+ }
+}
More information about the hibernate-commits
mailing list