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