You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@lucene.apache.org by Chris Hostetter <ho...@apache.org> on 2013/03/04 21:46:24 UTC

Re: svn commit: r1452483 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/schema/ core/src/java/org/apache/solr/search/ core/src/test-files/solr/collection1/conf/ core/src/test/org/apache/solr/schema/ core/src/test/org/apache/solr/search/

Bah ... i swear i ran "ant precommit" on this, and yet i just found 
doclint problems (merging to 4x) ... fix coming.

: Date: Mon, 04 Mar 2013 20:25:37 -0000
: From: hossman@apache.org
: Reply-To: dev@lucene.apache.org
: To: commits@lucene.apache.org
: Subject: svn commit: r1452483 - in /lucene/dev/trunk/solr: ./
:     core/src/java/org/apache/solr/schema/
:     core/src/java/org/apache/solr/search/
:     core/src/test-files/solr/collection1/conf/
:     core/src/test/org/apache/solr/schema/
:     core/src/test/org/apache/solr/search/
: 
: Author: hossman
: Date: Mon Mar  4 20:25:37 2013
: New Revision: 1452483
: 
: URL: http://svn.apache.org/r1452483
: Log:
: SOLR-4138: CurrencyField fields can now be used in a ValueSources. There is also a new currency(field,[CODE]) function
: 
: Modified:
:     lucene/dev/trunk/solr/CHANGES.txt
:     lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/CurrencyField.java
:     lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
:     lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema15.xml
:     lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/AbstractCurrencyFieldTest.java
:     lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java
: 
: Modified: lucene/dev/trunk/solr/CHANGES.txt
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/CHANGES.txt (original)
: +++ lucene/dev/trunk/solr/CHANGES.txt Mon Mar  4 20:25:37 2013
: @@ -98,6 +98,14 @@ New Features
:    Similarity when you know the optimal "Sweet Spot" of values for the field 
:    length and TF scoring factors.  (hossman)
:  
: +* SOLR-4138: CurrencyField fields can now be used in a ValueSources to
: +  get the "raw" value (using the default number of fractional digits) in 
: +  the default currency of the field type.  There is also a new 
: +  currency(field,[CODE]) function for generating a ValueSource of the 
: +  "natural" value, converted to an optionally specified currency to 
: +  override the default for the field type.
: +  (hossman)
: +
:  Bug Fixes
:  ----------------------
:  
: 
: Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/CurrencyField.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/CurrencyField.java?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/CurrencyField.java (original)
: +++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/CurrencyField.java Mon Mar  4 20:25:37 2013
: @@ -242,6 +242,67 @@ public class CurrencyField extends Field
:      return getRangeQuery(parser, field, valueDefault, valueDefault, true, true);
:    }
:  
: +  /**
: +   * <p>
: +   * Returns a ValueSource over this field in which the numeric value for 
: +   * each document represents the indexed value as converted to the default 
: +   * currency for the field, normalized to it's most granular form based 
: +   * on the default fractional digits.
: +   * </p>
: +   * <p>
: +   * For example: If the default Currency specified for a field is 
: +   * <code>USD</code>, then the values returned by this value source would 
: +   * represent the equivilent number of "cents" (ie: value in dollars * 100) 
: +   * after converting each document's native currency to USD -- because the 
: +   * default fractional digits for <code>USD</code> is "<code>2</code>".  
: +   * So for a document whose indexed value was currently equivilent to 
: +   * "<code>5.43,USD</code>" using the the exchange provider for this field, 
: +   * this ValueSource would return a value of "<code>543<code>"
: +   * </p>
: +   *
: +   * @see #PARAM_DEFAULT_CURRENCY
: +   * @see #DEFAULT_DEFAULT_CURRENCY
: +   * @see Currency#getDefaultFractionDigits
: +   * @see getConvertedValueSource
: +   */
: +  public RawCurrencyValueSource getValueSource(SchemaField field, 
: +                                               QParser parser) {
: +    field.checkFieldCacheSource(parser);
: +    return new RawCurrencyValueSource(field, defaultCurrency, parser);
: +  }
: +
: +  /**
: +   * <p>
: +   * Returns a ValueSource over this field in which the numeric value for 
: +   * each document represents the value from the underlying 
: +   * <code>RawCurrencyValueSource</code> as converted to the specified target 
: +   * Currency.
: +   * </p>
: +   * <p>
: +   * For example: If the <code>targetCurrencyCode</code> param is set to
: +   * <code>USD</code>, then the values returned by this value source would 
: +   * represent the equivilent number of dollars after converting each 
: +   * document's raw value to <code>USD</code>.  So for a document whose 
: +   * indexed value was currently equivilent to "<code>5.43,USD</code>" 
: +   * using the the exchange provider for this field, this ValueSource would 
: +   * return a value of "<code>5.43<code>"
: +   * </p>
: +   *
: +   * @param targetCurrencyCode The target currency for the resulting value source, if null the defaultCurrency for this field type will be used
: +   * @param source the raw ValueSource to wrap
: +   * @see #PARAM_DEFAULT_CURRENCY
: +   * @see #DEFAULT_DEFAULT_CURRENCY
: +   * @see getValueSource
: +   */
: +  public ValueSource getConvertedValueSource(String targetCurrencyCode, 
: +                                             RawCurrencyValueSource source) {
: +    if (null == targetCurrencyCode) { 
: +      targetCurrencyCode = defaultCurrency; 
: +    }
: +    return new ConvertedCurrencyValueSource(targetCurrencyCode, 
: +                                            source);
: +  }
: +
:    @Override
:    public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, final boolean minInclusive, final boolean maxInclusive) {
:        final CurrencyValue p1 = CurrencyValue.parse(part1, defaultCurrency);
: @@ -263,7 +324,7 @@ public class CurrencyField extends Field
:      // ValueSourceRangeFilter doesn't check exists(), so we have to
:      final Filter docsWithValues = new FieldValueFilter(getAmountField(field).getName());
:      final Filter vsRangeFilter = new ValueSourceRangeFilter
: -      (new CurrencyValueSource(field, currencyCode, parser),
: +      (new RawCurrencyValueSource(field, currencyCode, parser),
:         p1 == null ? null : p1.getAmount() + "", 
:         p2 == null ? null : p2.getAmount() + "",
:         minInclusive, maxInclusive);
: @@ -277,7 +338,7 @@ public class CurrencyField extends Field
:    @Override
:    public SortField getSortField(SchemaField field, boolean reverse) {
:      // Convert all values to default currency for sorting.
: -    return (new CurrencyValueSource(field, defaultCurrency, null)).getSortField(reverse);
: +    return (new RawCurrencyValueSource(field, defaultCurrency, null)).getSortField(reverse);
:    }
:  
:    @Override
: @@ -289,14 +350,128 @@ public class CurrencyField extends Field
:      return provider;
:    }
:  
: -  class CurrencyValueSource extends ValueSource {
: +  /**
: +   * <p>
: +   * A value source whose values represent the "normal" values
: +   * in the specified target currency.
: +   * </p>
: +   * @see RawCurrencyValueSource
: +   */
: +  class ConvertedCurrencyValueSource extends ValueSource {
: +    private final Currency targetCurrency;
: +    private final RawCurrencyValueSource source;
: +    private final double rate;
: +    public ConvertedCurrencyValueSource(String targetCurrencyCode, 
: +                                        RawCurrencyValueSource source) {
: +      this.source = source;
: +      this.targetCurrency = getCurrency(targetCurrencyCode);
: +      if (null == targetCurrency) {
: +        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Currency code not supported by this JVM: " + targetCurrencyCode);
: +      }
: +      // the target digits & currency of our source, 
: +      // become the source digits & currency of ourselves
: +      this.rate = provider.getExchangeRate
: +        (source.getTargetCurrency().getCurrencyCode(), 
: +         targetCurrency.getCurrencyCode());
: +    }
: +
: +    @Override
: +    public FunctionValues getValues(Map context, AtomicReaderContext reader) 
: +      throws IOException {
: +      final FunctionValues amounts = source.getValues(context, reader);
: +      // the target digits & currency of our source, 
: +      // become the source digits & currency of ourselves
: +      final String sourceCurrencyCode = source.getTargetCurrency().getCurrencyCode();
: +      final int sourceFractionDigits = source.getTargetCurrency().getDefaultFractionDigits();
: +      final double divisor = Math.pow(10D, targetCurrency.getDefaultFractionDigits());
: +      return new FunctionValues() {
: +        @Override
: +        public boolean exists(int doc) {
: +          return amounts.exists(doc);
: +        }
: +        @Override
: +        public long longVal(int doc) {
: +          return (long) doubleVal(doc);
: +        }
: +        @Override
: +        public int intVal(int doc) {
: +          return (int) doubleVal(doc);
: +        }
: +
: +        @Override
: +        public double doubleVal(int doc) {
: +          return CurrencyValue.convertAmount(rate, sourceCurrencyCode, amounts.longVal(doc), targetCurrency.getCurrencyCode()) / divisor;
: +        }
: +
: +        @Override
: +        public float floatVal(int doc) {
: +          return CurrencyValue.convertAmount(rate, sourceCurrencyCode, amounts.longVal(doc), targetCurrency.getCurrencyCode()) / ((float)divisor);
: +        }
: +
: +        @Override
: +        public String strVal(int doc) {
: +          return Double.toString(doubleVal(doc));
: +        }
: +
: +        @Override
: +        public String toString(int doc) {
: +          return name() + '(' + strVal(doc) + ')';
: +        }
: +      };
: +    }
: +    public String name() {
: +      return "currency";
: +    }
: +
: +    @Override
: +    public String description() {
: +      return name() + "(" + source.getField().getName() + "," + targetCurrency.getCurrencyCode()+")";
: +    }
: +
: +    @Override
: +    public boolean equals(Object o) {
: +      if (this == o) return true;
: +      if (o == null || getClass() != o.getClass()) return false;
: +
: +      ConvertedCurrencyValueSource that = (ConvertedCurrencyValueSource) o;
: +
: +      return !(source != null ? !source.equals(that.source) : that.source != null) &&
: +        (rate == that.rate) && 
: +        !(targetCurrency != null ? !targetCurrency.equals(that.targetCurrency) : that.targetCurrency != null);
: +
: +    }
: +
: +    @Override
: +    public int hashCode() {
: +      int result = targetCurrency != null ? targetCurrency.hashCode() : 0;
: +      result = 31 * result + (source != null ? source.hashCode() : 0);
: +      result = 31 * (int) Double.doubleToLongBits(rate);
: +      return result;
: +    }
: +  }
: +
: +  /**
: +   * <p>
: +   * A value source whose values represent the "raw" (ie: normalized using 
: +   * the number of default fractional digits) values in the specified 
: +   * target currency).
: +   * </p>
: +   * <p>
: +   * For example: if the specified target currency is "<code>USD</code>" 
: +   * then the numeric values are the number of pennies in the value 
: +   * (ie: <code>$n * 100</code>) since the number of defalt fractional 
: +   * digits for <code>USD</code> is "<code>2</code>")
: +   * </p>
: +   * @see ConvertedCurrencValueSource
: +   */
: +  class RawCurrencyValueSource extends ValueSource {
:      private static final long serialVersionUID = 1L;
: -    private Currency targetCurrency;
: +    private final Currency targetCurrency;
:      private ValueSource currencyValues;
:      private ValueSource amountValues;
:      private final SchemaField sf;
:  
: -    public CurrencyValueSource(SchemaField sfield, String targetCurrencyCode, QParser parser) {
: +    public RawCurrencyValueSource(SchemaField sfield, String targetCurrencyCode, QParser parser) {
:        this.sf = sfield;
:        this.targetCurrency = getCurrency(targetCurrencyCode);
:        if (null == targetCurrency) {
: @@ -309,6 +484,9 @@ public class CurrencyField extends Field
:        currencyValues = currencyField.getType().getValueSource(currencyField, parser);
:        amountValues = amountField.getType().getValueSource(amountField, parser);
:      }
: +    
: +    public SchemaField getField() { return sf; }
: +    public Currency getTargetCurrency() { return targetCurrency; }
:  
:      @Override
:      public FunctionValues getValues(Map context, AtomicReaderContext reader) throws IOException {
: @@ -444,12 +622,13 @@ public class CurrencyField extends Field
:      }
:  
:      public String name() {
: -      return "currency";
: +      return "rawcurrency";
:      }
:  
:      @Override
:      public String description() {
: -      return name() + "(" + sf.getName() + ")";
: +      return name() + "(" + sf.getName() + 
: +        ",target="+targetCurrency.getCurrencyCode()+")";
:      }
:  
:      @Override
: @@ -457,7 +636,7 @@ public class CurrencyField extends Field
:        if (this == o) return true;
:        if (o == null || getClass() != o.getClass()) return false;
:  
: -      CurrencyValueSource that = (CurrencyValueSource) o;
: +      RawCurrencyValueSource that = (RawCurrencyValueSource) o;
:  
:        return !(amountValues != null ? !amountValues.equals(that.amountValues) : that.amountValues != null) &&
:                !(currencyValues != null ? !currencyValues.equals(that.currencyValues) : that.currencyValues != null) &&
: 
: Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java (original)
: +++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java Mon Mar  4 20:25:37 2013
: @@ -392,6 +392,21 @@ public abstract class ValueSourceParser 
:          return f.getType().getValueSource(f, fp);
:        }
:      });
: +    addParser("currency", new ValueSourceParser() {
: +      @Override
: +      public ValueSource parse(FunctionQParser fp) throws SyntaxError {
: +
: +        String fieldName = fp.parseArg();
: +        SchemaField f = fp.getReq().getSchema().getField(fieldName);
: +        if (! (f.getType() instanceof CurrencyField)) {
: +          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
: +                                  "Currency function input must be the name of a CurrencyField: " + fieldName);
: +        }
: +        CurrencyField ft = (CurrencyField) f.getType();
: +        String code = fp.hasMoreArguments() ? fp.parseArg() : null;
: +        return ft.getConvertedValueSource(code, ft.getValueSource(f, fp));
: +      }
: +    });
:  
:      addParser(new DoubleParser("rad") {
:        @Override
: 
: Modified: lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema15.xml
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema15.xml?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema15.xml (original)
: +++ lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema15.xml Mon Mar  4 20:25:37 2013
: @@ -45,6 +45,7 @@
:      <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" positionIncrementGap="0"/>
:      <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" positionIncrementGap="0"/>
:      <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" positionIncrementGap="0"/>
: +    <fieldType name="currency" class="solr.CurrencyField" currencyConfig="currency.xml" multiValued="false" />
:  
:      <!-- numeric field types that manipulate the value into
:         a string value that isn't human readable in it's internal form,
: @@ -518,6 +519,7 @@
:     <field name="pointD" type="xyd" indexed="true" stored="true" multiValued="false"/>
:     <field name="point_hash" type="geohash" indexed="true" stored="true" multiValued="false"/>
:     <field name="store" type="location" indexed="true" stored="true"/>
: +   <field name="amount" type="currency" indexed="true" stored="true" multiValued="false"/>
:     
:     <!-- to test uniq fields -->   
:     <field name="uniq" type="string" indexed="true" stored="true" multiValued="true"/>
: 
: Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/AbstractCurrencyFieldTest.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/AbstractCurrencyFieldTest.java?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/AbstractCurrencyFieldTest.java (original)
: +++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/AbstractCurrencyFieldTest.java Mon Mar  4 20:25:37 2013
: @@ -297,6 +297,118 @@ public abstract class AbstractCurrencyFi
:      assertQ(req("fl", "*,score", "q", "*:*", "sort", field()+" asc", "limit", "1"), "//int[@name='id']='3'");
:    }
:  
: +  public void testFunctionUsage() throws Exception {
: +    clearIndex();
: +    for (int i = 1; i <= 8; i++) {
: +      // "GBP" currency code is 1/2 of a USD dollar, for testing.
: +      assertU(adoc("id", "" + i, field(), (((float)i)/2) + ",GBP"));
: +    }
: +    for (int i = 9; i <= 11; i++) {
: +      assertU(adoc("id", "" + i, field(), i + ",USD"));
: +    }
: +
: +    assertU(commit());
: +
: +    // direct value source usage, gets "raw" form od default curency
: +    // default==USD, so raw==penies
: +    assertQ(req("fl", "id,func:field($f)",
: +                "f", field(),
: +                "q", "id:5"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=500]");
: +    assertQ(req("fl", "id,func:field($f)",
: +                "f", field(),
: +                "q", "id:10"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=1000]");
: +    assertQ(req("fl", "id,score,"+field(), 
: +                "q", "{!frange u=500}"+field())
: +            ,"//*[@numFound='5']"
: +            ,"//int[@name='id']='1'"
: +            ,"//int[@name='id']='2'"
: +            ,"//int[@name='id']='3'"
: +            ,"//int[@name='id']='4'"
: +            ,"//int[@name='id']='5'"
: +            );
: +    assertQ(req("fl", "id,score,"+field(), 
: +                "q", "{!frange l=500 u=1000}"+field())
: +            ,"//*[@numFound='6']"
: +            ,"//int[@name='id']='5'"
: +            ,"//int[@name='id']='6'"
: +            ,"//int[@name='id']='7'"
: +            ,"//int[@name='id']='8'"
: +            ,"//int[@name='id']='9'"
: +            ,"//int[@name='id']='10'"
: +            );
: +
: +    // use the currency function to convert to default (USD)
: +    assertQ(req("fl", "id,func:currency($f)",
: +                "f", field(),
: +                "q", "id:10"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=10]");
: +    assertQ(req("fl", "id,func:currency($f)",
: +                "f", field(),
: +                "q", "id:5"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=5]");
: +    assertQ(req("fl", "id,score"+field(), 
: +                "f", field(),
: +                "q", "{!frange u=5}currency($f)")
: +            ,"//*[@numFound='5']"
: +            ,"//int[@name='id']='1'"
: +            ,"//int[@name='id']='2'"
: +            ,"//int[@name='id']='3'"
: +            ,"//int[@name='id']='4'"
: +            ,"//int[@name='id']='5'"
: +            );
: +    assertQ(req("fl", "id,score"+field(), 
: +                "f", field(),
: +                "q", "{!frange l=5 u=10}currency($f)")
: +            ,"//*[@numFound='6']"
: +            ,"//int[@name='id']='5'"
: +            ,"//int[@name='id']='6'"
: +            ,"//int[@name='id']='7'"
: +            ,"//int[@name='id']='8'"
: +            ,"//int[@name='id']='9'"
: +            ,"//int[@name='id']='10'"
: +            );
: +    
: +    // use the currency function to convert to MXN
: +    assertQ(req("fl", "id,func:currency($f,MXN)",
: +                "f", field(),
: +                "q", "id:5"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=10]");
: +    assertQ(req("fl", "id,func:currency($f,MXN)",
: +                "f", field(),
: +                "q", "id:10"),
: +            "//*[@numFound='1']",
: +            "//doc/float[@name='func' and .=20]");
: +    assertQ(req("fl", "*,score,"+field(), 
: +                "f", field(),
: +                "q", "{!frange u=10}currency($f,MXN)")
: +            ,"//*[@numFound='5']"
: +            ,"//int[@name='id']='1'"
: +            ,"//int[@name='id']='2'"
: +            ,"//int[@name='id']='3'"
: +            ,"//int[@name='id']='4'"
: +            ,"//int[@name='id']='5'"
: +            );
: +    assertQ(req("fl", "*,score,"+field(), 
: +                "f", field(),
: +                "q", "{!frange l=10 u=20}currency($f,MXN)")
: +            ,"//*[@numFound='6']"
: +            ,"//int[@name='id']='5'"
: +            ,"//int[@name='id']='6'"
: +            ,"//int[@name='id']='7'"
: +            ,"//int[@name='id']='8'"
: +            ,"//int[@name='id']='9'"
: +            ,"//int[@name='id']='10'"
: +            );
: +
: +  }
: +
:    @Test
:    public void testMockFieldType() throws Exception {
:      clearIndex();
: 
: Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java
: URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java?rev=1452483&r1=1452482&r2=1452483&view=diff
: ==============================================================================
: --- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java (original)
: +++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java Mon Mar  4 20:25:37 2013
: @@ -679,6 +679,13 @@ public class QueryEqualityTest extends S
:                       "field('foo_i\')", 
:                       "foo_i");
:    }
: +  public void testFuncCurrency() throws Exception {
: +    assertFuncEquals("currency(\"amount\")", 
: +                     "currency('amount\')",
: +                     "currency(amount)",
: +                     "currency(amount,USD)",
: +                     "currency('amount',USD)");
: +  }
:  
:    public void testTestFuncs() throws Exception {
:      assertFuncEquals("sleep(1,5)", "sleep(1,5)");
: 
: 
: 

-Hoss

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org