This commit is contained in:
Karl Wright 2017-09-12 08:34:52 -04:00
commit b125107b7c
22 changed files with 248 additions and 152 deletions

View File

@ -129,6 +129,8 @@ Bug Fixes
* SOLR-10101: TestLazyCores hangs (Erick Erickson) * SOLR-10101: TestLazyCores hangs (Erick Erickson)
* SOLR-11332: Fix sorting on 'enum' fieldTypes that use sortMissingFirst or sortMissingLast (hossman)
Optimizations Optimizations
---------------------- ----------------------
@ -199,6 +201,10 @@ Other Changes
* SOLR-10990: Breakup QueryComponent.process method for readability. (Christine Poerschke) * SOLR-10990: Breakup QueryComponent.process method for readability. (Christine Poerschke)
* SOLR-11132: Refactor common getSortField logic in various FieldTypes (Jason Gerlowski, hossman)
* SOLR-11351: Make LTRScoringModel model more extensible. (Christine Poerschke)
================== 7.0.0 ================== ================== 7.0.0 ==================
Versions of Major Components Versions of Major Components

View File

@ -80,7 +80,7 @@ public abstract class LTRScoringModel {
protected final List<Feature> features; protected final List<Feature> features;
private final List<Feature> allFeatures; private final List<Feature> allFeatures;
private final Map<String,Object> params; private final Map<String,Object> params;
private final List<Normalizer> norms; protected final List<Normalizer> norms;
public static LTRScoringModel getInstance(SolrResourceLoader solrResourceLoader, public static LTRScoringModel getInstance(SolrResourceLoader solrResourceLoader,
String className, String name, List<Feature> features, String className, String name, List<Feature> features,
@ -123,6 +123,8 @@ public abstract class LTRScoringModel {
* {@link ModelException} if they do not make sense. * {@link ModelException} if they do not make sense.
*/ */
protected void validate() throws ModelException { protected void validate() throws ModelException {
final List<Feature> features = getFeatures();
final List<Normalizer> norms = getNorms();
if (features.isEmpty()) { if (features.isEmpty()) {
throw new ModelException("no features declared for model "+name); throw new ModelException("no features declared for model "+name);
} }

View File

@ -239,12 +239,14 @@ public class TestRerankBase extends RestTestBase {
.append(",\n"); .append(",\n");
sb.append("\"class\":").append('"').append(type).append('"').append(",\n"); sb.append("\"class\":").append('"').append(type).append('"').append(",\n");
sb.append("\"features\":").append('['); sb.append("\"features\":").append('[');
for (final String feature : features) { if (features.length > 0) {
sb.append("\n\t{ "); for (final String feature : features) {
sb.append("\"name\":").append('"').append(feature).append('"') sb.append("\n\t{ ");
.append("},"); sb.append("\"name\":").append('"').append(feature).append('"')
.append("},");
}
sb.deleteCharAt(sb.length() - 1);
} }
sb.deleteCharAt(sb.length() - 1);
sb.append("\n]\n"); sb.append("\n]\n");
if (params != null) { if (params != null) {
sb.append(",\n"); sb.append(",\n");

View File

@ -296,6 +296,7 @@ public class StreamHandler extends RequestHandlerBase implements SolrCoreAware,
.withFunctionName("probability", ProbabilityEvaluator.class) .withFunctionName("probability", ProbabilityEvaluator.class)
.withFunctionName("sumDifference", SumDifferenceEvaluator.class) .withFunctionName("sumDifference", SumDifferenceEvaluator.class)
.withFunctionName("meanDifference", MeanDifferenceEvaluator.class) .withFunctionName("meanDifference", MeanDifferenceEvaluator.class)
.withFunctionName("primes", PrimesEvaluator.class)
// Boolean Stream Evaluators // Boolean Stream Evaluators

View File

@ -357,14 +357,14 @@ public class QueryComponent extends SearchComponent
cmd.setSegmentTerminateEarly(false); // not supported, silently ignore any segmentTerminateEarly flag cmd.setSegmentTerminateEarly(false); // not supported, silently ignore any segmentTerminateEarly flag
try { try {
if (params.getBool(GroupParams.GROUP_DISTRIBUTED_FIRST, false)) { if (params.getBool(GroupParams.GROUP_DISTRIBUTED_FIRST, false)) {
doProcessGroupedDistributedSearchFirstPhase(rb, result); doProcessGroupedDistributedSearchFirstPhase(rb, cmd, result);
return; return;
} else if (params.getBool(GroupParams.GROUP_DISTRIBUTED_SECOND, false)) { } else if (params.getBool(GroupParams.GROUP_DISTRIBUTED_SECOND, false)) {
doProcessGroupedDistributedSearchSecondPhase(rb, result); doProcessGroupedDistributedSearchSecondPhase(rb, cmd, result);
return; return;
} }
doProcessGroupedSearch(rb, result); doProcessGroupedSearch(rb, cmd, result);
return; return;
} catch (SyntaxError e) { } catch (SyntaxError e) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
@ -372,7 +372,7 @@ public class QueryComponent extends SearchComponent
} }
// normal search result // normal search result
doProcessUngroupedSearch(rb, result); doProcessUngroupedSearch(rb, cmd, result);
} }
protected void doFieldSortValues(ResponseBuilder rb, SolrIndexSearcher searcher) throws IOException protected void doFieldSortValues(ResponseBuilder rb, SolrIndexSearcher searcher) throws IOException
@ -1248,7 +1248,7 @@ public class QueryComponent extends SearchComponent
return true; return true;
} }
private void doProcessGroupedDistributedSearchFirstPhase(ResponseBuilder rb, QueryResult result) throws IOException { private void doProcessGroupedDistributedSearchFirstPhase(ResponseBuilder rb, QueryCommand cmd, QueryResult result) throws IOException {
GroupingSpecification groupingSpec = rb.getGroupingSpec(); GroupingSpecification groupingSpec = rb.getGroupingSpec();
assert null != groupingSpec : "GroupingSpecification is null"; assert null != groupingSpec : "GroupingSpecification is null";
@ -1259,8 +1259,6 @@ public class QueryComponent extends SearchComponent
SolrIndexSearcher searcher = req.getSearcher(); SolrIndexSearcher searcher = req.getSearcher();
IndexSchema schema = searcher.getSchema(); IndexSchema schema = searcher.getSchema();
QueryCommand cmd = rb.getQueryCommand();
CommandHandler.Builder topsGroupsActionBuilder = new CommandHandler.Builder() CommandHandler.Builder topsGroupsActionBuilder = new CommandHandler.Builder()
.setQueryCommand(cmd) .setQueryCommand(cmd)
.setNeedDocSet(false) // Order matters here .setNeedDocSet(false) // Order matters here
@ -1286,7 +1284,7 @@ public class QueryComponent extends SearchComponent
rb.setResult(result); rb.setResult(result);
} }
private void doProcessGroupedDistributedSearchSecondPhase(ResponseBuilder rb, QueryResult result) throws IOException, SyntaxError { private void doProcessGroupedDistributedSearchSecondPhase(ResponseBuilder rb, QueryCommand cmd, QueryResult result) throws IOException, SyntaxError {
GroupingSpecification groupingSpec = rb.getGroupingSpec(); GroupingSpecification groupingSpec = rb.getGroupingSpec();
assert null != groupingSpec : "GroupingSpecification is null"; assert null != groupingSpec : "GroupingSpecification is null";
@ -1299,7 +1297,6 @@ public class QueryComponent extends SearchComponent
SolrIndexSearcher searcher = req.getSearcher(); SolrIndexSearcher searcher = req.getSearcher();
IndexSchema schema = searcher.getSchema(); IndexSchema schema = searcher.getSchema();
QueryCommand cmd = rb.getQueryCommand();
boolean needScores = (cmd.getFlags() & SolrIndexSearcher.GET_SCORES) != 0; boolean needScores = (cmd.getFlags() & SolrIndexSearcher.GET_SCORES) != 0;
CommandHandler.Builder secondPhaseBuilder = new CommandHandler.Builder() CommandHandler.Builder secondPhaseBuilder = new CommandHandler.Builder()
@ -1358,7 +1355,7 @@ public class QueryComponent extends SearchComponent
rb.setResult(result); rb.setResult(result);
} }
private void doProcessGroupedSearch(ResponseBuilder rb, QueryResult result) throws IOException, SyntaxError { private void doProcessGroupedSearch(ResponseBuilder rb, QueryCommand cmd, QueryResult result) throws IOException, SyntaxError {
GroupingSpecification groupingSpec = rb.getGroupingSpec(); GroupingSpecification groupingSpec = rb.getGroupingSpec();
assert null != groupingSpec : "GroupingSpecification is null"; assert null != groupingSpec : "GroupingSpecification is null";
@ -1370,8 +1367,6 @@ public class QueryComponent extends SearchComponent
SolrIndexSearcher searcher = req.getSearcher(); SolrIndexSearcher searcher = req.getSearcher();
QueryCommand cmd = rb.getQueryCommand();
int maxDocsPercentageToCache = params.getInt(GroupParams.GROUP_CACHE_PERCENTAGE, 0); int maxDocsPercentageToCache = params.getInt(GroupParams.GROUP_CACHE_PERCENTAGE, 0);
boolean cacheSecondPassSearch = maxDocsPercentageToCache >= 1 && maxDocsPercentageToCache <= 100; boolean cacheSecondPassSearch = maxDocsPercentageToCache >= 1 && maxDocsPercentageToCache <= 100;
Grouping.TotalCount defaultTotalCount = groupingSpec.isIncludeGroupCount() ? Grouping.TotalCount defaultTotalCount = groupingSpec.isIncludeGroupCount() ?
@ -1430,15 +1425,13 @@ public class QueryComponent extends SearchComponent
} }
} }
private void doProcessUngroupedSearch(ResponseBuilder rb, QueryResult result) throws IOException { private void doProcessUngroupedSearch(ResponseBuilder rb, QueryCommand cmd, QueryResult result) throws IOException {
SolrQueryRequest req = rb.req; SolrQueryRequest req = rb.req;
SolrQueryResponse rsp = rb.rsp; SolrQueryResponse rsp = rb.rsp;
SolrIndexSearcher searcher = req.getSearcher(); SolrIndexSearcher searcher = req.getSearcher();
QueryCommand cmd = rb.getQueryCommand();
searcher.search(result, cmd); searcher.search(result, cmd);
rb.setResult(result); rb.setResult(result);

View File

@ -250,11 +250,12 @@ public abstract class AbstractEnumField extends PrimitiveFieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); SortField result = getSortField(field, SortField.Type.INT, top, Integer.MIN_VALUE, Integer.MAX_VALUE);
final Object missingValue = Integer.MIN_VALUE; if (null == result.getMissingValue()) {
SortField sf = new SortField(field.getName(), SortField.Type.INT, top); // special case default behavior: assume missing values are "below" all enum values
sf.setMissingValue(missingValue); result.setMissingValue(Integer.MIN_VALUE);
return sf; }
return result;
} }
@Override @Override

View File

@ -190,20 +190,7 @@ public class DatePointField extends PointField implements DateValueFieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortField(field, SortField.Type.LONG, top, Long.MIN_VALUE, Long.MAX_VALUE);
Object missingValue = null;
boolean sortMissingLast = field.sortMissingLast();
boolean sortMissingFirst = field.sortMissingFirst();
if (sortMissingLast) {
missingValue = top ? Long.MIN_VALUE : Long.MAX_VALUE;
} else if (sortMissingFirst) {
missingValue = top ? Long.MAX_VALUE : Long.MIN_VALUE;
}
SortField sf = new SortField(field.getName(), SortField.Type.LONG, top);
sf.setMissingValue(missingValue);
return sf;
} }
@Override @Override

