Author: rhauch
Date: 2009-11-24 19:59:30 -0500 (Tue, 24 Nov 2009)
New Revision: 1342
Modified:
trunk/dna-search/src/main/java/org/jboss/dna/search/DualIndexSearchProvider.java
trunk/dna-search/src/main/java/org/jboss/dna/search/IndexRules.java
trunk/dna-search/src/test/java/org/jboss/dna/search/IndexingRulesTest.java
trunk/dna-search/src/test/java/org/jboss/dna/search/SearchEngineTest.java
Log:
DNA-467 Changed the way IndexRules are defined to address the different datatypes,
allowing the queries to be properly created using the appropriate Lucene query objects.
Modified:
trunk/dna-search/src/main/java/org/jboss/dna/search/DualIndexSearchProvider.java
===================================================================
---
trunk/dna-search/src/main/java/org/jboss/dna/search/DualIndexSearchProvider.java 2009-11-24
21:17:39 UTC (rev 1341)
+++
trunk/dna-search/src/main/java/org/jboss/dna/search/DualIndexSearchProvider.java 2009-11-25
00:59:30 UTC (rev 1342)
@@ -74,14 +74,14 @@
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.Node;
-import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyType;
import org.jboss.dna.graph.property.ValueFactories;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.property.basic.JodaDateTime;
import org.jboss.dna.graph.query.QueryContext;
import org.jboss.dna.graph.query.QueryEngine;
import org.jboss.dna.graph.query.QueryResults;
@@ -106,6 +106,8 @@
import org.jboss.dna.graph.request.ChangeRequest;
import org.jboss.dna.graph.search.SearchException;
import org.jboss.dna.graph.search.SearchProvider;
+import org.jboss.dna.search.IndexRules.FieldType;
+import org.jboss.dna.search.IndexRules.NumericRule;
import org.jboss.dna.search.IndexRules.Rule;
import org.jboss.dna.search.LuceneSession.TupleCollector;
import org.jboss.dna.search.query.CompareLengthQuery;
@@ -133,22 +135,22 @@
public static final IndexRules DEFAULT_RULES;
static {
+ // We know that the earliest creation/modified dates cannot be before November 1
2009,
+ // which is before this feature was implemented
+ long earliestChangeDate = new JodaDateTime(2009, 11, 01, 0, 0, 0,
0).getMilliseconds();
+
IndexRules.Builder builder = IndexRules.createBuilder();
// Configure the default behavior ...
- builder.defaultTo(IndexRules.INDEX | IndexRules.FULL_TEXT | IndexRules.STORE);
+ builder.defaultTo(Field.Store.YES, Field.Index.ANALYZED);
// Configure the UUID properties to be just indexed and stored (not analyzed, not
included in full-text) ...
- builder.store(JcrLexicon.UUID, DnaLexicon.UUID);
+ builder.stringField(JcrLexicon.UUID, Field.Store.YES, Field.Index.NOT_ANALYZED);
+ builder.stringField(DnaLexicon.UUID, Field.Store.YES, Field.Index.NOT_ANALYZED);
// Configure the properties that we'll treat as dates ...
- builder.treatAsDates(JcrLexicon.CREATED, JcrLexicon.LAST_MODIFIED);
+ builder.dateField(JcrLexicon.CREATED, Field.Store.YES, Field.Index.NOT_ANALYZED,
earliestChangeDate);
+ builder.dateField(JcrLexicon.LAST_MODIFIED, Field.Store.YES,
Field.Index.NOT_ANALYZED, earliestChangeDate);
DEFAULT_RULES = builder.build();
}
- protected static final long MIN_DATE = 0;
- protected static final long MAX_DATE = Long.MAX_VALUE;
- protected static final long MIN_LONG = Long.MIN_VALUE;
- protected static final long MAX_LONG = Long.MAX_VALUE;
- protected static final double MIN_DOUBLE = Double.MIN_VALUE;
- protected static final double MAX_DOUBLE = Double.MAX_VALUE;
protected static final int MIN_DEPTH = 0;
protected static final int MAX_DEPTH = 100;
protected static final int MIN_SNS_INDEX = 1;
@@ -506,31 +508,66 @@
for (Property property : node.getProperties()) {
Name name = property.getName();
Rule rule = rules.getRule(name);
- if (!rule.isIncluded()) continue;
+ if (rule.isSkipped()) continue;
String nameString = stringFactory.create(name);
- if (rule.isDate()) {
+ FieldType type = rule.getType();
+ if (type == FieldType.DATE) {
+ boolean index = rule.getIndexOption() != Field.Index.NO;
for (Object value : property) {
if (value == null) continue;
+ // Add a separate field for each property value ...
DateTime dateValue = dateFactory.create(value);
+ long longValue = dateValue.getMillisecondsInUtc();
+ doc.add(new NumericField(nameString, rule.getStoreOption(),
index).setLongValue(longValue));
+ }
+ continue;
+ }
+ if (type ==
FieldType.INT) {
+ ValueFactory<Long> longFactory =
context.getValueFactories().getLongFactory();
+ boolean index = rule.getIndexOption() != Field.Index.NO;
+ for (Object value : property) {
+ if (value == null) continue;
// Add a separate field for each property value ...
- doc.add(new NumericField(nameString, rule.getStoreOption(),
true).setLongValue(dateValue.getMillisecondsInUtc()));
- // Dates are not added to the full-text search field (since
this wouldn't make sense)
+ int intValue = longFactory.create(value).intValue();
+ doc.add(new NumericField(nameString, rule.getStoreOption(),
index).setIntValue(intValue));
}
continue;
}
+ if (type == FieldType.DOUBLE) {
+ ValueFactory<Double> doubleFactory =
context.getValueFactories().getDoubleFactory();
+ boolean index = rule.getIndexOption() != Field.Index.NO;
+ for (Object value : property) {
+ if (value == null) continue;
+ // Add a separate field for each property value ...
+ double dValue = doubleFactory.create(value);
+ doc.add(new NumericField(nameString, rule.getStoreOption(),
index).setDoubleValue(dValue));
+ }
+ continue;
+ }
+ if (type == FieldType.FLOAT) {
+ ValueFactory<Double> doubleFactory =
context.getValueFactories().getDoubleFactory();
+ boolean index = rule.getIndexOption() != Field.Index.NO;
+ for (Object value : property) {
+ if (value == null) continue;
+ // Add a separate field for each property value ...
+ float fValue = doubleFactory.create(value).floatValue();
+ doc.add(new NumericField(nameString, rule.getStoreOption(),
index).setFloatValue(fValue));
+ }
+ continue;
+ }
+ if (type == FieldType.BINARY) {
+ // TODO : add to full-text search ...
+ continue;
+ }
+ assert type == FieldType.STRING;
for (Object value : property) {
if (value == null) continue;
- if (value instanceof Binary) {
- // don't include binary values as individual fields but
do include them in the full-text search ...
- // TODO : add to full-text search ...
- continue;
- }
stringValue = stringFactory.create(value);
// Add a separate field for each property value ...
doc.add(new Field(nameString, stringValue, rule.getStoreOption(),
rule.getIndexOption()));
- if (rule.isFullText()) {
- // Add this text to the full-text field ...
+ if (rule.getIndexOption() != Field.Index.NO) {
+ // This field is to be full-text searchable ...
if (fullTextSearchValue == null) {
fullTextSearchValue = new StringBuilder();
} else {
@@ -545,7 +582,7 @@
}
}
// Add the full-text-search field ...
- if (fullTextSearchValue != null) {
+ if (fullTextSearchValue != null && fullTextSearchValue.length()
!= 0) {
doc.add(new Field(ContentIndex.FULL_TEXT,
fullTextSearchValue.toString(), Field.Store.NO,
Field.Index.ANALYZED));
}
@@ -1121,23 +1158,22 @@
return null;
}
+ @SuppressWarnings( "unchecked" )
@Override
public Query findNodesWith( PropertyValue propertyValue,
Operator operator,
Object value,
boolean caseSensitive ) {
String field = stringFactory.create(propertyValue.getPropertyName());
- PropertyType valueType = PropertyType.discoverType(value);
+ Name fieldName = nameFactory.create(propertyValue.getPropertyName());
ValueFactories factories = context.getValueFactories();
- switch (valueType) {
- case NAME:
- case PATH:
- case REFERENCE:
- case URI:
- case UUID:
+ IndexRules.Rule rule = rules.getRule(fieldName);
+ if (rule == null || rule.isSkipped()) return new MatchNoneQuery();
+ FieldType type = rule.getType();
+ switch (type) {
case STRING:
String stringValue = stringFactory.create(value);
- if (valueType == PropertyType.PATH) {
+ if (value instanceof Path) {
stringValue = pathAsString(pathFactory.create(value),
stringFactory);
}
if (!caseSensitive) stringValue = stringValue.toLowerCase();
@@ -1178,6 +1214,7 @@
}
break;
case DATE:
+ NumericRule<Long> longRule = (NumericRule<Long>)rule;
long date = factories.getLongFactory().create(value);
switch (operator) {
case EQUAL_TO:
@@ -1186,13 +1223,13 @@
Query query = NumericRangeQuery.newLongRange(field, date,
date, true, true);
return new NotQuery(query);
case GREATER_THAN:
- return NumericRangeQuery.newLongRange(field, date, MAX_DATE,
false, true);
+ return NumericRangeQuery.newLongRange(field, date,
longRule.getMaximum(), false, true);
case GREATER_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newLongRange(field, date, MAX_DATE,
true, true);
+ return NumericRangeQuery.newLongRange(field, date,
longRule.getMaximum(), true, true);
case LESS_THAN:
- return NumericRangeQuery.newLongRange(field, MIN_DATE, date,
true, false);
+ return NumericRangeQuery.newLongRange(field,
longRule.getMinimum(), date, true, false);
case LESS_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newLongRange(field, MIN_DATE, date,
true, true);
+ return NumericRangeQuery.newLongRange(field,
longRule.getMinimum(), date, true, true);
case LIKE:
// This is not allowed ...
assert false;
@@ -1200,6 +1237,7 @@
}
break;
case LONG:
+ longRule = (NumericRule<Long>)rule;
long longValue = factories.getLongFactory().create(value);
switch (operator) {
case EQUAL_TO:
@@ -1208,21 +1246,44 @@
Query query = NumericRangeQuery.newLongRange(field,
longValue, longValue, true, true);
return new NotQuery(query);
case GREATER_THAN:
- return NumericRangeQuery.newLongRange(field, longValue,
MAX_LONG, false, true);
+ return NumericRangeQuery.newLongRange(field, longValue,
longRule.getMaximum(), false, true);
case GREATER_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newLongRange(field, longValue,
MAX_LONG, true, true);
+ return NumericRangeQuery.newLongRange(field, longValue,
longRule.getMaximum(), true, true);
case LESS_THAN:
- return NumericRangeQuery.newLongRange(field, MIN_LONG,
longValue, true, false);
+ return NumericRangeQuery.newLongRange(field,
longRule.getMinimum(), longValue, true, false);
case LESS_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newLongRange(field, MIN_LONG,
longValue, true, true);
+ return NumericRangeQuery.newLongRange(field,
longRule.getMinimum(), longValue, true, true);
case LIKE:
// This is not allowed ...
assert false;
return null;
}
break;
- case DECIMAL:
+ case INT:
+ NumericRule<Integer> intRule =
(NumericRule<Integer>)rule;
+ int intValue = factories.getLongFactory().create(value).intValue();
+ switch (operator) {
+ case EQUAL_TO:
+ return NumericRangeQuery.newIntRange(field, intValue,
intValue, true, true);
+ case NOT_EQUAL_TO:
+ Query query = NumericRangeQuery.newIntRange(field, intValue,
intValue, true, true);
+ return new NotQuery(query);
+ case GREATER_THAN:
+ return NumericRangeQuery.newIntRange(field, intValue,
intRule.getMaximum(), false, true);
+ case GREATER_THAN_OR_EQUAL_TO:
+ return NumericRangeQuery.newIntRange(field, intValue,
intRule.getMaximum(), true, true);
+ case LESS_THAN:
+ return NumericRangeQuery.newIntRange(field,
intRule.getMinimum(), intValue, true, false);
+ case LESS_THAN_OR_EQUAL_TO:
+ return NumericRangeQuery.newIntRange(field,
intRule.getMinimum(), intValue, true, true);
+ case LIKE:
+ // This is not allowed ...
+ assert false;
+ return null;
+ }
+ break;
case DOUBLE:
+ NumericRule<Double> dRule = (NumericRule<Double>)rule;
double doubleValue = factories.getDoubleFactory().create(value);
switch (operator) {
case EQUAL_TO:
@@ -1231,19 +1292,42 @@
Query query = NumericRangeQuery.newDoubleRange(field,
doubleValue, doubleValue, true, true);
return new NotQuery(query);
case GREATER_THAN:
- return NumericRangeQuery.newDoubleRange(field, doubleValue,
MAX_DOUBLE, false, true);
+ return NumericRangeQuery.newDoubleRange(field, doubleValue,
dRule.getMaximum(), false, true);
case GREATER_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newDoubleRange(field, doubleValue,
MAX_DOUBLE, true, true);
+ return NumericRangeQuery.newDoubleRange(field, doubleValue,
dRule.getMaximum(), true, true);
case LESS_THAN:
- return NumericRangeQuery.newDoubleRange(field, MIN_DOUBLE,
doubleValue, true, false);
+ return NumericRangeQuery.newDoubleRange(field,
dRule.getMinimum(), doubleValue, true, false);
case LESS_THAN_OR_EQUAL_TO:
- return NumericRangeQuery.newDoubleRange(field, MIN_DOUBLE,
doubleValue, true, true);
+ return NumericRangeQuery.newDoubleRange(field,
dRule.getMinimum(), doubleValue, true, true);
case LIKE:
// This is not allowed ...
assert false;
return null;
}
break;
+ case FLOAT:
+ NumericRule<Float> fRule = (NumericRule<Float>)rule;
+ float floatValue =
factories.getDoubleFactory().create(value).floatValue();
+ switch (operator) {
+ case EQUAL_TO:
+ return NumericRangeQuery.newFloatRange(field, floatValue,
floatValue, true, true);
+ case NOT_EQUAL_TO:
+ Query query = NumericRangeQuery.newFloatRange(field,
floatValue, floatValue, true, true);
+ return new NotQuery(query);
+ case GREATER_THAN:
+ return NumericRangeQuery.newFloatRange(field, floatValue,
fRule.getMaximum(), false, true);
+ case GREATER_THAN_OR_EQUAL_TO:
+ return NumericRangeQuery.newFloatRange(field, floatValue,
fRule.getMaximum(), true, true);
+ case LESS_THAN:
+ return NumericRangeQuery.newFloatRange(field,
fRule.getMinimum(), floatValue, true, false);
+ case LESS_THAN_OR_EQUAL_TO:
+ return NumericRangeQuery.newFloatRange(field,
fRule.getMinimum(), floatValue, true, true);
+ case LIKE:
+ // This is not allowed ...
+ assert false;
+ return null;
+ }
+ break;
case BOOLEAN:
boolean booleanValue = factories.getBooleanFactory().create(value);
stringValue = stringFactory.create(value);
@@ -1274,7 +1358,6 @@
return null;
}
break;
- case OBJECT:
case BINARY:
// This is not allowed ...
assert false;
@@ -1307,8 +1390,10 @@
Object upperValue,
boolean includesLower,
boolean includesUpper ) {
- PropertyType type = PropertyType.discoverType(lowerValue);
- assert type == PropertyType.discoverType(upperValue);
+ Name fieldName = nameFactory.create(field);
+ IndexRules.Rule rule = rules.getRule(fieldName);
+ if (rule == null || rule.isSkipped()) return new MatchNoneQuery();
+ FieldType type = rule.getType();
ValueFactories factories = context.getValueFactories();
switch (type) {
case DATE:
@@ -1319,16 +1404,27 @@
long lowerLong = factories.getLongFactory().create(lowerValue);
long upperLong = factories.getLongFactory().create(upperValue);
return NumericRangeQuery.newLongRange(field, lowerLong, upperLong,
includesLower, includesUpper);
- case DECIMAL:
case DOUBLE:
double lowerDouble =
factories.getDoubleFactory().create(lowerValue);
double upperDouble =
factories.getDoubleFactory().create(upperValue);
return NumericRangeQuery.newDoubleRange(field, lowerDouble,
upperDouble, includesLower, includesUpper);
- default:
- // This is not allowed ...
+ case FLOAT:
+ float lowerFloat =
factories.getDoubleFactory().create(lowerValue).floatValue();
+ float upperFloat =
factories.getDoubleFactory().create(upperValue).floatValue();
+ return NumericRangeQuery.newFloatRange(field, lowerFloat, upperFloat,
includesLower, includesUpper);
+ case INT:
+ int lowerInt =
factories.getLongFactory().create(lowerValue).intValue();
+ int upperInt =
factories.getLongFactory().create(upperValue).intValue();
+ return NumericRangeQuery.newIntRange(field, lowerInt, upperInt,
includesLower, includesUpper);
+ case BOOLEAN:
+ lowerInt =
factories.getBooleanFactory().create(lowerValue).booleanValue() ? 1 : 0;
+ upperInt =
factories.getBooleanFactory().create(upperValue).booleanValue() ? 1 : 0;
+ return NumericRangeQuery.newIntRange(field, lowerInt, upperInt,
includesLower, includesUpper);
+ case STRING:
+ case BINARY:
assert false;
- return null;
}
+ return new MatchNoneQuery();
}
@Override
Modified: trunk/dna-search/src/main/java/org/jboss/dna/search/IndexRules.java
===================================================================
--- trunk/dna-search/src/main/java/org/jboss/dna/search/IndexRules.java 2009-11-24
21:17:39 UTC (rev 1341)
+++ trunk/dna-search/src/main/java/org/jboss/dna/search/IndexRules.java 2009-11-25
00:59:30 UTC (rev 1342)
@@ -26,7 +26,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import org.apache.lucene.document.Field;
@@ -41,13 +40,16 @@
@Immutable
public class IndexRules {
- public static final int INDEX = 2 << 0;
- public static final int ANALYZE = 2 << 1;
- public static final int STORE = 2 << 2;
- public static final int STORE_COMPRESSED = 2 << 3;
- public static final int ANALYZED_WITHOUT_NORMS = 2 << 4;
- public static final int FULL_TEXT = 2 << 5;
- public static final int TREAT_AS_DATE = 2 << 6;
+ public static enum FieldType {
+ STRING,
+ DOUBLE,
+ FLOAT,
+ INT,
+ BOOLEAN,
+ LONG,
+ DATE,
+ BINARY;
+ }
/**
* A single rule that dictates how a single property should be indexed.
@@ -56,111 +58,49 @@
*/
@Immutable
public static interface Rule {
- /**
- * Return whether this property should be included in the indexes.
- *
- * @return true if it is to be included, or false otherwise
- */
- boolean isIncluded();
- boolean isAnalyzed();
+ boolean isSkipped();
- boolean isAnalyzedWithoutNorms();
+ FieldType getType();
- boolean isStored();
-
- boolean isStoredCompressed();
-
- boolean isFullText();
-
- boolean isDate();
-
- int getMask();
-
Field.Store getStoreOption();
Field.Index getIndexOption();
}
+ @Immutable
+ public static interface NumericRule<T> extends Rule {
+ T getMinimum();
+
+ T getMaximum();
+ }
+
public static final Rule SKIP = new SkipRule();
@Immutable
protected static class SkipRule implements Rule {
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#getMask()
- */
- public int getMask() {
- return 0;
- }
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isAnalyzed()
+ * @see org.jboss.dna.search.IndexRules.Rule#getType()
*/
- public boolean isAnalyzed() {
- return false;
+ public FieldType getType() {
+ return FieldType.STRING;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isAnalyzedWithoutNorms()
+ * @see org.jboss.dna.search.IndexRules.Rule#isSkipped()
*/
- public boolean isAnalyzedWithoutNorms() {
- return false;
+ public boolean isSkipped() {
+ return true;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isFullText()
- */
- public boolean isFullText() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isIncluded()
- */
- public boolean isIncluded() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isStored()
- */
- public boolean isStored() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isStoredCompressed()
- */
- public boolean isStoredCompressed() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isDate()
- */
- public boolean isDate() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
* @see org.jboss.dna.search.IndexRules.Rule#getIndexOption()
*/
public Index getIndexOption() {
@@ -178,128 +118,115 @@
}
@Immutable
- public static final class GeneralRule implements Rule {
- private final int value;
- private final Field.Store store;
- private final Field.Index index;
+ protected static class TypedRule implements Rule {
+ protected final FieldType type;
+ protected final Field.Store store;
+ protected final Field.Index index;
- protected GeneralRule( int value ) {
- this.value = value;
- this.index = isAnalyzed() ? Field.Index.ANALYZED : Field.Index.NOT_ANALYZED;
- this.store = isStored() ? Field.Store.YES : Field.Store.NO;
+ protected TypedRule( FieldType type,
+ Field.Store store,
+ Field.Index index ) {
+ this.type = type;
+ this.index = index;
+ this.store = store;
+ assert this.type != null;
+ assert this.index != null;
+ assert this.store != null;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#getMask()
+ * @see org.jboss.dna.search.IndexRules.Rule#getType()
*/
- public int getMask() {
- return value;
+ public FieldType getType() {
+ return type;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isAnalyzed()
+ * @see org.jboss.dna.search.IndexRules.Rule#isSkipped()
*/
- public boolean isAnalyzed() {
- return (value & ANALYZE) == ANALYZE;
+ public boolean isSkipped() {
+ return false;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isAnalyzedWithoutNorms()
+ * @see org.jboss.dna.search.IndexRules.Rule#getIndexOption()
*/
- public boolean isAnalyzedWithoutNorms() {
- return (value & ANALYZED_WITHOUT_NORMS) == ANALYZED_WITHOUT_NORMS;
+ public Index getIndexOption() {
+ return index;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isFullText()
+ * @see org.jboss.dna.search.IndexRules.Rule#getStoreOption()
*/
- public boolean isFullText() {
- return (value & FULL_TEXT) == FULL_TEXT;
+ public Store getStoreOption() {
+ return store;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isIncluded()
+ * @see java.lang.Object#toString()
*/
- public boolean isIncluded() {
- return true;
+ @Override
+ public String toString() {
+ return type.name() + " rule (" + store + "," + index +
")";
}
+ }
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isStored()
- */
- public boolean isStored() {
- return (value & STORE) == STORE;
- }
+ @Immutable
+ protected static class NumericTypedRule<T> extends TypedRule implements
NumericRule<T> {
+ protected final T minValue;
+ protected final T maxValue;
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.search.IndexRules.Rule#isStoredCompressed()
- */
- public boolean isStoredCompressed() {
- return (value & STORE_COMPRESSED) == STORE_COMPRESSED;
+ protected NumericTypedRule( FieldType type,
+ Field.Store store,
+ Field.Index index,
+ T minValue,
+ T maxValue ) {
+ super(type, store, index);
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ assert this.minValue != null;
+ assert this.maxValue != null;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#isDate()
+ * @see org.jboss.dna.search.IndexRules.NumericRule#getMaximum()
*/
- public boolean isDate() {
- return (value & TREAT_AS_DATE) == TREAT_AS_DATE;
+ public T getMaximum() {
+ return maxValue;
}
- protected Rule with( int options ) {
- return createRule(value | options);
- }
-
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#getIndexOption()
+ * @see org.jboss.dna.search.IndexRules.NumericRule#getMinimum()
*/
- public Index getIndexOption() {
- return index;
+ public T getMinimum() {
+ return minValue;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.search.IndexRules.Rule#getStoreOption()
+ * @see java.lang.Object#toString()
*/
- public Store getStoreOption() {
- return store;
+ @Override
+ public String toString() {
+ return super.toString() + " with range [" + minValue +
"," + maxValue + "]";
}
}
- private static final ConcurrentHashMap<Integer, Rule> CACHE = new
ConcurrentHashMap<Integer, Rule>();
-
- protected static Rule createRule( int value ) {
- if (value <= 0) {
- return SKIP;
- }
- Integer key = new Integer(value);
- Rule rule = CACHE.get(key);
- if (rule == null) {
- Rule newRule = new GeneralRule(value);
- rule = CACHE.putIfAbsent(value, newRule);
- if (rule == null) rule = newRule;
- }
- return rule;
- }
-
private final Map<Name, Rule> rulesByName;
private final Rule defaultRule;
@@ -327,7 +254,7 @@
* @return a builder; never null
*/
public static Builder createBuilder() {
- return new Builder(new HashMap<Name, Rule>());
+ return new Builder(new HashMap<Name, Rule>(), null);
}
/**
@@ -339,7 +266,7 @@
*/
public static Builder createBuilder( IndexRules initialRules ) {
CheckArg.isNotNull(initialRules, "initialRules");
- return new Builder(new HashMap<Name,
Rule>(initialRules.rulesByName)).defaultTo(initialRules.defaultRule);
+ return new Builder(new HashMap<Name, Rule>(initialRules.rulesByName),
initialRules.defaultRule);
}
/**
@@ -350,258 +277,357 @@
private final Map<Name, Rule> rulesByName;
private Rule defaultRule;
- Builder( Map<Name, Rule> rulesByName ) {
+ Builder( Map<Name, Rule> rulesByName,
+ Rule defaultRule ) {
assert rulesByName != null;
this.rulesByName = rulesByName;
+ this.defaultRule = defaultRule;
}
/**
- * Set the default rules.
+ * Mark the properties with the supplied names to be skipped from indexing.
*
- * @param rule the default rule to use
+ * @param namesToIndex the names of the properties that are to be skipped
* @return this builder for convenience and method chaining; never null
- * @throws IllegalArgumentException if the rule mask is negative
*/
- public Builder defaultTo( Rule rule ) {
- CheckArg.isNotNull(rule, "rule");
- defaultRule = rule;
+ public Builder skip( Name... namesToIndex ) {
+ if (namesToIndex != null) {
+ for (Name name : namesToIndex) {
+ rulesByName.put(name, SKIP);
+ }
+ }
return this;
}
/**
- * Set the default rules.
+ * Define a string-based field as the default.
*
- * @param ruleMask the bitmask of rule to use
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
* @return this builder for convenience and method chaining; never null
- * @throws IllegalArgumentException if the rule mask is negative
*/
- public Builder defaultTo( int ruleMask ) {
- CheckArg.isNonNegative(ruleMask, "options");
- if (ruleMask == 0) {
- defaultRule = SKIP;
- } else {
- // Make sure the index flag is set ...
- ruleMask |= INDEX;
- defaultRule = createRule(ruleMask);
- }
+ public Builder defaultTo( Field.Store store,
+ Field.Index index ) {
+ if (store == null) store = Field.Store.YES;
+ if (index == null) index = Field.Index.NOT_ANALYZED;
+ defaultRule = new TypedRule(FieldType.STRING, store, index);
return this;
}
/**
- * Mark the properties with the supplied names to be skipped from indexing.
+ * Define a string-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be skipped
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
* @return this builder for convenience and method chaining; never null
*/
- public Builder skip( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- rulesByName.put(name, SKIP);
- }
- }
+ public Builder stringField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ if (store == null) store = Field.Store.YES;
+ if (index == null) index = Field.Index.NOT_ANALYZED;
+ Rule rule = new TypedRule(FieldType.STRING, store, index);
+ rulesByName.put(name, rule);
return this;
}
/**
- * Set the properties with the supplied names to use the supplied rules.
+ * Define a binary-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param ruleMask the bitmask of rules to use
- * @param namesToIndex the names of the properties that are to be skipped
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
* @return this builder for convenience and method chaining; never null
- * @throws IllegalArgumentException if the rule mask is negative
*/
- public Builder set( int ruleMask,
- Name... namesToIndex ) {
- CheckArg.isNonNegative(ruleMask, "options");
- if (namesToIndex != null) {
- if (ruleMask > 0) {
- skip(namesToIndex);
- } else {
- // Make sure the index flag is set ...
- ruleMask |= INDEX;
- Rule rule = createRule(ruleMask);
- for (Name name : namesToIndex) {
- rulesByName.put(name, rule);
- }
- }
- }
+ public Builder binaryField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ if (store == null) store = Field.Store.YES;
+ if (index == null) index = Field.Index.NOT_ANALYZED;
+ Rule rule = new TypedRule(FieldType.BINARY, store, index);
+ rulesByName.put(name, rule);
return this;
}
+ protected <T> Builder numericField( Name name,
+ FieldType type,
+ Field.Store store,
+ Field.Index index,
+ T minValue,
+ T maxValue ) {
+ if (store == null) store = Field.Store.YES;
+ if (index == null) index = Field.Index.NOT_ANALYZED;
+ Rule rule = new NumericTypedRule<T>(type, store, index, minValue,
maxValue);
+ rulesByName.put(name, rule);
+ return this;
+ }
+
/**
- * Mark the properties with the supplied names to use the supplied rule mask.
This does not remove any other rules for
- * these properties.
+ * Define a boolean-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param ruleMask the bitmask of rules to add
- * @param namesToIndex the names of the properties that are to be skipped
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
* @return this builder for convenience and method chaining; never null
- * @throws IllegalArgumentException if the rule mask is negative
*/
- public Builder add( int ruleMask,
- Name... namesToIndex ) {
- CheckArg.isNonNegative(ruleMask, "options");
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, ruleMask);
- }
- }
- return this;
+ public Builder booleanField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return numericField(name, FieldType.BOOLEAN, store, index, Boolean.FALSE,
Boolean.TRUE);
}
/**
- * Mark the properties with the supplied names to be indexed. This does not
remove any other rules for these properties.
+ * Define a integer-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be indexed
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @param maxValue the maximum value for this field, or null if there is no
maximum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder index( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, INDEX);
- }
- }
- return this;
+ public Builder integerField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Integer minValue,
+ Integer maxValue ) {
+ if (minValue == null) minValue = Integer.MIN_VALUE;
+ if (maxValue == null) maxValue = Integer.MAX_VALUE;
+ return numericField(name,
FieldType.INT, store, index, minValue, maxValue);
}
/**
- * Mark the properties with the supplied names to be analyzed (and obviously
indexed). This does not remove any other
- * rules for these properties.
+ * Define a long-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be analyzed
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @param maxValue the maximum value for this field, or null if there is no
maximum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder analyze( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, ANALYZE | INDEX);
- }
- }
- return this;
+ public Builder longField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Long minValue,
+ Long maxValue ) {
+ if (minValue == null) minValue = Long.MIN_VALUE;
+ if (maxValue == null) maxValue = Long.MAX_VALUE;
+ return numericField(name, FieldType.LONG, store, index, minValue, maxValue);
}
/**
- * Mark the properties with the supplied names to be stored (and obviously
indexed). This does not remove any other rules
- * for these properties.
+ * Define a date-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be stored
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @param maxValue the maximum value for this field, or null if there is no
maximum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder store( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, STORE | INDEX);
- }
- }
- return this;
+ public Builder dateField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Long minValue,
+ Long maxValue ) {
+ if (minValue == null) minValue = 0L;
+ if (maxValue == null) maxValue = Long.MAX_VALUE;
+ return numericField(name, FieldType.DATE, store, index, minValue, maxValue);
}
/**
- * Mark the properties with the supplied names to be included in full-text
searches (and obviously indexed). This does not
- * remove any other rules for these properties.
+ * Define a float-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be included in
full-text searches
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @param maxValue the maximum value for this field, or null if there is no
maximum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder fullText( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, FULL_TEXT | INDEX);
- }
- }
- return this;
+ public Builder floatField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Float minValue,
+ Float maxValue ) {
+ if (minValue == null) minValue = Float.MIN_VALUE;
+ if (maxValue == null) maxValue = Float.MAX_VALUE;
+ return numericField(name, FieldType.FLOAT, store, index, minValue,
maxValue);
}
/**
- * Mark the properties with the supplied names to be treated as dates (and
obviously indexed). This does not remove any
- * other rules for these properties.
+ * Define a double-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be included in
full-text searches
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @param maxValue the maximum value for this field, or null if there is no
maximum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder treatAsDates( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, TREAT_AS_DATE | INDEX);
- }
- }
- return this;
+ public Builder doubleField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Double minValue,
+ Double maxValue ) {
+ if (minValue == null) minValue = Double.MIN_VALUE;
+ if (maxValue == null) maxValue = Double.MAX_VALUE;
+ return numericField(name, FieldType.DOUBLE, store, index, minValue,
maxValue);
}
/**
- * Mark the properties with the supplied names to be indexed, analyzed and
stored. This does not remove any other rules
- * for these properties.
+ * Define a integer-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be indexed,
analyzed and stored
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder analyzeAndStore( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, INDEX | ANALYZE | STORE);
- }
- }
- return this;
+ public Builder integerField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Integer minValue ) {
+ return integerField(name, store, index, minValue, null);
}
/**
- * Mark the properties with the supplied names to be indexed, analyzed, stored
and included in full-text searches. This
- * does not remove any other rules for these properties.
+ * Define a long-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be indexed,
analyzed, stored and included in full-text
- * searches
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder analyzeAndStoreAndFullText( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, INDEX | ANALYZE | STORE | FULL_TEXT);
- }
- }
- return this;
+ public Builder longField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Long minValue ) {
+ return longField(name, store, index, minValue, null);
}
/**
- * Mark the properties with the supplied names to be indexed, analyzed and
included in full-text searches. This does not
- * remove any other rules for these properties.
+ * Define a date-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be indexed,
analyzed and included in full-text searches
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder analyzeAndFullText( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, INDEX | ANALYZE | FULL_TEXT);
- }
- }
- return this;
+ public Builder dateField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Long minValue ) {
+ return dateField(name, store, index, minValue, null);
}
/**
- * Mark the properties with the supplied names to be indexed, stored and included
in full-text searches. This does not
- * remove any other rules for these properties.
+ * Define a float-based field in the indexes. This method will overwrite any
existing definition in this builder.
*
- * @param namesToIndex the names of the properties that are to be indexed, stored
and included in full-text searches
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
* @return this builder for convenience and method chaining; never null
*/
- public Builder storeAndFullText( Name... namesToIndex ) {
- if (namesToIndex != null) {
- for (Name name : namesToIndex) {
- add(name, INDEX | STORE | FULL_TEXT);
- }
- }
- return this;
+ public Builder floatField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Float minValue ) {
+ return floatField(name, store, index, minValue, null);
}
- protected void add( Name name,
- int option ) {
- Rule rule = rulesByName.get(name);
- if (rule != null) {
- option |= rule.getMask();
- }
- rulesByName.put(name, createRule(option));
+ /**
+ * Define a double-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @param minValue the minimum value for this field, or null if there is no
minimum value
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder doubleField( Name name,
+ Field.Store store,
+ Field.Index index,
+ Double minValue ) {
+ return doubleField(name, store, index, minValue, null);
}
/**
+ * Define a integer-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder integerField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return integerField(name, store, index, null, null);
+ }
+
+ /**
+ * Define a long-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder longField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return longField(name, store, index, null, null);
+ }
+
+ /**
+ * Define a date-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder dateField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return dateField(name, store, index, null, null);
+ }
+
+ /**
+ * Define a float-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder floatField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return floatField(name, store, index, null, null);
+ }
+
+ /**
+ * Define a double-based field in the indexes. This method will overwrite any
existing definition in this builder.
+ *
+ * @param name the name of the field
+ * @param store the storage setting, or null if the field should be {@link
Store#YES stored}
+ * @param index the index setting, or null if the field should be indexed but
{@link Index#NOT_ANALYZED not analyzed}
+ * @return this builder for convenience and method chaining; never null
+ */
+ public Builder doubleField( Name name,
+ Field.Store store,
+ Field.Index index ) {
+ return doubleField(name, store, index, null, null);
+ }
+
+ /**
* Build the indexing rules.
*
* @return the immutable indexing rules.
Modified: trunk/dna-search/src/test/java/org/jboss/dna/search/IndexingRulesTest.java
===================================================================
--- trunk/dna-search/src/test/java/org/jboss/dna/search/IndexingRulesTest.java 2009-11-24
21:17:39 UTC (rev 1341)
+++ trunk/dna-search/src/test/java/org/jboss/dna/search/IndexingRulesTest.java 2009-11-25
00:59:30 UTC (rev 1342)
@@ -25,6 +25,7 @@
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
+import org.apache.lucene.document.Field;
import org.jboss.dna.search.IndexRules.Builder;
import org.junit.Before;
import org.junit.Test;
@@ -51,8 +52,9 @@
@Test
public void shouldBuildValidRulesFromBuilderAfterJustSettingDefaultRules() {
- builder.defaultTo(IndexRules.FULL_TEXT);
+ builder.defaultTo(Field.Store.NO, Field.Index.ANALYZED_NO_NORMS);
rules = builder.build();
- assertThat(rules.getRule(null).isFullText(), is(true));
+ assertThat(rules.getRule(null).getIndexOption(),
is(Field.Index.ANALYZED_NO_NORMS));
+ assertThat(rules.getRule(null).getStoreOption(), is(Field.Store.NO));
}
}
Modified: trunk/dna-search/src/test/java/org/jboss/dna/search/SearchEngineTest.java
===================================================================
--- trunk/dna-search/src/test/java/org/jboss/dna/search/SearchEngineTest.java 2009-11-24
21:17:39 UTC (rev 1341)
+++ trunk/dna-search/src/test/java/org/jboss/dna/search/SearchEngineTest.java 2009-11-25
00:59:30 UTC (rev 1342)
@@ -29,6 +29,7 @@
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.List;
+import org.apache.lucene.document.Field;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.Location;
@@ -47,7 +48,6 @@
import org.jboss.dna.graph.search.SearchEngine;
import org.jboss.dna.graph.search.SearchProvider;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.xml.sax.SAXException;
@@ -93,6 +93,12 @@
// Set up the provider and the search engine ...
IndexRules.Builder rulesBuilder =
IndexRules.createBuilder(DualIndexSearchProvider.DEFAULT_RULES);
+ rulesBuilder.defaultTo(Field.Store.YES, Field.Index.NOT_ANALYZED);
+ rulesBuilder.stringField(name("model"), Field.Store.YES,
Field.Index.ANALYZED);
+ rulesBuilder.integerField(name("year"), Field.Store.YES,
Field.Index.NOT_ANALYZED);
+ rulesBuilder.floatField(name("userRating"), Field.Store.YES,
Field.Index.NOT_ANALYZED, 0.0f, 10.0f);
+ rulesBuilder.integerField(name("mpgCity"), Field.Store.YES,
Field.Index.NOT_ANALYZED, 0, 50);
+ rulesBuilder.integerField(name("mpgHighway"), Field.Store.YES,
Field.Index.NOT_ANALYZED, 0, 50);
// rulesBuilder.analyzeAndStoreAndFullText(name("maker"));
IndexRules rules = rulesBuilder.build();
LuceneConfiguration luceneConfig = LuceneConfigurations.inMemory();
@@ -103,7 +109,7 @@
// Create the schemata for the workspaces ...
schemata = ImmutableSchemata.createBuilder(typeSystem)
- .addTable("__ALLNODES__",
"maker", "model", "year", "msrp")
+ .addTable("__ALLNODES__",
"maker", "model", "year", "msrp",
"mpgHighway", "mpgCity")
.makeSearchable("__ALLNODES__",
"maker")
.build();
@@ -242,6 +248,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM
__ALLNODES__", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(18));
System.out.println(results);
@@ -252,19 +259,21 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE maker = 'Toyota'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);
}
- @Ignore
@Test
public void shouldFindNodesBySimpleQueryWithGreaterThanComparisonCriteria() {
engine.index(workspaceName1, path("/"), 100);
- QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE mpgHighway > 20", typeSystem);
+ QueryCommand query = sql.parseQuery("SELECT model, maker, mpgHighway,
mpgCity FROM __ALLNODES__ WHERE mpgHighway > 20",
+ typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
- assertThat(results.getRowCount(), is(2));
+ assertThat(results.getRowCount(), is(6));
System.out.println(results);
}
@@ -273,6 +282,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE LOWER(maker) = 'toyota'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);
@@ -283,6 +293,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE UPPER(maker) = 'TOYOTA'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);
@@ -293,6 +304,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE maker LIKE 'Toyo%'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);
@@ -303,6 +315,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE maker LIKE '%yota'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);
@@ -313,6 +326,7 @@
engine.index(workspaceName1, path("/"), 100);
QueryCommand query = sql.parseQuery("SELECT model, maker FROM __ALLNODES__
WHERE LOWER(maker) LIKE 'toyo%'", typeSystem);
QueryResults results = engine.query(context, workspaceName1, query, schemata);
+ assertNoErrors(results);
assertThat(results, is(notNullValue()));
assertThat(results.getRowCount(), is(2));
System.out.println(results);