You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2015/07/31 18:48:27 UTC

svn commit: r1693628 - in /lucene/dev/branches/branch_5x: ./ lucene/ lucene/core/ lucene/core/src/java/org/apache/lucene/search/ solr/ solr/core/ solr/core/src/java/org/apache/solr/schema/ solr/core/src/java/org/apache/solr/search/ solr/core/src/test-f...

Author: hossman
Date: Fri Jul 31 16:48:26 2015
New Revision: 1693628

URL: http://svn.apache.org/r1693628
Log:
SOLR-2522: new two argument option for the existing field() function; picks the min/max value of a docValues field to use as a ValueSource: "field(field_name,min)" and "field(field_name,max)" (merge r1693625)

Added:
    lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/function/TestMinMaxOnMultiValuedField.java
      - copied unchanged from r1693625, lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/function/TestMinMaxOnMultiValuedField.java
Modified:
    lucene/dev/branches/branch_5x/   (props changed)
    lucene/dev/branches/branch_5x/lucene/   (props changed)
    lucene/dev/branches/branch_5x/lucene/core/   (props changed)
    lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/SortedSetSelector.java
    lucene/dev/branches/branch_5x/solr/   (props changed)
    lucene/dev/branches/branch_5x/solr/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_5x/solr/core/   (props changed)
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/FieldType.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieDoubleField.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieField.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieFloatField.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieIntField.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/   (props changed)
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
    lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema15.xml
    lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java

