From 1a261b54fd58a993076a1625f10ddfb192cf4883 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Mon, 8 Jun 2009 10:42:01 +0000 Subject: [PATCH] Added generic support for lucene scalar functions and used the to implement CMIS Upper/Lower string functions (MOB-221) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14578 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../cmis/CMISPropertyLuceneBuilder.java | 47 +- .../cmis/mapping/AbstractProperty.java | 13 +- .../cmis/mapping/AbstractSimpleProperty.java | 35 +- .../cmis/mapping/FixedValueProperty.java | 13 +- .../cmis/mapping/ObjectIdProperty.java | 23 +- .../cmis/mapping/ObjectTypeIdProperty.java | 23 +- .../alfresco/cmis/mapping/ParentProperty.java | 15 +- .../search/CmisFunctionEvaluationContext.java | 55 +- .../org/alfresco/cmis/search/QueryTest.java | 20 + .../search/impl/lucene/LuceneFunction.java | 51 ++ .../search/impl/lucene/LuceneQueryParser.java | 587 +++++++++++++++--- .../query/CaseInsensitiveFieldQuery.java | 62 ++ .../query/CaseInsensitiveFieldRangeQuery.java | 84 +++ .../lucene/query/CaseInsensitiveTermEnum.java | 86 +++ .../query/CaseInsensitiveTermRangeEnum.java | 129 ++++ .../AlfrescoFunctionEvaluationContext.java | 59 +- .../querymodel/FunctionEvaluationContext.java | 147 ++++- .../impl/querymodel/impl/BaseComparison.java | 126 +++- .../querymodel/impl/functions/Equals.java | 2 +- .../impl/functions/GreaterThan.java | 2 +- .../impl/functions/GreaterThanOrEquals.java | 2 +- .../querymodel/impl/functions/LessThan.java | 2 +- .../impl/functions/LessThanOrEquals.java | 2 +- .../querymodel/impl/functions/NotEquals.java | 2 +- .../impl/lucene/functions/LuceneEquals.java | 2 +- .../lucene/functions/LuceneFTSPhrase.java | 5 +- .../impl/lucene/functions/LuceneFTSRange.java | 5 +- .../impl/lucene/functions/LuceneFTSTerm.java | 5 +- .../lucene/functions/LuceneGreaterThan.java | 2 +- .../functions/LuceneGreaterThanOrEquals.java | 2 +- .../impl/lucene/functions/LuceneLessThan.java | 2 +- .../functions/LuceneLessThanOrEquals.java | 2 +- .../lucene/functions/LuceneNotEquals.java | 15 +- 33 files changed, 1385 insertions(+), 242 deletions(-) create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/LuceneFunction.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldQuery.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldRangeQuery.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermEnum.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermRangeEnum.java diff --git a/source/java/org/alfresco/cmis/CMISPropertyLuceneBuilder.java b/source/java/org/alfresco/cmis/CMISPropertyLuceneBuilder.java index 3c2b9d848c..c2d4249a07 100644 --- a/source/java/org/alfresco/cmis/CMISPropertyLuceneBuilder.java +++ b/source/java/org/alfresco/cmis/CMISPropertyLuceneBuilder.java @@ -27,6 +27,7 @@ package org.alfresco.cmis; import java.io.Serializable; import java.util.Collection; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.apache.lucene.queryParser.ParseException; @@ -43,15 +44,16 @@ public interface CMISPropertyLuceneBuilder * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query * @throws ParseException */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param not - * @return + * @return the query * @throws ParseException */ public Query buildLuceneExists(LuceneQueryParser lqp, Boolean not) throws ParseException; @@ -60,24 +62,29 @@ public interface CMISPropertyLuceneBuilder * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query + * @throws ParseException */ - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query + * @throws ParseException */ - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param values * @param not * @param mode - * @return + * @return the query + * @throws ParseException */ public Query buildLuceneIn(LuceneQueryParser lqp, Collection values, Boolean not, PredicateMode mode) throws ParseException; @@ -85,40 +92,48 @@ public interface CMISPropertyLuceneBuilder * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query + * @throws ParseException */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query + * @throws ParseException */ - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param value * @param mode - * @return + * @param luceneFunction + * @return the query + * @throws ParseException */ - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException; + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; /** * @param lqp * @param value * @param not - * @return + * @return the query + * @throws ParseException */ public Query buildLuceneLike(LuceneQueryParser lqp, Serializable value, Boolean not) throws ParseException; /** - * @return + * @return the sort field */ public String getLuceneSortField(); /** + * @return the field name * */ public String getLuceneFieldName(); diff --git a/source/java/org/alfresco/cmis/mapping/AbstractProperty.java b/source/java/org/alfresco/cmis/mapping/AbstractProperty.java index 10fc62330d..44b0de12c9 100644 --- a/source/java/org/alfresco/cmis/mapping/AbstractProperty.java +++ b/source/java/org/alfresco/cmis/mapping/AbstractProperty.java @@ -29,6 +29,7 @@ import java.util.Collection; import org.alfresco.cmis.CMISPropertyAccessor; import org.alfresco.cmis.CMISPropertyLuceneBuilder; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -88,7 +89,7 @@ public abstract class AbstractProperty implements CMISPropertyAccessor, CMISProp } - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } @@ -98,12 +99,12 @@ public abstract class AbstractProperty implements CMISPropertyAccessor, CMISProp return null; } - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } @@ -113,17 +114,17 @@ public abstract class AbstractProperty implements CMISPropertyAccessor, CMISProp return null; } - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { return null; } diff --git a/source/java/org/alfresco/cmis/mapping/AbstractSimpleProperty.java b/source/java/org/alfresco/cmis/mapping/AbstractSimpleProperty.java index 5c7cdfcf9a..630e42603d 100644 --- a/source/java/org/alfresco/cmis/mapping/AbstractSimpleProperty.java +++ b/source/java/org/alfresco/cmis/mapping/AbstractSimpleProperty.java @@ -28,6 +28,7 @@ import java.io.Serializable; import java.util.Collection; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -76,9 +77,9 @@ public abstract class AbstractSimpleProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneEquality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { - return lqp.getFieldQuery(getLuceneFieldName(), getValueAsString(value), AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(getLuceneFieldName(), getValueAsString(value), AnalysisMode.IDENTIFIER, luceneFunction); } /* @@ -89,11 +90,11 @@ public abstract class AbstractSimpleProperty extends AbstractProperty { if (not) { - return lqp.getFieldQuery("ISNULL", getQNameForExists().toString(), AnalysisMode.DEFAULT); + return lqp.getFieldQuery("ISNULL", getQNameForExists().toString(), AnalysisMode.DEFAULT, LuceneFunction.FIELD); } else { - return lqp.getFieldQuery("ISNOTNULL", getQNameForExists().toString(), AnalysisMode.DEFAULT); + return lqp.getFieldQuery("ISNOTNULL", getQNameForExists().toString(), AnalysisMode.DEFAULT, LuceneFunction.FIELD); } } @@ -101,22 +102,22 @@ public abstract class AbstractSimpleProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getRangeQuery(field, stringValue, getRangeMax(), false, true, AnalysisMode.IDENTIFIER); + return lqp.getRangeQuery(field, stringValue, getRangeMax(), false, true, AnalysisMode.IDENTIFIER, luceneFunction); } /* * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getRangeQuery(field, stringValue, getRangeMax(), true, true, AnalysisMode.IDENTIFIER); + return lqp.getRangeQuery(field, stringValue, getRangeMax(), true, true, AnalysisMode.IDENTIFIER, luceneFunction); } /* @@ -149,11 +150,11 @@ public abstract class AbstractSimpleProperty extends AbstractProperty String value = asStrings.iterator().next(); if (not) { - return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } else { - return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } } else @@ -165,7 +166,7 @@ public abstract class AbstractSimpleProperty extends AbstractProperty } for (String value : asStrings) { - Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); if (not) { booleanQuery.add(any, Occur.MUST_NOT); @@ -183,33 +184,33 @@ public abstract class AbstractSimpleProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneInequality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER, luceneFunction); } /* * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getRangeQuery(field, getRangeMin(), stringValue, true, false, AnalysisMode.IDENTIFIER); + return lqp.getRangeQuery(field, getRangeMin(), stringValue, true, false, AnalysisMode.IDENTIFIER, luceneFunction); } /* * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getRangeQuery(field, getRangeMin(), stringValue, true, true, AnalysisMode.IDENTIFIER); + return lqp.getRangeQuery(field, getRangeMin(), stringValue, true, true, AnalysisMode.IDENTIFIER, luceneFunction); } /* diff --git a/source/java/org/alfresco/cmis/mapping/FixedValueProperty.java b/source/java/org/alfresco/cmis/mapping/FixedValueProperty.java index a42b03a28f..45e73ba7c2 100644 --- a/source/java/org/alfresco/cmis/mapping/FixedValueProperty.java +++ b/source/java/org/alfresco/cmis/mapping/FixedValueProperty.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -87,7 +88,7 @@ public class FixedValueProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneEquality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (EqualsHelper.nullSafeEquals(value, value)) { @@ -135,7 +136,7 @@ public class FixedValueProperty extends AbstractProperty * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ @SuppressWarnings("unchecked") - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (value instanceof Comparable) { @@ -160,7 +161,7 @@ public class FixedValueProperty extends AbstractProperty * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ @SuppressWarnings("unchecked") - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (value instanceof Comparable) { @@ -210,7 +211,7 @@ public class FixedValueProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneInequality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (!EqualsHelper.nullSafeEquals(value, value)) { @@ -227,7 +228,7 @@ public class FixedValueProperty extends AbstractProperty * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ @SuppressWarnings("unchecked") - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (value instanceof Comparable) { @@ -252,7 +253,7 @@ public class FixedValueProperty extends AbstractProperty * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ @SuppressWarnings("unchecked") - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { if (value instanceof Comparable) { diff --git a/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java b/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java index eefd6d9e22..dba8cecdc7 100644 --- a/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java +++ b/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java @@ -31,6 +31,7 @@ import org.alfresco.cmis.CMISDictionaryModel; import org.alfresco.cmis.CMISQueryException; import org.alfresco.model.ContentModel; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -112,11 +113,11 @@ public class ObjectIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneEquality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER, luceneFunction); } /* @@ -139,7 +140,7 @@ public class ObjectIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() +" can not be used in a 'greater than' comparison"); } @@ -148,7 +149,7 @@ public class ObjectIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'greater than or equals' comparison"); } @@ -183,11 +184,11 @@ public class ObjectIdProperty extends AbstractProperty String value = asStrings.iterator().next(); if (not) { - return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } else { - return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } } else @@ -199,7 +200,7 @@ public class ObjectIdProperty extends AbstractProperty } for (String value : asStrings) { - Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); if (not) { booleanQuery.add(any, Occur.MUST_NOT); @@ -217,18 +218,18 @@ public class ObjectIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneInequality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER, luceneFunction); } /* * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'less than' comparison"); } @@ -237,7 +238,7 @@ public class ObjectIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'less than or equals' comparison"); } diff --git a/source/java/org/alfresco/cmis/mapping/ObjectTypeIdProperty.java b/source/java/org/alfresco/cmis/mapping/ObjectTypeIdProperty.java index 42444f6229..04e63fd8ce 100644 --- a/source/java/org/alfresco/cmis/mapping/ObjectTypeIdProperty.java +++ b/source/java/org/alfresco/cmis/mapping/ObjectTypeIdProperty.java @@ -33,6 +33,7 @@ import org.alfresco.cmis.CMISQueryException; import org.alfresco.cmis.CMISScope; import org.alfresco.cmis.CMISTypeDefinition; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -103,12 +104,12 @@ public class ObjectTypeIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneEquality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); CMISTypeDefinition type = getServiceRegistry().getCMISDictionaryService().findType(stringValue); - return lqp.getFieldQuery(field, type.getTypeId().getQName().toString(), AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, type.getTypeId().getQName().toString(), AnalysisMode.IDENTIFIER, luceneFunction); } /* @@ -131,7 +132,7 @@ public class ObjectTypeIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'greater than' comparison"); } @@ -140,7 +141,7 @@ public class ObjectTypeIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneGreaterThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'greater than or equals' comparison"); } @@ -177,11 +178,11 @@ public class ObjectTypeIdProperty extends AbstractProperty String value = asStrings.iterator().next(); if (not) { - return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } else { - return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } } else @@ -193,7 +194,7 @@ public class ObjectTypeIdProperty extends AbstractProperty } for (String value : asStrings) { - Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); if (not) { booleanQuery.add(any, Occur.MUST_NOT); @@ -211,19 +212,19 @@ public class ObjectTypeIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneInequality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); CMISTypeDefinition type = getServiceRegistry().getCMISDictionaryService().findType(stringValue); - return lqp.getDoesNotMatchFieldQuery(field, type.getTypeId().getQName().toString(), AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, type.getTypeId().getQName().toString(), AnalysisMode.IDENTIFIER, luceneFunction); } /* * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThan(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'less than' comparison"); } @@ -232,7 +233,7 @@ public class ObjectTypeIdProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneLessThanOrEquals(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new CMISQueryException("Property " + getName() + " can not be used in a 'less than or equals' comparison"); } diff --git a/source/java/org/alfresco/cmis/mapping/ParentProperty.java b/source/java/org/alfresco/cmis/mapping/ParentProperty.java index 954c37ed6d..6a1a376440 100644 --- a/source/java/org/alfresco/cmis/mapping/ParentProperty.java +++ b/source/java/org/alfresco/cmis/mapping/ParentProperty.java @@ -29,6 +29,7 @@ import java.util.Collection; import org.alfresco.cmis.CMISDictionaryModel; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.ServiceRegistry; @@ -100,11 +101,11 @@ public class ParentProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneEquality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER, luceneFunction); } /* @@ -153,11 +154,11 @@ public class ParentProperty extends AbstractProperty String value = asStrings.iterator().next(); if (not) { - return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } else { - return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + return lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); } } else @@ -169,7 +170,7 @@ public class ParentProperty extends AbstractProperty } for (String value : asStrings) { - Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER); + Query any = lqp.getFieldQuery(field, value, AnalysisMode.IDENTIFIER, LuceneFunction.FIELD); if (not) { booleanQuery.add(any, Occur.MUST_NOT); @@ -187,11 +188,11 @@ public class ParentProperty extends AbstractProperty * (non-Javadoc) * @see org.alfresco.cmis.property.PropertyLuceneBuilder#buildLuceneInequality(org.alfresco.repo.search.impl.lucene.LuceneQueryParser, java.io.Serializable, org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { String field = getLuceneFieldName(); String stringValue = getValueAsString(value); - return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER); + return lqp.getDoesNotMatchFieldQuery(field, stringValue, AnalysisMode.IDENTIFIER, luceneFunction); } diff --git a/source/java/org/alfresco/cmis/search/CmisFunctionEvaluationContext.java b/source/java/org/alfresco/cmis/search/CmisFunctionEvaluationContext.java index 20a45731b2..5fdd43622f 100644 --- a/source/java/org/alfresco/cmis/search/CmisFunctionEvaluationContext.java +++ b/source/java/org/alfresco/cmis/search/CmisFunctionEvaluationContext.java @@ -28,16 +28,19 @@ import java.io.Serializable; import java.util.Collection; import java.util.Map; -import org.alfresco.cmis.CMISDictionaryModel; import org.alfresco.cmis.CMISDictionaryService; import org.alfresco.cmis.CMISPropertyDefinition; import org.alfresco.cmis.mapping.CMISMapping; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.repo.search.impl.querymodel.FunctionArgument; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; import org.alfresco.repo.search.impl.querymodel.PredicateMode; +import org.alfresco.repo.search.impl.querymodel.QueryModelException; +import org.alfresco.repo.search.impl.querymodel.impl.functions.Lower; +import org.alfresco.repo.search.impl.querymodel.impl.functions.Upper; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.search.Query; @@ -151,10 +154,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext this.score = score; } - public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneEquality(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneEquality(lqp, value, mode, luceneFunction); } /* @@ -176,10 +179,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext * org.alfresco.service.namespace.QName, java.io.Serializable, * org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneGreaterThan(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneGreaterThan(lqp, value, mode, luceneFunction); } /* @@ -189,10 +192,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext * org.alfresco.service.namespace.QName, java.io.Serializable, * org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneGreaterThanOrEquals(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneGreaterThanOrEquals(lqp, value, mode, luceneFunction); } /* @@ -215,10 +218,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext * org.alfresco.service.namespace.QName, java.io.Serializable, * org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneInequality(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneInequality(lqp, value, mode, luceneFunction); } /* @@ -228,10 +231,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext * org.alfresco.service.namespace.QName, java.io.Serializable, * org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneLessThan(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneLessThan(lqp, value, mode, luceneFunction); } /* @@ -241,10 +244,10 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext * org.alfresco.service.namespace.QName, java.io.Serializable, * org.alfresco.repo.search.impl.querymodel.PredicateMode) */ - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null); - return propertyDef.getPropertyLuceneBuilder().buildLuceneLessThanOrEquals(lqp, value, mode); + return propertyDef.getPropertyLuceneBuilder().buildLuceneLessThanOrEquals(lqp, value, mode, luceneFunction); } /* @@ -322,5 +325,29 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext } } + public LuceneFunction getLuceneFunction(FunctionArgument functionArgument) + { + if (functionArgument == null) + { + return LuceneFunction.FIELD; + } + else + { + String functionName = functionArgument.getFunction().getName(); + if (functionName.equals(Upper.NAME)) + { + return LuceneFunction.UPPER; + } + else if (functionName.equals(Lower.NAME)) + { + return LuceneFunction.LOWER; + } + else + { + throw new QueryModelException("Unsupported function: " + functionName); + } + } + } + } diff --git a/source/java/org/alfresco/cmis/search/QueryTest.java b/source/java/org/alfresco/cmis/search/QueryTest.java index 68a2625519..f27649bd09 100644 --- a/source/java/org/alfresco/cmis/search/QueryTest.java +++ b/source/java/org/alfresco/cmis/search/QueryTest.java @@ -1473,6 +1473,26 @@ public class QueryTest extends BaseCMISTest rs = null; } + + public void testUpperAndLower() + { + testQuery("SELECT * FROM Folder WHERE Name = 'Folder 1'", 1, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Name = 'FOLDER 1'", 0, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Name = 'folder 1'", 0, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) = 'FOLDER 1'", 1, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Lower(Name) = 'folder 1'", 1, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) = 'folder 1'", 0, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Lower(Name) = 'FOLDER 1'", 0, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) = 'Folder 1'", 0, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Lower(Name) = 'Folder 1'", 0, false, "ObjectId", new String(), false); + + testQuery("SELECT * FROM Folder WHERE Upper(Name) <> 'FOLDER 1'", 9, false, "ObjectId", new String(), false); + + testQuery("SELECT * FROM Folder WHERE Upper(Name) <= 'FOLDER 1'", 2, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) < 'FOLDER 1'", 1, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) >= 'FOLDER 1'", 9, false, "ObjectId", new String(), false); + testQuery("SELECT * FROM Folder WHERE Upper(Name) > 'FOLDER 1'", 8, false, "ObjectId", new String(), false); + } public void testAllSimpleTextPredicates() { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneFunction.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneFunction.java new file mode 100644 index 0000000000..bffbe81a85 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneFunction.java @@ -0,0 +1,51 @@ + +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene; + +/** + * Functions that can be applied to lucene fields + * + * Currently upper and lower that perform a case insensitive match for untokenised fields. + * (If the field is tokenised the match should already be case insensitive.) + * + * @author andyh + * + */ +public enum LuceneFunction +{ + /** + * Match as if the field was converted to upper case. + */ + UPPER, + /** + * Match as if the field was converted to lower case. + */ + LOWER, + /** + * A normal lucene field match. + */ + FIELD; +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java index aaf7b5b304..9c5dfa0525 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java @@ -45,7 +45,8 @@ import org.alfresco.repo.search.MLAnalysisMode; import org.alfresco.repo.search.SearcherException; import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser; import org.alfresco.repo.search.impl.lucene.analysis.MLTokenDuplicator; -import org.alfresco.repo.search.impl.lucene.analysis.VerbatimAnalyser; +import org.alfresco.repo.search.impl.lucene.query.CaseInsensitiveFieldQuery; +import org.alfresco.repo.search.impl.lucene.query.CaseInsensitiveFieldRangeQuery; import org.alfresco.repo.search.impl.lucene.query.PathQuery; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.dictionary.AspectDefinition; @@ -66,7 +67,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.TokenStream; -import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.CharStream; @@ -132,7 +132,14 @@ public class LuceneQueryParser extends QueryParser * the default field for query terms. * @param analyzer * used to find terms in the query text. + * @param namespacePrefixResolver + * @param dictionaryService + * @param tenantService + * @param defaultOperator + * @param searchParameters * @param config + * @param indexReader + * @return - the query * @throws ParseException * if the parsing fails */ @@ -161,31 +168,51 @@ public class LuceneQueryParser extends QueryParser return result; } + /** + * @param config + */ public void setLuceneConfig(LuceneConfig config) { this.config = config; } + /** + * @param indexReader + */ public void setIndexReader(IndexReader indexReader) { this.indexReader = indexReader; } + /** + * @param searchParameters + */ public void setSearchParameters(SearchParameters searchParameters) { this.searchParameters = searchParameters; } + /** + * @param namespacePrefixResolver + */ public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) { this.namespacePrefixResolver = namespacePrefixResolver; } + /** + * @param tenantService + */ public void setTenantService(TenantService tenantService) { this.tenantService = tenantService; } + /** + * Lucene default constructor + * @param arg0 + * @param arg1 + */ public LuceneQueryParser(String arg0, Analyzer arg1) { super(arg0, arg1); @@ -195,11 +222,19 @@ public class LuceneQueryParser extends QueryParser } } + /** + * Lucene default constructor + * @param arg0 + */ public LuceneQueryParser(CharStream arg0) { super(arg0); } + /** + * Lucene default constructor + * @param arg0 + */ public LuceneQueryParser(QueryParserTokenManager arg0) { super(arg0); @@ -220,12 +255,21 @@ public class LuceneQueryParser extends QueryParser } - public Query getFieldQuery(String field, String queryText, AnalysisMode analysisMode, int slop) throws ParseException + /** + * @param field + * @param queryText + * @param analysisMode + * @param slop + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query getFieldQuery(String field, String queryText, AnalysisMode analysisMode, int slop, LuceneFunction luceneFunction) throws ParseException { try { internalSlop = slop; - Query query = getFieldQuery(field, queryText, analysisMode); + Query query = getFieldQuery(field, queryText, analysisMode, luceneFunction); return query; } finally @@ -235,17 +279,32 @@ public class LuceneQueryParser extends QueryParser } + /** + * @param field + * @param sqlLikeClause + * @param analysisMode + * @return the query + * @throws ParseException + */ public Query getLikeQuery(String field, String sqlLikeClause, AnalysisMode analysisMode) throws ParseException { String luceneWildCardExpression = SearchLanguageConversion.convertSQLLikeToLucene(sqlLikeClause); - return getFieldQuery(field, luceneWildCardExpression, analysisMode); + return getFieldQuery(field, luceneWildCardExpression, analysisMode, LuceneFunction.FIELD); } - public Query getDoesNotMatchFieldQuery(String field, String queryText, AnalysisMode analysisMode) throws ParseException + /** + * @param field + * @param queryText + * @param analysisMode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query getDoesNotMatchFieldQuery(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { BooleanQuery query = new BooleanQuery(); Query allQuery = new MatchAllDocsQuery(); - Query matchQuery = getFieldQuery(field, queryText, analysisMode); + Query matchQuery = getFieldQuery(field, queryText, analysisMode, luceneFunction); if ((matchQuery != null)) { query.add(allQuery, Occur.MUST); @@ -260,9 +319,17 @@ public class LuceneQueryParser extends QueryParser public Query getFieldQuery(String field, String queryText) throws ParseException { - return getFieldQuery(field, queryText, AnalysisMode.DEFAULT); + return getFieldQuery(field, queryText, AnalysisMode.DEFAULT, LuceneFunction.FIELD); } + /** + * @param field + * @param first + * @param last + * @param slop + * @param inOrder + * @return the query + */ public Query getSpanQuery(String field, String first, String last, int slop, boolean inOrder) { if (field.equals("TEXT")) @@ -342,7 +409,15 @@ public class LuceneQueryParser extends QueryParser } - public Query getFieldQuery(String field, String queryText, AnalysisMode analysisMode) throws ParseException + /** + * @param field + * @param queryText + * @param analysisMode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query getFieldQuery(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { try { @@ -380,7 +455,7 @@ public class LuceneQueryParser extends QueryParser for (QName qname : contentAttributes) { // The super implementation will create phrase queries etc if required - Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode); + Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode, luceneFunction); if (part != null) { query.add(part, Occur.SHOULD); @@ -397,7 +472,7 @@ public class LuceneQueryParser extends QueryParser BooleanQuery query = new BooleanQuery(); for (String fieldName : text) { - Query part = getFieldQuery(fieldName, queryText, analysisMode); + Query part = getFieldQuery(fieldName, queryText, analysisMode, luceneFunction); if (part != null) { query.add(part, Occur.SHOULD); @@ -497,7 +572,7 @@ public class LuceneQueryParser extends QueryParser { throw new SearcherException("Invalid type: " + queryText); } - return getFieldQuery(target.isAspect() ? "ASPECT" : "TYPE", queryText, analysisMode); + return getFieldQuery(target.isAspect() ? "ASPECT" : "TYPE", queryText, analysisMode, luceneFunction); } else if (field.equals("TYPE")) { @@ -634,7 +709,7 @@ public class LuceneQueryParser extends QueryParser } else if (field.startsWith("@")) { - Query query = attributeQueryBuilder(field, queryText, new FieldQuery(), analysisMode); + Query query = attributeQueryBuilder(field, queryText, new FieldQuery(), analysisMode, luceneFunction); return query; } else if (field.equals("ALL")) @@ -647,7 +722,7 @@ public class LuceneQueryParser extends QueryParser for (QName qname : contentAttributes) { // The super implementation will create phrase queries etc if required - Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode); + Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode, luceneFunction); if (part != null) { query.add(part, Occur.SHOULD); @@ -664,7 +739,7 @@ public class LuceneQueryParser extends QueryParser BooleanQuery query = new BooleanQuery(); for (String fieldName : all) { - Query part = getFieldQuery(fieldName, queryText, analysisMode); + Query part = getFieldQuery(fieldName, queryText, analysisMode, luceneFunction); if (part != null) { query.add(part, Occur.SHOULD); @@ -689,7 +764,7 @@ public class LuceneQueryParser extends QueryParser QName container = containerClass.getName(); BooleanQuery query = new BooleanQuery(); String classType = containerClass.isAspect() ? "ASPECT" : "TYPE"; - Query typeQuery = getFieldQuery(classType, container.toString(), analysisMode); + Query typeQuery = getFieldQuery(classType, container.toString(), analysisMode, luceneFunction); Query presenceQuery = getWildcardQuery("@" + qname.toString(), "*"); if ((typeQuery != null) && (presenceQuery != null)) { @@ -700,7 +775,7 @@ public class LuceneQueryParser extends QueryParser } else { - return getFieldQueryImpl(field, queryText, analysisMode); + return getFieldQueryImpl(field, queryText, analysisMode, luceneFunction); } } @@ -722,7 +797,7 @@ public class LuceneQueryParser extends QueryParser } else { - return getFieldQueryImpl(field, queryText, analysisMode); + return getFieldQueryImpl(field, queryText, analysisMode, luceneFunction); } } @@ -737,7 +812,7 @@ public class LuceneQueryParser extends QueryParser QName container = containerClass.getName(); BooleanQuery query = new BooleanQuery(); String classType = containerClass.isAspect() ? "ASPECT" : "TYPE"; - Query typeQuery = getFieldQuery(classType, container.toString(), analysisMode); + Query typeQuery = getFieldQuery(classType, container.toString(), analysisMode, luceneFunction); Query presenceQuery = getWildcardQuery("@" + qname.toString(), "*"); if ((typeQuery != null) && (presenceQuery != null)) { @@ -748,7 +823,7 @@ public class LuceneQueryParser extends QueryParser } else { - return getFieldQueryImpl(field, queryText, analysisMode); + return getFieldQueryImpl(field, queryText, analysisMode, luceneFunction); } } @@ -759,7 +834,7 @@ public class LuceneQueryParser extends QueryParser for (QName qname : contentAttributes) { // The super implementation will create phrase queries etc if required - Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode); + Query part = getFieldQuery("@" + qname.toString(), queryText, analysisMode, luceneFunction); if (part != null) { query.add(part, Occur.SHOULD); @@ -778,7 +853,7 @@ public class LuceneQueryParser extends QueryParser } else { - return getFieldQueryImpl(field, queryText, analysisMode); + return getFieldQueryImpl(field, queryText, analysisMode, luceneFunction); } } @@ -789,10 +864,17 @@ public class LuceneQueryParser extends QueryParser } - private Query getFieldQueryImpl(String field, String queryText, AnalysisMode analysisMode) throws ParseException + private Query getFieldQueryImpl(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { // Use the analyzer to get all the tokens, and then build a TermQuery, - // PhraseQuery, or nothing based on the term count + // PhraseQuery, or noth + + // TODO: Untokenised columns with functions require special handling + + if (luceneFunction != LuceneFunction.FIELD) + { + throw new UnsupportedOperationException("Field queries are not supported on lucene functions (UPPER, LOWER, etc)"); + } boolean requiresMLTokenDuplication = false; String testText = queryText; @@ -1404,14 +1486,23 @@ public class LuceneQueryParser extends QueryParser */ protected Query getRangeQuery(String field, String part1, String part2, boolean inclusive) throws ParseException { - return getRangeQuery(field, part1, part2, inclusive, inclusive, AnalysisMode.DEFAULT); + return getRangeQuery(field, part1, part2, inclusive, inclusive, AnalysisMode.DEFAULT, LuceneFunction.FIELD); } /** + * @param field + * @param part1 + * @param part2 + * @param includeLower + * @param includeUpper + * @param analysisMode + * @param luceneFunction + * @return the query * @exception ParseException * throw in overridden method to disallow */ - public Query getRangeQuery(String field, String part1, String part2, boolean includeLower, boolean includeUpper, AnalysisMode analysisMode) throws ParseException + public Query getRangeQuery(String field, String part1, String part2, boolean includeLower, boolean includeUpper, AnalysisMode analysisMode, LuceneFunction luceneFunction) + throws ParseException { if (field.startsWith("@")) @@ -1433,6 +1524,44 @@ public class LuceneQueryParser extends QueryParser if (propertyDef != null) { + if (luceneFunction != LuceneFunction.FIELD) + { + if (propertyDef.getDataType().getName().equals(DataTypeDefinition.TEXT)) + { + BooleanQuery booleanQuery = new BooleanQuery(); + MLAnalysisMode mlAnalysisMode = searchParameters.getMlAnalaysisMode() == null ? config.getDefaultMLSearchAnalysisMode() : searchParameters + .getMlAnalaysisMode(); + List locales = searchParameters.getLocales(); + List expandedLocales = new ArrayList(); + for (Locale locale : (((locales == null) || (locales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : locales)) + { + expandedLocales.addAll(MLAnalysisMode.getLocales(mlAnalysisMode, locale, false)); + } + for (Locale locale : (((expandedLocales == null) || (expandedLocales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : expandedLocales)) + { + if (locale.toString().length() == 0) + { + continue; + } + + String textFieldName = fieldName; + + if (tokenisationMode == IndexTokenisationMode.BOTH) + { + textFieldName = textFieldName + "." + locale + ".sort"; + } + + addLocaleSpecificUntokenisedTextRangeFunction(field, part1, part2, includeLower, includeUpper, luceneFunction, booleanQuery, mlAnalysisMode, locale, textFieldName); + + } + return booleanQuery; + } + else + { + throw new UnsupportedOperationException("Lucene Function"); + } + } + if (propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) { throw new UnsupportedOperationException("Range is not supported against ml-text"); @@ -1620,6 +1749,72 @@ public class LuceneQueryParser extends QueryParser } } + private void addLocaleSpecificUntokenisedTextRangeFunction(String expandedFieldName, String lower, String upper, boolean includeLower, boolean includeUpper, LuceneFunction luceneFunction, BooleanQuery booleanQuery, + MLAnalysisMode mlAnalysisMode, Locale locale, String textFieldName) + { + String lowerTermText = lower; + if (locale.toString().length() > 0) + { + lowerTermText = "{" + locale + "}" + lower; + } + String upperTermText = upper; + if (locale.toString().length() > 0) + { + upperTermText = "{" + locale + "}" + upper; + } + Query subQuery = buildRangeFunctionQuery(textFieldName, lowerTermText, upperTermText, includeLower, includeUpper, luceneFunction); + booleanQuery.add(subQuery, Occur.SHOULD); + + if (booleanQuery.getClauses().length == 0) + { + booleanQuery.add(new TermQuery(new Term("NO_TOKENS", "__")), Occur.SHOULD); + } + } + + private Query buildRangeFunctionQuery(String expandedFieldName, String lowerTermText, String upperTermText, boolean includeLower, boolean includeUpper, LuceneFunction luceneFunction) + { + String testLowerTermText = lowerTermText; + if (testLowerTermText.startsWith("{")) + { + int index = lowerTermText.indexOf("}"); + testLowerTermText = lowerTermText.substring(index + 1); + } + + String testUpperTermText = upperTermText; + if (testUpperTermText.startsWith("{")) + { + int index = upperTermText.indexOf("}"); + testUpperTermText = upperTermText.substring(index + 1); + } + + switch (luceneFunction) + { + case LOWER: + if (testLowerTermText.equals(testLowerTermText.toLowerCase()) && testUpperTermText.equals(testUpperTermText.toLowerCase())) + { + return new CaseInsensitiveFieldRangeQuery(expandedFieldName, lowerTermText, upperTermText, includeLower, includeUpper); + } + else + { + // No match + return new TermQuery(new Term("NO_TOKENS", "__")); + } + case UPPER: + if (testLowerTermText.equals(testLowerTermText.toUpperCase()) && testUpperTermText.equals(testUpperTermText.toUpperCase())) + { + return new CaseInsensitiveFieldRangeQuery(expandedFieldName, lowerTermText, upperTermText, includeLower, includeUpper); + } + else + { + // No match + return new TermQuery(new Term("NO_TOKENS", "__")); + } + default: + throw new UnsupportedOperationException("Unsupported Lucene Function " + luceneFunction); + + } + } + private void addLocaleSpecificTokenisedTextRange(String part1, String part2, boolean includeLower, boolean includeUpper, AnalysisMode analysisMode, String fieldName, BooleanQuery booleanQuery, Locale locale, String textFieldName) throws ParseException { @@ -1645,7 +1840,7 @@ public class LuceneQueryParser extends QueryParser lower = "{" + locale + "}" + part1; upper = "{" + locale + "}" + part2; } - + Query subQuery = new ConstantScoreRangeQuery(textFieldName, lower, upper, includeLower, includeUpper); booleanQuery.add(subQuery, Occur.SHOULD); @@ -2394,7 +2589,7 @@ public class LuceneQueryParser extends QueryParser { if (field.startsWith("@")) { - return attributeQueryBuilder(field, termStr, new PrefixQuery(), AnalysisMode.PREFIX); + return attributeQueryBuilder(field, termStr, new PrefixQuery(), AnalysisMode.PREFIX, LuceneFunction.FIELD); } else if (field.equals("TEXT")) { @@ -2447,7 +2642,7 @@ public class LuceneQueryParser extends QueryParser { if (field.startsWith("@")) { - return attributeQueryBuilder(field, termStr, new WildcardQuery(), AnalysisMode.WILD); + return attributeQueryBuilder(field, termStr, new WildcardQuery(), AnalysisMode.WILD, LuceneFunction.FIELD); } else if (field.equals("TEXT")) @@ -2501,7 +2696,7 @@ public class LuceneQueryParser extends QueryParser { if (field.startsWith("@")) { - return attributeQueryBuilder(field, termStr, new FuzzyQuery(minSimilarity), AnalysisMode.FUZZY); + return attributeQueryBuilder(field, termStr, new FuzzyQuery(minSimilarity), AnalysisMode.FUZZY, LuceneFunction.FIELD); } else if (field.equals("TEXT")) @@ -2550,26 +2745,56 @@ public class LuceneQueryParser extends QueryParser } } + /** + * @param dictionaryService + */ public void setDictionaryService(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; } - public Query getSuperFieldQuery(String field, String queryText, AnalysisMode analysisMode) throws ParseException + /** + * @param field + * @param queryText + * @param analysisMode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query getSuperFieldQuery(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { - return getFieldQueryImpl(field, queryText, analysisMode); + return getFieldQueryImpl(field, queryText, analysisMode, luceneFunction); } + /** + * @param field + * @param termStr + * @param minSimilarity + * @return the query + * @throws ParseException + */ public Query getSuperFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException { return super.getFuzzyQuery(field, termStr, minSimilarity); } + /** + * @param field + * @param termStr + * @return the query + * @throws ParseException + */ public Query getSuperPrefixQuery(String field, String termStr) throws ParseException { return super.getPrefixQuery(field, termStr); } + /** + * @param field + * @param termStr + * @return the query + * @throws ParseException + */ public Query getSuperWildcardQuery(String field, String termStr) throws ParseException { return super.getWildcardQuery(field, termStr); @@ -2577,14 +2802,22 @@ public class LuceneQueryParser extends QueryParser interface SubQuery { - Query getQuery(String field, String queryText, AnalysisMode analysisMode) throws ParseException; + /** + * @param field + * @param queryText + * @param analysisMode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + Query getQuery(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException; } class FieldQuery implements SubQuery { - public Query getQuery(String field, String queryText, AnalysisMode analysisMode) throws ParseException + public Query getQuery(String field, String queryText, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { - return getSuperFieldQuery(field, queryText, analysisMode); + return getSuperFieldQuery(field, queryText, analysisMode, luceneFunction); } } @@ -2597,7 +2830,7 @@ public class LuceneQueryParser extends QueryParser this.minSimilarity = minSimilarity; } - public Query getQuery(String field, String termStr, AnalysisMode analysisMode) throws ParseException + public Query getQuery(String field, String termStr, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { return getSuperFuzzyQuery(field, termStr, minSimilarity); } @@ -2605,7 +2838,7 @@ public class LuceneQueryParser extends QueryParser class PrefixQuery implements SubQuery { - public Query getQuery(String field, String termStr, AnalysisMode analysisMode) throws ParseException + public Query getQuery(String field, String termStr, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { return getSuperPrefixQuery(field, termStr); } @@ -2613,13 +2846,13 @@ public class LuceneQueryParser extends QueryParser class WildcardQuery implements SubQuery { - public Query getQuery(String field, String termStr, AnalysisMode analysisMode) throws ParseException + public Query getQuery(String field, String termStr, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { return getSuperWildcardQuery(field, termStr); } } - private Query attributeQueryBuilder(String field, String queryText, SubQuery subQueryBuilder, AnalysisMode analysisMode) throws ParseException + private Query attributeQueryBuilder(String field, String queryText, SubQuery subQueryBuilder, AnalysisMode analysisMode, LuceneFunction luceneFunction) throws ParseException { // TODO: Fix duplicate token generation for mltext, content and text. // -locale expansion here and in tokeisation -> duplicates @@ -2628,43 +2861,24 @@ public class LuceneQueryParser extends QueryParser String expandedFieldName = expandAttributeFieldName(field); - // Mime type + // Get type info etc + QName propertyQName = null; if (expandedFieldName.endsWith(".mimetype")) { - QName propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 9)); - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) - { - return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); - } - + propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 9)); } else if (expandedFieldName.endsWith(".size")) { - QName propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 5)); - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) - { - return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); - } - + propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 5)); } else if (expandedFieldName.endsWith(".locale")) { - QName propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 7)); - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) - { - return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); - } - + propertyQName = QName.createQName(expandedFieldName.substring(1, expandedFieldName.length() - 7)); + } + else + { + propertyQName = QName.createQName(expandedFieldName.substring(1)); } - - // Already in expanded form - - // ML - - QName propertyQName = QName.createQName(expandedFieldName.substring(1)); PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); IndexTokenisationMode tokenisationMode = IndexTokenisationMode.TRUE; if (propertyDef != null) @@ -2676,6 +2890,44 @@ public class LuceneQueryParser extends QueryParser } } + if (luceneFunction != LuceneFunction.FIELD) + { + if ((tokenisationMode == IndexTokenisationMode.FALSE) || (tokenisationMode == IndexTokenisationMode.BOTH)) + { + return functionQueryBuilder(expandedFieldName, propertyQName, propertyDef, tokenisationMode, queryText, luceneFunction); + } + } + + // Mime type + if (expandedFieldName.endsWith(".mimetype")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); + } + + } + else if (expandedFieldName.endsWith(".size")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); + } + + } + else if (expandedFieldName.endsWith(".locale")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); + } + + } + + // Already in expanded form + + // ML + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))) { // Build a sub query for each locale and or the results together - the analysis will take care of @@ -2713,18 +2965,20 @@ public class LuceneQueryParser extends QueryParser default: case DEFAULT: case TOKENISE: - addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, booleanQuery, locale, mlFieldName); + addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, locale, mlFieldName); break; case IDENTIFIER: case FUZZY: case PREFIX: case WILD: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, mlFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + mlFieldName); break; } break; case FALSE: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, mlFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + mlFieldName); break; case TRUE: default: @@ -2734,12 +2988,13 @@ public class LuceneQueryParser extends QueryParser case DEFAULT: case TOKENISE: case IDENTIFIER: - addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, booleanQuery, locale, mlFieldName); + addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, locale, mlFieldName); break; case FUZZY: case PREFIX: case WILD: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, mlFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + mlFieldName); break; } } @@ -2758,7 +3013,7 @@ public class LuceneQueryParser extends QueryParser if (mlAnalysisMode.includesAll()) { - return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); + return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); } List locales = searchParameters.getLocales(); @@ -2771,7 +3026,7 @@ public class LuceneQueryParser extends QueryParser if (expandedLocales.size() > 0) { BooleanQuery booleanQuery = new BooleanQuery(); - Query contentQuery = subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); + Query contentQuery = subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); if (contentQuery != null) { booleanQuery.add(contentQuery, Occur.MUST); @@ -2812,7 +3067,7 @@ public class LuceneQueryParser extends QueryParser } else { - Query query = subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); + Query query = subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); if (query != null) { return query; @@ -2830,7 +3085,7 @@ public class LuceneQueryParser extends QueryParser || propertyQName.equals(ContentModel.PROP_USERNAME) || propertyQName.equals(ContentModel.PROP_AUTHORITY_NAME) || propertyQName.equals(ContentModel.PROP_MEMBERS)) { - return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode); + return subQueryBuilder.getQuery(expandedFieldName, queryText, analysisMode, luceneFunction); } BooleanQuery booleanQuery = new BooleanQuery(); @@ -2866,18 +3121,20 @@ public class LuceneQueryParser extends QueryParser default: case DEFAULT: case TOKENISE: - addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, booleanQuery, locale, textFieldName); + addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, locale, textFieldName); break; case IDENTIFIER: case FUZZY: case PREFIX: case WILD: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, textFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + textFieldName); break; } break; case FALSE: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, textFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + textFieldName); break; case TRUE: default: @@ -2886,12 +3143,13 @@ public class LuceneQueryParser extends QueryParser case DEFAULT: case TOKENISE: case IDENTIFIER: - addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, booleanQuery, locale, textFieldName); + addLocaleSpecificTokenisedMLOrTextAttribute(queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, locale, textFieldName); break; case FUZZY: case PREFIX: case WILD: - addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, booleanQuery, mlAnalysisMode, locale, textFieldName); + addLocaleSpecificUntokenisedMLOrTextAttribute(field, queryText, subQueryBuilder, analysisMode, luceneFunction, booleanQuery, mlAnalysisMode, locale, + textFieldName); break; } break; @@ -2904,7 +3162,7 @@ public class LuceneQueryParser extends QueryParser { // Sort and id is only special for MLText, text, and content // Dates are not special in this case - Query query = subQueryBuilder.getQuery(expandedFieldName, queryText, AnalysisMode.DEFAULT); + Query query = subQueryBuilder.getQuery(expandedFieldName, queryText, AnalysisMode.DEFAULT, luceneFunction); if (query != null) { return query; @@ -2917,7 +3175,7 @@ public class LuceneQueryParser extends QueryParser } private void addLocaleSpecificUntokenisedMLOrTextAttribute(String sourceField, String queryText, SubQuery subQueryBuilder, AnalysisMode analysisMode, - BooleanQuery booleanQuery, MLAnalysisMode mlAnalysisMode, Locale locale, String actualField) throws ParseException + LuceneFunction luceneFunction, BooleanQuery booleanQuery, MLAnalysisMode mlAnalysisMode, Locale locale, String actualField) throws ParseException { String termText = queryText; @@ -2925,7 +3183,7 @@ public class LuceneQueryParser extends QueryParser { termText = "{" + locale + "}" + queryText; } - Query subQuery = subQueryBuilder.getQuery(actualField, termText, analysisMode); + Query subQuery = subQueryBuilder.getQuery(actualField, termText, analysisMode, luceneFunction); booleanQuery.add(subQuery, Occur.SHOULD); if (booleanQuery.getClauses().length == 0) @@ -2934,12 +3192,12 @@ public class LuceneQueryParser extends QueryParser } } - private void addLocaleSpecificTokenisedMLOrTextAttribute(String queryText, SubQuery subQueryBuilder, AnalysisMode analysisMode, BooleanQuery booleanQuery, Locale locale, - String actualField) throws ParseException + private void addLocaleSpecificTokenisedMLOrTextAttribute(String queryText, SubQuery subQueryBuilder, AnalysisMode analysisMode, LuceneFunction luceneFunction, + BooleanQuery booleanQuery, Locale locale, String actualField) throws ParseException { StringBuilder builder = new StringBuilder(queryText.length() + 10); builder.append("\u0000").append(locale.toString()).append("\u0000").append(queryText); - Query subQuery = subQueryBuilder.getQuery(actualField, builder.toString(), analysisMode); + Query subQuery = subQueryBuilder.getQuery(actualField, builder.toString(), analysisMode, luceneFunction); if (subQuery != null) { booleanQuery.add(subQuery, Occur.SHOULD); @@ -2950,6 +3208,161 @@ public class LuceneQueryParser extends QueryParser } } + private Query functionQueryBuilder(String expandedFieldName, QName propertyQName, PropertyDefinition propertyDef, IndexTokenisationMode tokenisationMode, String queryText, + LuceneFunction luceneFunction) throws ParseException + { + + // Mime type + if (expandedFieldName.endsWith(".mimetype")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + throw new UnsupportedOperationException("Lucene Function"); + } + + } + else if (expandedFieldName.endsWith(".size")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + throw new UnsupportedOperationException("Lucene Function"); + } + + } + else if (expandedFieldName.endsWith(".locale")) + { + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + throw new UnsupportedOperationException("Lucene Function"); + } + + } + + // Already in expanded form + + // ML + + if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))) + { + // Build a sub query for each locale and or the results together - the analysis will take care of + // cross language matching for each entry + BooleanQuery booleanQuery = new BooleanQuery(); + MLAnalysisMode mlAnalysisMode = searchParameters.getMlAnalaysisMode() == null ? config.getDefaultMLSearchAnalysisMode() : searchParameters.getMlAnalaysisMode(); + List locales = searchParameters.getLocales(); + List expandedLocales = new ArrayList(); + for (Locale locale : (((locales == null) || (locales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : locales)) + { + expandedLocales.addAll(MLAnalysisMode.getLocales(mlAnalysisMode, locale, false)); + } + for (Locale locale : (((expandedLocales == null) || (expandedLocales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : expandedLocales)) + { + String mlFieldName = expandedFieldName; + + if (tokenisationMode == IndexTokenisationMode.BOTH) + { + mlFieldName = mlFieldName + "." + locale + ".sort"; + } + + addLocaleSpecificUntokenisedMLOrTextFunction(expandedFieldName, queryText, luceneFunction, booleanQuery, mlAnalysisMode, locale, mlFieldName); + + } + return booleanQuery; + } + // Content + else if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))) + { + throw new UnsupportedOperationException("Lucene functions not supported for content"); + } + else if ((propertyDef != null) && (propertyDef.getDataType().getName().equals(DataTypeDefinition.TEXT))) + { + if (propertyQName.equals(ContentModel.PROP_USER_USERNAME) + || propertyQName.equals(ContentModel.PROP_USERNAME) || propertyQName.equals(ContentModel.PROP_AUTHORITY_NAME) + || propertyQName.equals(ContentModel.PROP_MEMBERS)) + { + throw new UnsupportedOperationException("Functions are not supported agaisnt special text fields"); + } + + BooleanQuery booleanQuery = new BooleanQuery(); + MLAnalysisMode mlAnalysisMode = searchParameters.getMlAnalaysisMode() == null ? config.getDefaultMLSearchAnalysisMode() : searchParameters.getMlAnalaysisMode(); + List locales = searchParameters.getLocales(); + List expandedLocales = new ArrayList(); + for (Locale locale : (((locales == null) || (locales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : locales)) + { + expandedLocales.addAll(MLAnalysisMode.getLocales(mlAnalysisMode, locale, false)); + } + for (Locale locale : (((expandedLocales == null) || (expandedLocales.size() == 0)) ? Collections.singletonList(I18NUtil.getLocale()) : expandedLocales)) + { + String textFieldName = expandedFieldName; + + if (tokenisationMode == IndexTokenisationMode.BOTH) + { + textFieldName = textFieldName + "." + locale + ".sort"; + } + + addLocaleSpecificUntokenisedMLOrTextFunction(expandedFieldName, queryText, luceneFunction, booleanQuery, mlAnalysisMode, locale, textFieldName); + + } + return booleanQuery; + } + else + { + throw new UnsupportedOperationException("Lucene Function"); + } + } + + private void addLocaleSpecificUntokenisedMLOrTextFunction(String expandedFieldName, String queryText, LuceneFunction luceneFunction, BooleanQuery booleanQuery, + MLAnalysisMode mlAnalysisMode, Locale locale, String textFieldName) + { + String termText = queryText; + if (locale.toString().length() > 0) + { + termText = "{" + locale + "}" + queryText; + } + Query subQuery = buildFunctionQuery(textFieldName, termText, luceneFunction); + booleanQuery.add(subQuery, Occur.SHOULD); + + if (booleanQuery.getClauses().length == 0) + { + booleanQuery.add(new TermQuery(new Term("NO_TOKENS", "__")), Occur.SHOULD); + } + } + + private Query buildFunctionQuery(String expandedFieldName, String termText, LuceneFunction luceneFunction) + { + String testText = termText; + if (termText.startsWith("{")) + { + int index = termText.indexOf("}"); + testText = termText.substring(index + 1); + } + switch (luceneFunction) + { + case LOWER: + if (testText.equals(testText.toLowerCase())) + { + return new CaseInsensitiveFieldQuery(new Term(expandedFieldName, termText)); + } + else + { + // No match + return new TermQuery(new Term("NO_TOKENS", "__")); + } + case UPPER: + if (testText.equals(testText.toUpperCase())) + { + return new CaseInsensitiveFieldQuery(new Term(expandedFieldName, termText)); + } + else + { + // No match + return new TermQuery(new Term("NO_TOKENS", "__")); + } + default: + throw new UnsupportedOperationException("Unsupported Lucene Function " + luceneFunction); + + } + } + public static void main(String[] args) throws ParseException, java.text.ParseException { Query query; diff --git a/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldQuery.java b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldQuery.java new file mode 100644 index 0000000000..6abfc8081f --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldQuery.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene.query; + +import java.io.IOException; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.FilteredTermEnum; +import org.apache.lucene.search.MultiTermQuery; + +/** + * Perform a case insensitive match against a field + * + * @author andyh + * + */ +public class CaseInsensitiveFieldQuery extends MultiTermQuery +{ + /** + * + */ + private static final long serialVersionUID = -2570803495329346982L; + + /** + * @param term - the term for the match + */ + public CaseInsensitiveFieldQuery(Term term) + { + super(term); + } + + @Override + protected FilteredTermEnum getEnum(IndexReader reader) throws IOException + { + Term term = new Term(getTerm().field(), getTerm().text()); + return new CaseInsensitiveTermEnum(reader, term); + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldRangeQuery.java b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldRangeQuery.java new file mode 100644 index 0000000000..ccf07fddd0 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveFieldRangeQuery.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene.query; + +import java.io.IOException; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.FilteredTermEnum; +import org.apache.lucene.search.MultiTermQuery; + +/** + * Find terms that match a range ignoring case + * + * @author andyh + */ +public class CaseInsensitiveFieldRangeQuery extends MultiTermQuery +{ + /** + * + */ + private static final long serialVersionUID = -5859977841901861122L; + + String expandedFieldName; + + String lowerTermText; + + String upperTermText; + + boolean includeLower; + + boolean includeUpper; + + /** + * @param expandedFieldName - + * field + * @param lowerTermText - + * upper range value + * @param upperTermText - + * lower range value + * @param includeLower - + * include the lower value + * @param includeUpper - + * include the upper value + */ + public CaseInsensitiveFieldRangeQuery(String expandedFieldName, String lowerTermText, String upperTermText, boolean includeLower, boolean includeUpper) + { + super(new Term(expandedFieldName, "")); + this.expandedFieldName = expandedFieldName; + this.lowerTermText = lowerTermText; + this.upperTermText = upperTermText; + this.includeLower = includeLower; + this.includeUpper = includeUpper; + } + + @Override + protected FilteredTermEnum getEnum(IndexReader reader) throws IOException + { + return new CaseInsensitiveTermRangeEnum(reader, expandedFieldName, lowerTermText, upperTermText, includeLower, includeUpper); + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermEnum.java b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermEnum.java new file mode 100644 index 0000000000..d62fc0c5e9 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermEnum.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene.query; + +import java.io.IOException; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.FilteredTermEnum; + +/** + * A term enum to find case insensitive matches - used for Upper and Lower + * + * @author andyh + */ +public class CaseInsensitiveTermEnum extends FilteredTermEnum +{ + private String field = ""; + + private boolean endEnum = false; + + private String text; + + /** + * @param reader = + * the index reader + * @param term - + * the term to match + * @throws IOException + */ + public CaseInsensitiveTermEnum(IndexReader reader, Term term) throws IOException + { + super(); + field = term.field(); + text = term.text(); + // position at the start - we could do slightly better + setEnum(reader.terms(new Term(term.field(), ""))); + } + + @Override + public float difference() + { + return 1.0f; + } + + @Override + protected boolean endEnum() + { + return endEnum; + } + + @Override + protected boolean termCompare(Term term) + { + if (field.equals(term.field())) + { + String searchText = term.text(); + return searchText.equalsIgnoreCase(text); + } + endEnum = true; + return false; + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermRangeEnum.java b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermRangeEnum.java new file mode 100644 index 0000000000..1ea478cbc8 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/query/CaseInsensitiveTermRangeEnum.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene.query; + +import java.io.IOException; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.FilteredTermEnum; + +/** + * A term enum that finds terms that lie with in some range ignoring case + * + * @author andyh + */ +public class CaseInsensitiveTermRangeEnum extends FilteredTermEnum +{ + + private boolean endEnum = false; + + String expandedFieldName; + + String lowerTermText; + + String upperTermText; + + boolean includeLower; + + boolean includeUpper; + + /** + * @param reader + * the index reader + * @param expandedFieldName - + * field + * @param lowerTermText - + * upper range value + * @param upperTermText - + * lower range value + * @param includeLower - + * include the lower value + * @param includeUpper - + * include the upper value + * @throws IOException + */ + public CaseInsensitiveTermRangeEnum(IndexReader reader, String expandedFieldName, String lowerTermText, String upperTermText, boolean includeLower, boolean includeUpper) + throws IOException + { + super(); + this.expandedFieldName = expandedFieldName; + this.lowerTermText = lowerTermText.toLowerCase(); + this.upperTermText = upperTermText.toLowerCase(); + this.includeLower = includeLower; + this.includeUpper = includeUpper; + + setEnum(reader.terms(new Term(expandedFieldName, ""))); + } + + @Override + public float difference() + { + return 1.0f; + } + + @Override + protected boolean endEnum() + { + return endEnum; + } + + @Override + protected boolean termCompare(Term term) + { + if (expandedFieldName.equals(term.field())) + { + String searchText = term.text().toLowerCase(); + return checkLower(searchText) && checkUpper(searchText); + } + endEnum = true; + return false; + } + + private boolean checkLower(String searchText) + { + if (includeLower) + { + return (lowerTermText.compareTo(searchText) <= 0); + } + else + { + return (lowerTermText.compareTo(searchText) < 0); + } + } + + private boolean checkUpper(String searchText) + { + if (includeUpper) + { + return (upperTermText.compareTo(searchText) >= 0); + } + else + { + return (upperTermText.compareTo(searchText) > 0); + } + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/parsers/AlfrescoFunctionEvaluationContext.java b/source/java/org/alfresco/repo/search/impl/parsers/AlfrescoFunctionEvaluationContext.java index eb3ade2f86..7b8cb5646e 100644 --- a/source/java/org/alfresco/repo/search/impl/parsers/AlfrescoFunctionEvaluationContext.java +++ b/source/java/org/alfresco/repo/search/impl/parsers/AlfrescoFunctionEvaluationContext.java @@ -29,7 +29,9 @@ import java.util.Collection; import java.util.HashSet; import java.util.Map; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.repo.search.impl.querymodel.FunctionArgument; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; import org.alfresco.repo.search.impl.querymodel.PredicateMode; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -40,14 +42,19 @@ import org.alfresco.service.namespace.QName; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.search.Query; +/** + * Alfrecso function evaluation context for evaluating FTS expressions against lucene. + * @author andyh + * + */ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationContext { private static HashSet EXPOSED_FIELDS = new HashSet(); - + private NamespacePrefixResolver namespacePrefixResolver; private DictionaryService dictionaryService; - + private String defaultNamespace; static @@ -71,7 +78,12 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont EXPOSED_FIELDS.add("ISNULL"); EXPOSED_FIELDS.add("ISNOTNULL"); } - + + /** + * @param namespacePrefixResolver + * @param dictionaryService + * @param defaultNamespace + */ public AlfrescoFunctionEvaluationContext(NamespacePrefixResolver namespacePrefixResolver, DictionaryService dictionaryService, String defaultNamespace) { this.namespacePrefixResolver = namespacePrefixResolver; @@ -79,7 +91,7 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont this.defaultNamespace = defaultNamespace; } - public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } @@ -89,12 +101,12 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont throw new UnsupportedOperationException(); } - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } @@ -104,17 +116,17 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont throw new UnsupportedOperationException(); } - public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } - public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException { throw new UnsupportedOperationException(); } @@ -177,7 +189,7 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont return propertyName; } - if(propertyName.startsWith("{")) + if (propertyName.startsWith("{")) { QName qname = QName.createQName(propertyName); if (dictionaryService.getProperty(qname) != null) @@ -186,10 +198,10 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont } else { - throw new FTSQueryException("Unknown property: "+propertyName); + throw new FTSQueryException("Unknown property: " + propertyName); } } - + int index = propertyName.indexOf(':'); if (index != -1) { @@ -201,30 +213,30 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont } else { - throw new FTSQueryException("Unknown property: "+propertyName); + throw new FTSQueryException("Unknown property: " + propertyName); } } - + index = propertyName.indexOf('_'); if (index != -1) { // Try as a property, if invalid pass through - QName qname = QName.createQName(propertyName.substring(0, index), propertyName.substring(index+1), namespacePrefixResolver); + QName qname = QName.createQName(propertyName.substring(0, index), propertyName.substring(index + 1), namespacePrefixResolver); if (dictionaryService.getProperty(qname) != null) { return "@" + qname.toString(); } else { - throw new FTSQueryException("Unknown property: "+propertyName); + throw new FTSQueryException("Unknown property: " + propertyName); } } - - if(EXPOSED_FIELDS.contains(propertyName)) + + if (EXPOSED_FIELDS.contains(propertyName)) { return propertyName; } - + QName qname = QName.createQName(defaultNamespace, propertyName); if (dictionaryService.getProperty(qname) != null) { @@ -232,9 +244,14 @@ public class AlfrescoFunctionEvaluationContext implements FunctionEvaluationCont } else { - throw new FTSQueryException("Unknown property: "+propertyName); + throw new FTSQueryException("Unknown property: " + propertyName); } - + + } + + public LuceneFunction getLuceneFunction(FunctionArgument functionArgument) + { + throw new UnsupportedOperationException(); } } diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/FunctionEvaluationContext.java b/source/java/org/alfresco/repo/search/impl/querymodel/FunctionEvaluationContext.java index 62d0a0443d..69c8a8fac3 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/FunctionEvaluationContext.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/FunctionEvaluationContext.java @@ -28,53 +28,184 @@ import java.io.Serializable; import java.util.Collection; import java.util.Map; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.search.Query; /** + * The function evaluation context for lucene query implementations. + * + * This context is used at query time and also when navigating the results to get column values. + * * @author andyh */ public interface FunctionEvaluationContext { + /** + * @return the matching nodes by selector (at navigation time) + */ public Map getNodeRefs(); + /** + * @return the scores by selector (at navigation time) + */ public Map getScores(); + /** + * Get a property + * @param nodeRef + * @param propertyName + * @return the property (at navigation time) + */ public Serializable getProperty(NodeRef nodeRef, String propertyName); + /** + * @return the node service + */ public NodeService getNodeService(); + /** + * @return the score (at navigation time) + */ public Float getScore(); - public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneEquality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; + /** + * Note: null and not null are not required to support functions from the spec + * @param lqp + * @param propertyName + * @param not + * @return the query + * @throws ParseException + */ public Query buildLuceneExists(LuceneQueryParser lqp, String propertyName, Boolean not) throws ParseException; - public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneGreaterThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; - public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneGreaterThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; - public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneLessThan(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; - public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneLessThanOrEquals(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; + /** + * Note: Like is not required to support functions from the spec + * @param lqp + * @param propertyName + * @param value + * @param not + * @return the query + * @throws ParseException + */ public Query buildLuceneLike(LuceneQueryParser lqp, String propertyName, Serializable value, Boolean not) throws ParseException; - public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode) throws ParseException; + /** + * @param lqp + * @param propertyName + * @param value + * @param mode + * @param luceneFunction + * @return the query + * @throws ParseException + */ + public Query buildLuceneInequality(LuceneQueryParser lqp, String propertyName, Serializable value, PredicateMode mode, LuceneFunction luceneFunction) throws ParseException; + /** + * Note: In is not required to support functions from the spec + * @param lqp + * @param propertyName + * @param values + * @param not + * @param mode + * @return the query + * @throws ParseException + */ public Query buildLuceneIn(LuceneQueryParser lqp, String propertyName, Collection values, Boolean not, PredicateMode mode) throws ParseException; + /** + * @param propertyName + * @return the field used for sorting the given property + */ public String getLuceneSortField(String propertyName); - + + /** + * @param propertyName + * @return - is this an object id + */ public boolean isObjectId(String propertyName); + /** + * @param propertyName + * @return is this property queryable + */ public boolean isQueryable(String propertyName); + /** + * @param propertyName + * @return Is this property orderable + */ public boolean isOrderable(String propertyName); + /** + * @param propertyName + * @return the lucene field name for the property + */ public String getLuceneFieldName(String propertyName); + + /** + * @param functionArgument + * @return the lucene function appropriate to a function argument + */ + public LuceneFunction getLuceneFunction(FunctionArgument functionArgument); + + } diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/BaseComparison.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/BaseComparison.java index 722dc181b4..378bbd642c 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/BaseComparison.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/BaseComparison.java @@ -29,10 +29,13 @@ import java.util.Map; import org.alfresco.repo.search.impl.querymodel.Argument; import org.alfresco.repo.search.impl.querymodel.ArgumentDefinition; +import org.alfresco.repo.search.impl.querymodel.FunctionArgument; import org.alfresco.repo.search.impl.querymodel.Multiplicity; import org.alfresco.repo.search.impl.querymodel.PropertyArgument; import org.alfresco.repo.search.impl.querymodel.QueryModelException; import org.alfresco.repo.search.impl.querymodel.StaticArgument; +import org.alfresco.repo.search.impl.querymodel.impl.functions.Lower; +import org.alfresco.repo.search.impl.querymodel.impl.functions.Upper; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.namespace.QName; @@ -41,21 +44,32 @@ import org.alfresco.service.namespace.QName; */ public abstract class BaseComparison extends BaseFunction { + /** + * Left hand side + */ public final static String ARG_LHS = "LHS"; + /** + * Right hand side + */ public final static String ARG_RHS = "RHS"; - public static LinkedHashMap args; + /** + * Args + */ + public static LinkedHashMap ARGS; private PropertyArgument propertyArgument; - + private StaticArgument staticArgument; - + + private FunctionArgument functionArgument; + static { - args = new LinkedHashMap(); - args.put(ARG_LHS, new BaseArgumentDefinition(Multiplicity.ANY, ARG_LHS, DataTypeDefinition.ANY, true)); - args.put(ARG_RHS, new BaseArgumentDefinition(Multiplicity.ANY, ARG_RHS, DataTypeDefinition.ANY, true)); + ARGS = new LinkedHashMap(); + ARGS.put(ARG_LHS, new BaseArgumentDefinition(Multiplicity.ANY, ARG_LHS, DataTypeDefinition.ANY, true)); + ARGS.put(ARG_RHS, new BaseArgumentDefinition(Multiplicity.ANY, ARG_RHS, DataTypeDefinition.ANY, true)); } /** @@ -68,14 +82,14 @@ public abstract class BaseComparison extends BaseFunction super(name, returnType, argumentDefinitions); } - public void setPropertyAndStaticArguments(Map functionArgs) + protected void setPropertyAndStaticArguments(Map functionArgs) { Argument lhs = functionArgs.get(ARG_LHS); Argument rhs = functionArgs.get(ARG_RHS); if (lhs instanceof PropertyArgument) { - if (rhs instanceof PropertyArgument) + if ((rhs instanceof PropertyArgument) || (rhs instanceof FunctionArgument)) { throw new QueryModelException("Implicit join is not supported"); } @@ -89,9 +103,29 @@ public abstract class BaseComparison extends BaseFunction throw new QueryModelException("Argument of type " + rhs.getClass().getName() + " is not supported"); } } + else if (lhs instanceof FunctionArgument) + { + if ((rhs instanceof PropertyArgument) || (rhs instanceof FunctionArgument)) + { + throw new QueryModelException("Implicit join is not supported"); + } + else if (rhs instanceof StaticArgument) + { + functionArgument = (FunctionArgument) lhs; + staticArgument = (StaticArgument) rhs; + } + else + { + throw new QueryModelException("Argument of type " + rhs.getClass().getName() + " is not supported"); + } + } else if (rhs instanceof PropertyArgument) { - if (lhs instanceof StaticArgument) + if ((lhs instanceof PropertyArgument) || (lhs instanceof FunctionArgument)) + { + throw new QueryModelException("Implicit join is not supported"); + } + else if (lhs instanceof StaticArgument) { propertyArgument = (PropertyArgument) rhs; staticArgument = (StaticArgument) lhs; @@ -101,6 +135,22 @@ public abstract class BaseComparison extends BaseFunction throw new QueryModelException("Argument of type " + lhs.getClass().getName() + " is not supported"); } } + else if (rhs instanceof FunctionArgument) + { + if ((lhs instanceof PropertyArgument) || (lhs instanceof FunctionArgument)) + { + throw new QueryModelException("Implicit join is not supported"); + } + else if (lhs instanceof StaticArgument) + { + functionArgument = (FunctionArgument) rhs; + staticArgument = (StaticArgument) lhs; + } + else + { + throw new QueryModelException("Argument of type " + lhs.getClass().getName() + " is not supported"); + } + } else { throw new QueryModelException("Equals must have one property argument"); @@ -108,7 +158,7 @@ public abstract class BaseComparison extends BaseFunction } /** - * @return the propertyArgument + * @return the propertyArgument - there must be a property argument of a function argument */ protected PropertyArgument getPropertyArgument() { @@ -116,13 +166,63 @@ public abstract class BaseComparison extends BaseFunction } /** - * @return the staticArgument + * @return the staticArgument - must be set */ protected StaticArgument getStaticArgument() { return staticArgument; } - - + /** + * @return the functionArgument + */ + protected FunctionArgument getFunctionArgument() + { + return functionArgument; + } + + protected String getPropertyName() + { + if (propertyArgument != null) + { + return propertyArgument.getPropertyName(); + } + else if (functionArgument != null) + { + String functionName = functionArgument.getFunction().getName(); + if (functionName.equals(Upper.NAME)) + { + Argument arg = functionArgument.getFunctionArguments().get(Upper.ARG_ARG); + if (arg instanceof PropertyArgument) + { + return ((PropertyArgument) arg).getPropertyName(); + } + else + { + throw new QueryModelException("Upper must have a column argument " + arg); + } + } + else if (functionName.equals(Lower.NAME)) + { + Argument arg = functionArgument.getFunctionArguments().get(Lower.ARG_ARG); + if (arg instanceof PropertyArgument) + { + return ((PropertyArgument) arg).getPropertyName(); + } + else + { + throw new QueryModelException("Lower must have a column argument " + arg); + } + } + else + { + throw new QueryModelException("Unsupported function: " + functionName); + } + } + else + { + throw new QueryModelException("A property of function argument must be provided"); + } + } + } diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/Equals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/Equals.java index ef6fc5ec8a..9bc840a7bf 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/Equals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/Equals.java @@ -47,7 +47,7 @@ public class Equals extends BaseComparison */ public Equals() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThan.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThan.java index b46eb826b8..d0c5a931fa 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThan.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThan.java @@ -47,7 +47,7 @@ public class GreaterThan extends BaseComparison */ public GreaterThan() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThanOrEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThanOrEquals.java index 1d00169948..6ec7bfe853 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThanOrEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/GreaterThanOrEquals.java @@ -47,7 +47,7 @@ public class GreaterThanOrEquals extends BaseComparison */ public GreaterThanOrEquals() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThan.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThan.java index 163a30df37..018e827a9d 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThan.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThan.java @@ -46,7 +46,7 @@ public class LessThan extends BaseComparison */ public LessThan() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThanOrEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThanOrEquals.java index 26e3c1c413..c8ef9dfe39 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThanOrEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/LessThanOrEquals.java @@ -46,7 +46,7 @@ public class LessThanOrEquals extends BaseComparison */ public LessThanOrEquals() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/NotEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/NotEquals.java index 405f5bb684..ea16cfeb59 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/NotEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/functions/NotEquals.java @@ -46,7 +46,7 @@ public class NotEquals extends BaseComparison */ public NotEquals() { - super(NAME, DataTypeDefinition.BOOLEAN, args); + super(NAME, DataTypeDefinition.BOOLEAN, ARGS); } /* diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneEquals.java index 2a6068a931..68ac98af49 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneEquals.java @@ -65,7 +65,7 @@ public class LuceneEquals extends Equals implements LuceneQueryBuilderComponent LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - Query query = functionContext.buildLuceneEquality(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); + Query query = functionContext.buildLuceneEquality(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext.getLuceneFunction(getFunctionArgument())); if(query == null) { diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSPhrase.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSPhrase.java index eaf636167a..5a28c0feed 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSPhrase.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSPhrase.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.Argument; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; @@ -78,11 +79,11 @@ public class LuceneFTSPhrase extends FTSPhrase implements LuceneQueryBuilderComp if (propArg != null) { String prop = propArg.getPropertyName(); - query = lqp.getFieldQuery(functionContext.getLuceneFieldName(prop), term, AnalysisMode.TOKENISE, slop); + query = lqp.getFieldQuery(functionContext.getLuceneFieldName(prop), term, AnalysisMode.TOKENISE, slop, LuceneFunction.FIELD); } else { - query = lqp.getFieldQuery("TEXT", term, AnalysisMode.TOKENISE, slop); + query = lqp.getFieldQuery("TEXT", term, AnalysisMode.TOKENISE, slop, LuceneFunction.FIELD); } return query; diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSRange.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSRange.java index 5bfb6ef965..6f162908eb 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSRange.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSRange.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import org.alfresco.repo.search.impl.lucene.AnalysisMode; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.querymodel.Argument; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; @@ -78,11 +79,11 @@ public class LuceneFTSRange extends FTSRange implements LuceneQueryBuilderCompon if (propArg != null) { String prop = propArg.getPropertyName(); - query = lqp.getRangeQuery(functionContext.getLuceneFieldName(prop), from, to, fromInc, toInc, AnalysisMode.DEFAULT); + query = lqp.getRangeQuery(functionContext.getLuceneFieldName(prop), from, to, fromInc, toInc, AnalysisMode.DEFAULT, LuceneFunction.FIELD); } else { - query = lqp.getRangeQuery("TEXT", from, to, fromInc, toInc, AnalysisMode.DEFAULT); + query = lqp.getRangeQuery("TEXT", from, to, fromInc, toInc, AnalysisMode.DEFAULT, LuceneFunction.FIELD); } return query; } diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSTerm.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSTerm.java index 8bdcc6d35b..7dfebba73a 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSTerm.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneFTSTerm.java @@ -27,6 +27,7 @@ package org.alfresco.repo.search.impl.querymodel.impl.lucene.functions; import java.util.Map; import java.util.Set; +import org.alfresco.repo.search.impl.lucene.LuceneFunction; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.search.impl.lucene.AnalysisMode; import org.alfresco.repo.search.impl.querymodel.Argument; @@ -72,11 +73,11 @@ public class LuceneFTSTerm extends FTSTerm implements LuceneQueryBuilderComponen if (propArg != null) { String prop = propArg.getPropertyName(); - query = lqp.getFieldQuery(functionContext.getLuceneFieldName(prop), term, mode); + query = lqp.getFieldQuery(functionContext.getLuceneFieldName(prop), term, mode, LuceneFunction.FIELD); } else { - query = lqp.getFieldQuery("TEXT", term, mode); + query = lqp.getFieldQuery("TEXT", term, mode, LuceneFunction.FIELD); } return query; diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThan.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThan.java index e3a7ef9df7..efcfeeb5e4 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThan.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThan.java @@ -65,7 +65,7 @@ public class LuceneGreaterThan extends GreaterThan implements LuceneQueryBuilder LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - Query query = functionContext.buildLuceneGreaterThan(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); + Query query = functionContext.buildLuceneGreaterThan(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext.getLuceneFunction(getFunctionArgument())); if(query == null) { diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThanOrEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThanOrEquals.java index 4880001a97..172c1a0d88 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThanOrEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneGreaterThanOrEquals.java @@ -66,7 +66,7 @@ public class LuceneGreaterThanOrEquals extends GreaterThanOrEquals implements Lu LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - Query query = functionContext.buildLuceneGreaterThanOrEquals(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); + Query query = functionContext.buildLuceneGreaterThanOrEquals(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext.getLuceneFunction(getFunctionArgument())); if(query == null) { diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThan.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThan.java index 06ee039acb..e1f93ccd25 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThan.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThan.java @@ -66,7 +66,7 @@ public class LuceneLessThan extends LessThan implements LuceneQueryBuilderCompon LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - Query query = functionContext.buildLuceneLessThan(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); + Query query = functionContext.buildLuceneLessThan(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext.getLuceneFunction(getFunctionArgument())); if(query == null) { diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThanOrEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThanOrEquals.java index cde4020f31..1fd28ad268 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThanOrEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneLessThanOrEquals.java @@ -66,7 +66,7 @@ public class LuceneLessThanOrEquals extends LessThanOrEquals implements LuceneQu LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - Query query = functionContext.buildLuceneLessThanOrEquals(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); + Query query = functionContext.buildLuceneLessThanOrEquals(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext.getLuceneFunction(getFunctionArgument())); if(query == null) { throw new QueryModelException("No query time mapping for property "+getPropertyArgument().getPropertyName()+", it should not be allowed in predicates"); diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneNotEquals.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneNotEquals.java index 7f46cd1c3f..61f653ac70 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneNotEquals.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/functions/LuceneNotEquals.java @@ -40,7 +40,6 @@ import org.apache.lucene.search.Query; /** * @author andyh - * */ public class LuceneNotEquals extends NotEquals implements LuceneQueryBuilderComponent { @@ -65,16 +64,16 @@ public class LuceneNotEquals extends NotEquals implements LuceneQueryBuilderComp { LuceneQueryParser lqp = luceneContext.getLuceneQueryParser(); setPropertyAndStaticArguments(functionArgs); - - Query query = functionContext.buildLuceneInequality(lqp, getPropertyArgument().getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY); - - if(query == null) + + Query query = functionContext.buildLuceneInequality(lqp, getPropertyName(), getStaticArgument().getValue(functionContext), PredicateMode.ANY, functionContext + .getLuceneFunction(getFunctionArgument())); + + if (query == null) { - throw new QueryModelException("No query time mapping for property "+getPropertyArgument().getPropertyName()+", it should not be allowed in predicates"); + throw new QueryModelException("No query time mapping for property " + getPropertyArgument().getPropertyName() + ", it should not be allowed in predicates"); } - + return query; } - }