View File

@ -134,20 +134,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortField(field, SortField.Type.DOUBLE, top, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
Object missingValue = null;
boolean sortMissingLast = field.sortMissingLast();
boolean sortMissingFirst = field.sortMissingFirst();
if (sortMissingLast) {
missingValue = top ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
} else if (sortMissingFirst) {
missingValue = top ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
}
SortField sf = new SortField(field.getName(), SortField.Type.DOUBLE, top);
sf.setMissingValue(missingValue);
return sf;
} }
@Override @Override

View File

@ -48,6 +48,7 @@ import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedSetSortField;
import org.apache.lucene.search.SortedNumericSelector; import org.apache.lucene.search.SortedNumericSelector;
import org.apache.lucene.search.SortedSetSelector; import org.apache.lucene.search.SortedSetSelector;
import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.search.TermInSetQuery;
@ -69,7 +70,6 @@ import org.apache.solr.query.SolrRangeQuery;
import org.apache.solr.response.TextResponseWriter; import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.search.QParser; import org.apache.solr.search.QParser;
import org.apache.solr.search.QueryUtils; import org.apache.solr.search.QueryUtils;
import org.apache.solr.search.Sorting;
import org.apache.solr.uninverting.UninvertingReader; import org.apache.solr.uninverting.UninvertingReader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -662,17 +662,76 @@ public abstract class FieldType extends FieldProperties {
* Returns the SortField instance that should be used to sort fields * Returns the SortField instance that should be used to sort fields
* of this type. * of this type.
* @see SchemaField#checkSortability * @see SchemaField#checkSortability
* @see #getSortField(SchemaField,SortField.Type,boolean,Object,Object)
*/ */
public abstract SortField getSortField(SchemaField field, boolean top); public abstract SortField getSortField(SchemaField field, boolean top);
/**
* <p>A Helper utility method for use by subclasses.</p>
* <p>This method deals with:</p>
* <ul>
* <li>{@link SchemaField#checkSortability}</li>
* <li>Creating a {@link SortField} on <code>field</code> with the specified
* <code>reverse</code> &amp; <code>sortType</code></li>
* <li>Setting the {@link SortField#setMissingValue} to <code>missingLow</code> or <code>missingHigh</code>
* as appropriate based on the value of <code>reverse</code> and the
* <code>sortMissingFirst</code> &amp; <code>sortMissingLast</code> properties of the
* <code>field</code></li>
* </ul>
*
* @param field The SchemaField to sort on. May use <code>sortMissingFirst</code> or <code>sortMissingLast</code> or neither.
* @param sortType The sort Type of the underlying values in the <code>field</code>
* @param reverse True if natural order of the <code>sortType</code> should be reversed
* @param missingLow The <code>missingValue</code> to be used if the other params indicate that docs w/o values should sort as "low" as possible.
* @param missingHigh The <code>missingValue</code> to be used if the other params indicate that docs w/o values should sort as "high" as possible.
* @see #getSortedSetSortField
*/
protected static SortField getSortField(SchemaField field, SortField.Type sortType, boolean reverse,
Object missingLow, Object missingHigh) {
field.checkSortability();
SortField sf = new SortField(field.getName(), sortType, reverse);
applySetMissingValue(field, sf, missingLow, missingHigh);
return sf;
}
/**
* Same as {@link #getSortField} but using {@link SortedSetSortField}
*/
protected static SortField getSortedSetSortField(SchemaField field, SortedSetSelector.Type selector,
boolean reverse, Object missingLow, Object missingHigh) {
field.checkSortability();
SortField sf = new SortedSetSortField(field.getName(), reverse, selector);
applySetMissingValue(field, sf, missingLow, missingHigh);
return sf;
}
/**
* @see #getSortField
* @see #getSortedSetSortField
*/
private static void applySetMissingValue(SchemaField field, SortField sortField,
Object missingLow, Object missingHigh) {
final boolean reverse = sortField.getReverse();
if (field.sortMissingLast()) {
sortField.setMissingValue(reverse ? missingLow : missingHigh);
} else if (field.sortMissingFirst()) {
sortField.setMissingValue(reverse ? missingHigh : missingLow);
}
}
/** /**
* Utility usable by subclasses when they want to get basic String sorting * Utility usable by subclasses when they want to get basic String sorting
* using common checks. * using common checks.
* @see SchemaField#checkSortability * @see SchemaField#checkSortability
*/ */
protected SortField getStringSort(SchemaField field, boolean reverse) { protected SortField getStringSort(SchemaField field, boolean reverse) {
field.checkSortability(); return getSortField(field, SortField.Type.STRING, reverse, SortField.STRING_FIRST, SortField.STRING_LAST);
return Sorting.getStringSortField(field.name, reverse, field.sortMissingLast(),field.sortMissingFirst());
} }
/** called to get the default value source (normally, from the /** called to get the default value source (normally, from the

View File

@ -134,20 +134,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortField(field, SortField.Type.FLOAT, top, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
Object missingValue = null;
boolean sortMissingLast = field.sortMissingLast();
boolean sortMissingFirst = field.sortMissingFirst();
if (sortMissingLast) {
missingValue = top ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
} else if (sortMissingFirst) {
missingValue = top ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY;
}
SortField sf = new SortField(field.getName(), SortField.Type.FLOAT, top);
sf.setMissingValue(missingValue);
return sf;
} }
@Override @Override

View File

@ -132,20 +132,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortField(field, SortField.Type.INT, top, Integer.MIN_VALUE, Integer.MAX_VALUE);
Object missingValue = null;
boolean sortMissingLast = field.sortMissingLast();
boolean sortMissingFirst = field.sortMissingFirst();
if (sortMissingLast) {
missingValue = top ? Integer.MIN_VALUE : Integer.MAX_VALUE;
} else if (sortMissingFirst) {
missingValue = top ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
SortField sf = new SortField(field.getName(), SortField.Type.INT, top);
sf.setMissingValue(missingValue);
return sf;
} }
@Override @Override

View File

@ -131,20 +131,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortField(field, SortField.Type.LONG, top, Long.MIN_VALUE, Long.MAX_VALUE);
Object missingValue = null;
boolean sortMissingLast = field.sortMissingLast();
boolean sortMissingFirst = field.sortMissingFirst();
if (sortMissingLast) {
missingValue = top ? Long.MIN_VALUE : Long.MAX_VALUE;
} else if (sortMissingFirst) {
missingValue = top ? Long.MAX_VALUE : Long.MIN_VALUE;
}
SortField sf = new SortField(field.getName(), SortField.Type.LONG, top);
sf.setMissingValue(missingValue);
return sf;
} }
@Override @Override

View File

@ -34,13 +34,13 @@ import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource; import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedSetSelector;
import org.apache.lucene.util.AttributeFactory; import org.apache.lucene.util.AttributeFactory;
import org.apache.lucene.util.AttributeSource.State; import org.apache.lucene.util.AttributeSource.State;
import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.AttributeSource;
import org.apache.solr.analysis.SolrAnalyzer; import org.apache.solr.analysis.SolrAnalyzer;
import org.apache.solr.response.TextResponseWriter; import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.search.QParser; import org.apache.solr.search.QParser;
import org.apache.solr.search.Sorting;
import org.apache.solr.uninverting.UninvertingReader.Type; import org.apache.solr.uninverting.UninvertingReader.Type;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -132,8 +132,8 @@ public class PreAnalyzedField extends TextField implements HasImplicitIndexAnaly
@Override @Override
public SortField getSortField(SchemaField field, boolean top) { public SortField getSortField(SchemaField field, boolean top) {
field.checkSortability(); return getSortedSetSortField(field, SortedSetSelector.Type.MIN, top,
return Sorting.getTextSortField(field.getName(), top, field.sortMissingLast(), field.sortMissingFirst()); SortField.STRING_FIRST, SortField.STRING_LAST);
} }
@Override @Override

View File

@ -32,7 +32,6 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.query.SolrRangeQuery; import org.apache.solr.query.SolrRangeQuery;
import org.apache.solr.response.TextResponseWriter; import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.search.QParser; import org.apache.solr.search.QParser;
import org.apache.solr.search.Sorting;
import org.apache.solr.uninverting.UninvertingReader.Type; import org.apache.solr.uninverting.UninvertingReader.Type;
/** <code>TextField</code> is the basic type for configurable text analysis. /** <code>TextField</code> is the basic type for configurable text analysis.
@ -108,8 +107,8 @@ public class TextField extends FieldType {
@Override @Override
public SortField getSortField(SchemaField field, boolean reverse) { public SortField getSortField(SchemaField field, boolean reverse) {
/* :TODO: maybe warn if isTokenized(), but doesn't use LimitTokenCountFilter in its chain? */ /* :TODO: maybe warn if isTokenized(), but doesn't use LimitTokenCountFilter in its chain? */
field.checkSortability(); return getSortedSetSortField(field, SortedSetSelector.Type.MIN, reverse,
return Sorting.getTextSortField(field.getName(), reverse, field.sortMissingLast(), field.sortMissingFirst()); SortField.STRING_FIRST, SortField.STRING_LAST);
} }
@Override @Override