Modified: lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/SortedSetSelector.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/SortedSetSelector.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/SortedSetSelector.java (original)
+++ lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/search/SortedSetSelector.java Fri Jul 31 16:48:26 2015
@@ -77,7 +77,7 @@ public class SortedSetSelector {
       return new MinValue(sortedSet);
     } else {
       if (sortedSet instanceof RandomAccessOrds == false) {
-        throw new UnsupportedOperationException("codec does not support random access ordinals, cannot use selector: " + selector);
+        throw new UnsupportedOperationException("codec does not support random access ordinals, cannot use selector: " + selector + " docValsImpl: " + sortedSet.toString());
       }
       RandomAccessOrds randomOrds = (RandomAccessOrds) sortedSet;
       switch(selector) {

Modified: lucene/dev/branches/branch_5x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/CHANGES.txt?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/solr/CHANGES.txt Fri Jul 31 16:48:26 2015
@@ -103,6 +103,9 @@ New Features
 
 * SOLR-6234: Scoring for query time join (Mikhail Khludnev)
 
+* SOLR-2522: new two argument option for the existing field() function; picks the min/max value of a
+  docValues field to use as a ValueSource: "field(field_name,min)" and "field(field_name,max)"  (hossman)
+
 Bug Fixes
 ----------------------
 

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/FieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/FieldType.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/FieldType.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/FieldType.java Fri Jul 31 16:48:26 2015
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -44,6 +45,8 @@ import org.apache.lucene.search.MultiTer
 import org.apache.lucene.search.PrefixQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.SortedSetSelector;
+import org.apache.lucene.search.SortedNumericSelector;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.TermRangeQuery;
 import org.apache.lucene.search.similarities.Similarity;
@@ -670,6 +673,27 @@ public abstract class FieldType extends
   }
 
   /**
+   * Method for dynamically building a ValueSource based on a single value of a multivalued field.
+   *
+   * The default implementation throws an error except in the trivial case where this method is used on 
+   * a {@link SchemaField} that is in fact not-multivalued, in which case it delegates to 
+   * {@link #getValueSource}
+   *
+   * @see MultiValueSelector
+   */
+  public ValueSource getSingleValueSource(MultiValueSelector choice, SchemaField field, QParser parser) {
+    // trivial base case
+    if (!field.multiValued()) {
+      // single value matches any selector
+      return getValueSource(field, parser);
+    }
+    
+    throw new SolrException(ErrorCode.BAD_REQUEST, "Selecting a single value from a multivalued field is not supported for this field: " + field.getName() + " (type: " + this.getTypeName() + ")");
+  }
+
+
+  
+  /**
    * Returns a Query instance for doing range searches on this field type. {@link org.apache.solr.search.SolrQueryParser}
    * currently passes part1 and part2 as null if they are '*' respectively. minInclusive and maxInclusive are both true
    * currently by SolrQueryParser but that may change in the future. Also, other QueryParser implementations may have
@@ -1028,4 +1052,65 @@ public abstract class FieldType extends
     final byte[] bytes = Base64.base64ToByteArray(val);
     return new BytesRef(bytes);
   }
+
+  /**
+   * An enumeration representing various options that may exist for selecting a single value from a 
+   * multivalued field.  This class is designed to be an abstract representation, agnostic of some of 
+   * the underlying specifics.  Not all enum value are garunteeded work in all contexts -- null checks 
+   * must be dont by the caller for the specific methods needed.
+   *
+   * @see FieldType#getSingleValueSource
+   */
+  public enum MultiValueSelector {
+    // trying to be agnostic about SortedSetSelector.Type vs SortedNumericSelector.Type
+    MIN(SortedSetSelector.Type.MIN, SortedNumericSelector.Type.MIN),
+    MAX(SortedSetSelector.Type.MAX, SortedNumericSelector.Type.MAX);
+
+    @Override
+    public String toString() { return super.toString().toLowerCase(Locale.ROOT); }
+    
+    /** 
+     * The appropriate <code>SortedSetSelector.Type</code> option for this <code>MultiValueSelector</code>,
+     * may be null if there is no equivilent
+     */
+    public SortedSetSelector.Type getSortedSetSelectorType() {
+      return sType;
+    }
+
+    /** 
+     * The appropriate <code>SortedNumericSelector.Type</code> option for this <code>MultiValueSelector</code>,
+     * may be null if there is no equivilent
+     */
+    public SortedNumericSelector.Type getSortedNumericSelectorType() {
+      return nType;
+    }
+    
+    private final SortedSetSelector.Type sType;
+    private final SortedNumericSelector.Type nType;
+    
+    private MultiValueSelector(SortedSetSelector.Type sType, SortedNumericSelector.Type nType) {
+      this.sType = sType;
+      this.nType = nType;
+    }
+
+    /**
+     * Returns a MultiValueSelector matching the specified (case insensitive) label, or null if 
+     * no corrisponding MultiValueSelector exists.
+     * 
+     * @param label a non null label to be checked for a corrisponding MultiValueSelector
+     * @return a MultiValueSelector or null if no MultiValueSelector matches the specified label
+     */
+    public static MultiValueSelector lookup(String label) {
+      if (null == label) {
+        throw new NullPointerException("label must not be null when calling MultiValueSelector.lookup");
+      }
+      try {
+        return valueOf(label.toUpperCase(Locale.ROOT));
+      } catch (IllegalArgumentException e) {
+        return null;
+      }
+    }
+
+  }
+  
 }

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieDoubleField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieDoubleField.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieDoubleField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieDoubleField.java Fri Jul 31 16:48:26 2015
@@ -17,6 +17,23 @@
 
 package org.apache.solr.schema;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