View File

@ -171,50 +171,14 @@ public class TrieField extends NumericFieldType {
switch (type) { switch (type) {
case INTEGER: case INTEGER:
if( sortMissingLast ) { return getSortField(field, SortField.Type.INT, top, Integer.MIN_VALUE, Integer.MAX_VALUE);
missingValue = top ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
else if( sortMissingFirst ) {
missingValue = top ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
sf = new SortField( field.getName(), SortField.Type.INT, top);
sf.setMissingValue(missingValue);
return sf;
case FLOAT: case FLOAT:
if( sortMissingLast ) { return getSortField(field, SortField.Type.FLOAT, top, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
missingValue = top ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
}
else if( sortMissingFirst ) {
missingValue = top ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY;
}
sf = new SortField( field.getName(), SortField.Type.FLOAT, top);
sf.setMissingValue(missingValue);
return sf;
case DATE: // fallthrough case DATE: // fallthrough
case LONG: case LONG:
if( sortMissingLast ) { return getSortField(field, SortField.Type.LONG, top, Long.MIN_VALUE, Long.MAX_VALUE);
missingValue = top ? Long.MIN_VALUE : Long.MAX_VALUE;
}
else if( sortMissingFirst ) {
missingValue = top ? Long.MAX_VALUE : Long.MIN_VALUE;
}
sf = new SortField( field.getName(), SortField.Type.LONG, top);
sf.setMissingValue(missingValue);
return sf;
case DOUBLE: case DOUBLE:
if( sortMissingLast ) { return getSortField(field, SortField.Type.DOUBLE, top, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
missingValue = top ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
}
else if( sortMissingFirst ) {
missingValue = top ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
}
sf = new SortField( field.getName(), SortField.Type.DOUBLE, top);
sf.setMissingValue(missingValue);
return sf;
default: default:
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + field.name); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + field.name);
} }

View File

@ -16,15 +16,16 @@
*/ */
package org.apache.solr.search; package org.apache.solr.search;
import org.apache.solr.schema.FieldType;
import org.apache.lucene.search.*; import org.apache.lucene.search.*;
/** /**
* Extra lucene sorting utilities &amp; convenience methods * Extra lucene sorting utilities &amp; convenience methods
* *
* *
* * @deprecated custom {@link FieldType}s should use the helper methods in the base class. Other usage should leverage th underling lucene {@link SortField} classes directly.
*/ */
@Deprecated
public class Sorting { public class Sorting {
@ -37,14 +38,19 @@ public class Sorting {
* @param nullLast true if null should come last, regardless of sort order * @param nullLast true if null should come last, regardless of sort order
* @param nullFirst true if null should come first, regardless of sort order * @param nullFirst true if null should come first, regardless of sort order
* @return SortField * @return SortField
* @deprecated custom {@link FieldType}s should use {@link FieldType#getSortField}. Other usage should leverage th underling lucene {@link SortField} classes directly.
*/ */
@Deprecated
public static SortField getStringSortField(String fieldName, boolean reverse, boolean nullLast, boolean nullFirst) { public static SortField getStringSortField(String fieldName, boolean reverse, boolean nullLast, boolean nullFirst) {
SortField sortField = new SortField(fieldName, SortField.Type.STRING, reverse); SortField sortField = new SortField(fieldName, SortField.Type.STRING, reverse);
applyMissingFirstLast(sortField, reverse, nullLast, nullFirst); applyMissingFirstLast(sortField, reverse, nullLast, nullFirst);
return sortField; return sortField;
} }
/** Like {@link #getStringSortField}) except safe for tokenized fields */ /** Like {@link #getStringSortField}) except safe for tokenized fields
* @deprecated custom {@link FieldType}s should use {@link FieldType#getSortedSetSortField}. Other usage should leverage th underling lucene {@link SortedSetSortField} classes directly.
*/
@Deprecated
public static SortField getTextSortField(String fieldName, boolean reverse, boolean nullLast, boolean nullFirst) { public static SortField getTextSortField(String fieldName, boolean reverse, boolean nullLast, boolean nullFirst) {
SortField sortField = new SortedSetSortField(fieldName, reverse); SortField sortField = new SortedSetSortField(fieldName, reverse);
applyMissingFirstLast(sortField, reverse, nullLast, nullFirst); applyMissingFirstLast(sortField, reverse, nullLast, nullFirst);

View File

@ -18,12 +18,22 @@
<schema name="tiny" version="1.1"> <schema name="tiny" version="1.1">
<field name="id" type="string" indexed="true" stored="true" required="true"/> <field name="id" type="string" indexed="true" stored="true" required="true"/>
<field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/> <field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/>
<!-- Test EnumField and EnumFieldType --> <!-- Test EnumField and EnumFieldType -->
<field name="severity" type="severityType" indexed="${solr.tests.EnumFieldTest.indexed}" stored="true" multiValued="false" docValues="${solr.tests.numeric.dv}"/> <field name="severity" type="severityType" indexed="${solr.tests.EnumFieldTest.indexed}" stored="true" multiValued="false" docValues="${solr.tests.numeric.dv}"/>
<!-- NOTE: because these test sortMissingLast/sortMissingFirst, we force indexed="true" so we don't get
random errors on schema init about inconsistent properties -->
<field name="severity_missingLast" type="severityType" indexed="true" stored="true" multiValued="false" docValues="${solr.tests.numeric.dv}" sortMissingLast="true"/>
<field name="severity_missingFirst" type="severityType" indexed="true" stored="true" multiValued="false" docValues="${solr.tests.numeric.dv}" sortMissingFirst="true"/>
<field name="severity_mv" type="severityType" indexed="${solr.tests.EnumFieldTest.indexed}" stored="true" multiValued="true" docValues="${solr.tests.numeric.dv}"/> <field name="severity_mv" type="severityType" indexed="${solr.tests.EnumFieldTest.indexed}" stored="true" multiValued="true" docValues="${solr.tests.numeric.dv}"/>
<field name="text" type="text" indexed="true" stored="true" multiValued="true"/> <field name="text" type="text" indexed="true" stored="true" multiValued="true"/>
<uniqueKey>id</uniqueKey> <uniqueKey>id</uniqueKey>
<copyField source="severity" dest="severity_missingLast" />
<copyField source="severity" dest="severity_missingFirst" />
<fieldType name="text" class="solr.TextField"> <fieldType name="text" class="solr.TextField">
<analyzer> <analyzer>
<tokenizer class="solr.WhitespaceTokenizerFactory"/> <tokenizer class="solr.WhitespaceTokenizerFactory"/>

View File

@ -16,6 +16,7 @@
*/ */
package org.apache.solr.schema; package org.apache.solr.schema;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -385,6 +386,21 @@ public class EnumFieldTest extends SolrTestCaseJ4 {
"//doc[4]/str[@name='" + FIELD_NAME + "']/text()='High'", "//doc[4]/str[@name='" + FIELD_NAME + "']/text()='High'",
"//doc[5]/str[@name='" + FIELD_NAME + "']/text()='Critical'" "//doc[5]/str[@name='" + FIELD_NAME + "']/text()='Critical'"
); );
// missing first....
for (String dir : Arrays.asList("asc", "desc")) {
assertQ(req("fl", "id", "q", "*:*", "sort", FIELD_NAME + "_missingFirst " + dir + ", id desc")
, "//doc[1]/str[@name='id']/text()='9'"
, "//doc[2]/str[@name='id']/text()='8'"
);
}
// missing last...
for (String dir : Arrays.asList("asc", "desc")) {
assertQ(req("fl", "id", "q", "*:*", "sort", FIELD_NAME + "_missingLast " + dir + ", id desc")
, "//doc[6]/str[@name='id']/text()='9'"
, "//doc[7]/str[@name='id']/text()='8'"
);
}
} }
@Test @Test

View File

@ -3331,7 +3331,7 @@ public class TestPointFields extends SolrTestCaseJ4 {
assertTrue(h.getCore().getLatestSchema().getField(field).getType() instanceof PointField); assertTrue(h.getCore().getLatestSchema().getField(field).getType() instanceof PointField);
int numVals = 10 * RANDOM_MULTIPLIER; int numVals = 10 * RANDOM_MULTIPLIER;
// Restrict values to float range; otherwise conversion to float will cause truncation -> undefined results // Restrict values to float range; otherwise conversion to float will cause truncation -> undefined results
List<Double> values = getRandomList(10, false, () -> { List<Double> values = getRandomList(numVals, false, () -> {
Float f = Float.NaN; Float f = Float.NaN;
while (f.isNaN()) { while (f.isNaN()) {
f = Float.intBitsToFloat(random().nextInt()); f = Float.intBitsToFloat(random().nextInt());

View File

@ -271,9 +271,9 @@ public class TestSort extends SolrTestCaseJ4 {
if (r.nextBoolean()) sfields.add( new SortField(null, SortField.Type.SCORE)); if (r.nextBoolean()) sfields.add( new SortField(null, SortField.Type.SCORE));
// hit both use-cases of sort-missing-last // hit both use-cases of sort-missing-last
sfields.add( Sorting.getStringSortField("f", reverse, sortMissingLast, sortMissingFirst) ); sfields.add( getStringSortField("f", reverse, sortMissingLast, sortMissingFirst) );
if (secondary) { if (secondary) {
sfields.add( Sorting.getStringSortField("f2", reverse2, sortMissingLast2, sortMissingFirst2) ); sfields.add( getStringSortField("f2", reverse2, sortMissingLast2, sortMissingFirst2) );
} }
if (r.nextBoolean()) sfields.add( new SortField(null, SortField.Type.SCORE)); if (r.nextBoolean()) sfields.add( new SortField(null, SortField.Type.SCORE));
@ -355,5 +355,20 @@ public class TestSort extends SolrTestCaseJ4 {
return new BitDocIdSet(obs); return new BitDocIdSet(obs);
} }
private static SortField getStringSortField(String fieldName, boolean reverse, boolean nullLast, boolean nullFirst) {
SortField sortField = new SortField(fieldName, SortField.Type.STRING, reverse);
// 4 cases:
// missingFirst / forward: default lucene behavior
// missingFirst / reverse: set sortMissingLast
// missingLast / forward: set sortMissingLast
// missingLast / reverse: default lucene behavior
if (nullFirst && reverse) {
sortField.setMissingValue(SortField.STRING_LAST);
} else if (nullLast && !reverse) {
sortField.setMissingValue(SortField.STRING_LAST);
}
return sortField;
}
} }

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.client.solrj.io.eval;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.math3.primes.Primes;
import org.apache.solr.client.solrj.io.stream.expr.StreamExpression;
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
public class PrimesEvaluator extends RecursiveNumericEvaluator implements ManyValueWorker {
protected static final long serialVersionUID = 1L;
public PrimesEvaluator(StreamExpression expression, StreamFactory factory) throws IOException{
super(expression, factory);
if(2 != containedEvaluators.size()){
throw new IOException(String.format(Locale.ROOT,"Invalid expression %s - expecting two values but found %d",expression, containedEvaluators.size()));
}
}
@Override
public Object doWork(Object... values) throws IOException {
if(2 != values.length){
throw new IOException(String.format(Locale.ROOT,"%s(...) only works with 2 values but %d were provided", constructingFactory.getFunctionName(getClass()), values.length));
}
int sizeNum = ((Number)values[0]).intValue();
int startNum = ((Number)values[1]).intValue();
List<Number> primes = new ArrayList();
for(int i=0; i< sizeNum; i++) {
int prime = Primes.nextPrime(startNum);
primes.add(prime);
startNum = prime;
++startNum;
}
return primes;
}
}

View File

@ -5857,6 +5857,35 @@ public class StreamExpressionTest extends SolrCloudTestCase {
} }
@Test
public void testPrimes() throws Exception {
String cexpr = "primes(10, 0)";
ModifiableSolrParams paramsLoc = new ModifiableSolrParams();
paramsLoc.set("expr", cexpr);
paramsLoc.set("qt", "/stream");
String url = cluster.getJettySolrRunners().get(0).getBaseUrl().toString()+"/"+COLLECTIONORALIAS;
TupleStream solrStream = new SolrStream(url, paramsLoc);
StreamContext context = new StreamContext();
solrStream.setStreamContext(context);
List<Tuple> tuples = getTuples(solrStream);
assertTrue(tuples.size() == 1);
Tuple tuple = tuples.get(0);
List<Number> asort = (List<Number>)tuple.get("return-value");
assertEquals(asort.size(), 10);
assertEquals(asort.get(0).intValue(), 2);
assertEquals(asort.get(1).intValue(), 3);
assertEquals(asort.get(2).intValue(), 5);
assertEquals(asort.get(3).intValue(), 7);
assertEquals(asort.get(4).intValue(), 11);
assertEquals(asort.get(5).intValue(), 13);
assertEquals(asort.get(6).intValue(), 17);
assertEquals(asort.get(7).intValue(), 19);
assertEquals(asort.get(8).intValue(), 23);
assertEquals(asort.get(9).intValue(), 29);
}
@Test @Test
public void testAscend() throws Exception { public void testAscend() throws Exception {
String cexpr = "asc(array(11.5, 12.3, 4, 3, 1, 0))"; String cexpr = "asc(array(11.5, 12.3, 4, 3, 1, 0))";