+import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
+import org.apache.lucene.search.SortedSetSelector;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.mutable.MutableValue;
+import org.apache.lucene.util.mutable.MutableValueDouble;
+
 /**
  * A numeric field that can contain double-precision 64-bit IEEE 754 floating 
  * point values.
@@ -37,4 +54,49 @@ public class TrieDoubleField extends Tri
   {
     type=TrieTypes.DOUBLE;
   }
+  
+  @Override
+  protected ValueSource getSingleValueSource(SortedSetSelector.Type choice, SchemaField f) {
+    
+    return new SortedSetFieldSource(f.getName(), choice) {
+      @Override
+      public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
+        SortedSetFieldSource thisAsSortedSetFieldSource = this; // needed for nested anon class ref
+        
+        SortedSetDocValues sortedSet = DocValues.getSortedSet(readerContext.reader(), field);
+        final SortedDocValues view = SortedSetSelector.wrap(sortedSet, selector);
+        
+        return new DoubleDocValues(thisAsSortedSetFieldSource) {
+          @Override
+          public double doubleVal(int doc) {
+            BytesRef bytes = view.get(doc);
+            return  NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(bytes));
+          }
+
+          @Override
+          public boolean exists(int doc) {
+            return -1 != view.getOrd(doc);
+          }
+
+          @Override
+          public ValueFiller getValueFiller() {
+            return new ValueFiller() {
+              private final MutableValueDouble mval = new MutableValueDouble();
+              
+              @Override
+              public MutableValue getValue() {
+                return mval;
+              }
+              
+              @Override
+              public void fillValue(int doc) {
+                mval.exists = exists(doc);
+                mval.value = mval.exists ? doubleVal(doc) : 0.0D;
+              }
+            };
+          }
+        };
+      }
+    };
+  }
 }

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieField.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieField.java Fri Jul 31 16:48:26 2015
@@ -42,6 +42,7 @@ import org.apache.lucene.queries.functio
 import org.apache.lucene.search.DocValuesRangeQuery;
 import org.apache.lucene.search.NumericRangeQuery;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortedSetSelector;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.uninverting.UninvertingReader.Type;
 import org.apache.lucene.util.BytesRef;
@@ -244,7 +245,50 @@ public class TrieField extends Primitive
     }
   }
 
+  @Override
+  public final ValueSource getSingleValueSource(MultiValueSelector choice, SchemaField field, QParser parser) {
+    // trivial base case
+    if (!field.multiValued()) {
+      // single value matches any selector
+      return getValueSource(field, parser);
+    }
+
+    // See LUCENE-6709
+    if (! field.hasDocValues()) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                              "docValues='true' is required to select '" + choice.toString() +
+                              "' value from multivalued field ("+ field.getName() +") at query time");
+    }
+    
+    // multivalued Trie fields all use SortedSetDocValues, so we give a clean error if that's
+    // not supported by the specified choice, else we delegate to a helper
+    SortedSetSelector.Type selectorType = choice.getSortedSetSelectorType();
+    if (null == selectorType) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                              choice.toString() + " is not a supported option for picking a single value"
+                              + " from the multivalued field: " + field.getName() +
+                              " (type: " + this.getTypeName() + ")");
+    }
+    
+    return getSingleValueSource(selectorType, field);
+  }
 
+  /**
+   * Helper method that will only be called for multivalued Trie fields that have doc values.
+   * Default impl throws an error indicating that selecting a single value from this multivalued 
+   * field is not supported for this field type
+   *
+   * @param choice the selector Type to use, will never be null
+   * @param field the field to use, garunteed to be multivalued.
+   * @see #getSingleValueSource(MultiValueSelector,SchemaField,QParser) 
+   */
+  protected ValueSource getSingleValueSource(SortedSetSelector.Type choice, SchemaField field) {
+    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                            "Can not select a single value for multivalued field: " + field.getName()
+                            + " (single valued field selection not supported for type: " + this.getTypeName()
+                            + ")");
+  }
+  
   @Override
   public void write(TextResponseWriter writer, String name, IndexableField f) throws IOException {
     writer.writeVal(name, toObject(f));

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieFloatField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieFloatField.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieFloatField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieFloatField.java Fri Jul 31 16:48:26 2015
@@ -17,6 +17,23 @@
 
 package org.apache.solr.schema;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.queries.function.docvalues.FloatDocValues;
+import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
+import org.apache.lucene.search.SortedSetSelector;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.mutable.MutableValue;
+import org.apache.lucene.util.mutable.MutableValueFloat;
+
 /**
  * A numeric field that can contain single-precision 32-bit IEEE 754 
  * floating point values.
@@ -45,4 +62,50 @@ public class TrieFloatField extends Trie
     if (val instanceof String) return Float.parseFloat((String) val);
     return super.toNativeType(val);
   }
+
+  @Override
+  protected ValueSource getSingleValueSource(SortedSetSelector.Type choice, SchemaField f) {
+    
+    return new SortedSetFieldSource(f.getName(), choice) {
+      @Override
+      public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
+        SortedSetFieldSource thisAsSortedSetFieldSource = this; // needed for nested anon class ref
+        
+        SortedSetDocValues sortedSet = DocValues.getSortedSet(readerContext.reader(), field);
+        final SortedDocValues view = SortedSetSelector.wrap(sortedSet, selector);
+        
+        return new FloatDocValues(thisAsSortedSetFieldSource) {
+          @Override
+          public float floatVal(int doc) {
+            BytesRef bytes = view.get(doc);
+            return  NumericUtils.sortableIntToFloat(NumericUtils.prefixCodedToInt(bytes));
+          }
+
+          @Override
+          public boolean exists(int doc) {
+            return -1 != view.getOrd(doc);
+          }
+
+          @Override
+          public ValueFiller getValueFiller() {
+            return new ValueFiller() {
+              private final MutableValueFloat mval = new MutableValueFloat();
+              
+              @Override
+              public MutableValue getValue() {
+                return mval;
+              }
+              
+              @Override
+              public void fillValue(int doc) {
+                mval.exists = exists(doc);
+                mval.value = mval.exists ? floatVal(doc) : 0.0F;
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
 }

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieIntField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieIntField.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieIntField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieIntField.java Fri Jul 31 16:48:26 2015
@@ -17,6 +17,23 @@
 
 package org.apache.solr.schema;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.queries.function.docvalues.IntDocValues;
+import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
+import org.apache.lucene.search.SortedSetSelector;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.mutable.MutableValue;
+import org.apache.lucene.util.mutable.MutableValueInt;
+
 /**
  * A numeric field that can contain 32-bit signed two's complement integer values.
  *
@@ -44,4 +61,49 @@ public class TrieIntField extends TrieFi
     }
     return super.toNativeType(val);
   }
+  
+  @Override
+  protected ValueSource getSingleValueSource(SortedSetSelector.Type choice, SchemaField f) {
+    
+    return new SortedSetFieldSource(f.getName(), choice) {
+      @Override
+      public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
+        SortedSetFieldSource thisAsSortedSetFieldSource = this; // needed for nested anon class ref
+        
+        SortedSetDocValues sortedSet = DocValues.getSortedSet(readerContext.reader(), field);
+        final SortedDocValues view = SortedSetSelector.wrap(sortedSet, selector);
+        
+        return new IntDocValues(thisAsSortedSetFieldSource) {
+          @Override
+          public int intVal(int doc) {
+            BytesRef bytes = view.get(doc);
+            return NumericUtils.prefixCodedToInt(bytes);
+          }
+
+          @Override
+          public boolean exists(int doc) {
+            return -1 != view.getOrd(doc);
+          }
+
+          @Override
+          public ValueFiller getValueFiller() {
+            return new ValueFiller() {
+              private final MutableValueInt mval = new MutableValueInt();
+              
+              @Override
+              public MutableValue getValue() {
+                return mval;
+              }
+              
+              @Override
+              public void fillValue(int doc) {
+                mval.exists = exists(doc);
+                mval.value = mval.exists ? intVal(doc) : 0;
+              }
+            };
+          }
+        };
+      }
+    };
+  }
 }

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieLongField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieLongField.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieLongField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/TrieLongField.java Fri Jul 31 16:48:26 2015
@@ -17,6 +17,23 @@
 
 package org.apache.solr.schema;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.queries.function.docvalues.LongDocValues;
+import org.apache.lucene.queries.function.valuesource.SortedSetFieldSource;
+import org.apache.lucene.search.SortedSetSelector;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.mutable.MutableValue;
+import org.apache.lucene.util.mutable.MutableValueLong;
+
 /**
  * A numeric field that can contain 64-bit signed two's complement integer values.
  *
@@ -31,4 +48,49 @@ public class TrieLongField extends TrieF
   {
     type=TrieTypes.LONG;
   }
+
+  @Override
+  protected ValueSource getSingleValueSource(SortedSetSelector.Type choice, SchemaField f) {
+    
+    return new SortedSetFieldSource(f.getName(), choice) {
+      @Override
+      public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
+        SortedSetFieldSource thisAsSortedSetFieldSource = this; // needed for nested anon class ref
+        
+        SortedSetDocValues sortedSet = DocValues.getSortedSet(readerContext.reader(), field);
+        final SortedDocValues view = SortedSetSelector.wrap(sortedSet, selector);
+        
+        return new LongDocValues(thisAsSortedSetFieldSource) {
+          @Override
+          public long longVal(int doc) {
+            BytesRef bytes = view.get(doc);
+            return NumericUtils.prefixCodedToLong(bytes);
+          }
+
+          @Override
+          public boolean exists(int doc) {
+            return -1 != view.getOrd(doc);
+          }
+
+          @Override
+          public ValueFiller getValueFiller() {
+            return new ValueFiller() {
+              private final MutableValueLong mval = new MutableValueLong();
+              
+              @Override
+              public MutableValue getValue() {
+                return mval;
+              }
+              
+              @Override
+              public void fillValue(int doc) {
+                mval.exists = exists(doc);
+                mval.value = mval.exists ? longVal(doc) : 0;
+              }
+            };
+          }
+        };
+      }
+    };
+  }
 }

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java Fri Jul 31 16:48:26 2015
@@ -398,6 +398,17 @@ public abstract class ValueSourceParser
 
         String fieldName = fp.parseArg();
         SchemaField f = fp.getReq().getSchema().getField(fieldName);
+        if (fp.hasMoreArguments()) {
+          // multivalued selector option
+          String s = fp.parseArg();
+          FieldType.MultiValueSelector selector = FieldType.MultiValueSelector.lookup(s);
+          if (null == selector) {
+            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                                    "Multi-Valued field selector '"+s+"' not spported");
+          }
+          return f.getType().getSingleValueSource(selector, f, fp);
+        }
+        // simple field ValueSource
         return f.getType().getValueSource(f, fp);
       }
     });
@@ -563,6 +574,7 @@ public abstract class ValueSourceParser
         return new MinFloatFunction(sources.toArray(new ValueSource[sources.size()]));
       }
     });
+
     addParser("sqedist", new ValueSourceParser() {
       @Override
       public ValueSource parse(FunctionQParser fp) throws SyntaxError {

Modified: lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema15.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema15.xml?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema15.xml (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema15.xml Fri Jul 31 16:48:26 2015
@@ -506,7 +506,7 @@
    <!-- points to the root document of a block of nested documents -->
    <field name="_root_" type="string" indexed="true" stored="true"/>
 
- 
+   <field name="multi_int_with_docvals" type="tint" multiValued="true" docValues="true" indexed="false" />
 
    <dynamicField name="*_coordinate"  type="tdouble" indexed="true"  stored="false"/>
 

Modified: lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java?rev=1693628&r1=1693627&r2=1693628&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java Fri Jul 31 16:48:26 2015
@@ -817,6 +817,28 @@ public class QueryEqualityTest extends S
     assertFuncEquals("field(\"foo_i\")", 
                      "field('foo_i\')", 
                      "foo_i");
+    
+    // simple VS of single valued field should be same as asking for min/max on that field
+    assertFuncEquals("field(\"foo_i\")", 
+                     "field('foo_i',min)", 
+                     "field(foo_i,'min')", 
+                     "field('foo_i',max)", 
+                     "field(foo_i,'max')", 
+                     "foo_i");
+
+    // multivalued field with selector
+    String multif = "multi_int_with_docvals";
+    SolrQueryRequest req = req("my_field", multif);
+    // this test is only viable if it's a multivalued field, sanity check the schema
+    assertTrue(multif + " is no longer multivalued, who broke this schema?",
+               req.getSchema().getField(multif).multiValued());
+    assertFuncEquals(req,
+                     "field($my_field,'MIN')", 
+                     "field('"+multif+"',min)");
+    assertFuncEquals(req,
+                     "field($my_field,'max')", 
+                     "field('"+multif+"',Max)"); 
+    
   }
   public void testFuncCurrency() throws Exception {
     assertFuncEquals("currency(\"amount\")",