You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by gs...@apache.org on 2009/12/24 14:03:24 UTC
svn commit: r893746 [2/2] - in /lucene/solr/trunk: ./ example/exampledocs/
example/solr/conf/ src/common/org/apache/solr/common/
src/java/org/apache/solr/schema/ src/java/org/apache/solr/search/
src/java/org/apache/solr/search/function/ src/java/org/ap...
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/DistanceUtils.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/DistanceUtils.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/DistanceUtils.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/DistanceUtils.java Thu Dec 24 13:03:22 2009
@@ -1,4 +1,6 @@
package org.apache.solr.search.function.distance;
+
+import org.apache.solr.common.SolrException;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -50,5 +52,44 @@
return result;
}
-
+ /**
+ * Given a string containing <i>dimension</i> values encoded in it, separated by commas, return a String array of length <i>dimension</i>
+ * containing the values.
+ * @param out A preallocated array. Must be size dimension. If it is not it will be resized.
+ * @param externalVal The value to parse
+ * @param dimension The expected number of values for the point
+ * @return An array of the values that make up the point (aka vector)
+ *
+ * @throws {@link SolrException} if the dimension specified does not match the number of values in the externalValue.
+ */
+ public static String[] parsePoint(String[] out, String externalVal, int dimension) {
+ //TODO: Should we support sparse vectors?
+ if (out==null || out.length != dimension) out=new String[dimension];
+ int idx = externalVal.indexOf(',');
+ int end = idx;
+ int start = 0;
+ int i = 0;
+ if (idx == -1 && dimension == 1 && externalVal.length() > 0){//we have a single point, dimension better be 1
+ out[0] = externalVal.trim();
+ i = 1;
+ }
+ else if (idx > 0) {//if it is zero, that is an error
+ //Parse out a comma separated list of point values, as in: 73.5,89.2,7773.4
+ for (; i < dimension; i++){
+ while (start<end && externalVal.charAt(start)==' ') start++;
+ while (end>start && externalVal.charAt(end-1)==' ') end--;
+ out[i] = externalVal.substring(start, end);
+ start = idx+1;
+ end = externalVal.indexOf(',', start);
+ if (end == -1){
+ end = externalVal.length();
+ }
+ }
+ }
+ if (i != dimension){
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "incompatible dimension (" + dimension +
+ ") and values (" + externalVal + "). Only " + i + " values specified");
+ }
+ return out;
+ }
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/HaversineFunction.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/HaversineFunction.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/HaversineFunction.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/HaversineFunction.java Thu Dec 24 13:03:22 2009
@@ -18,6 +18,8 @@
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Searcher;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.search.MultiValueSource;
import org.apache.solr.search.function.DocValues;
import org.apache.solr.search.function.ValueSource;
@@ -29,28 +31,31 @@
* Calculate the Haversine formula (distance) between any two points on a sphere
* Takes in four value sources: (latA, lonA); (latB, lonB).
* <p/>
- * Assumes the value sources are in radians
+ * Assumes the value sources are in radians unless
* <p/>
* See http://en.wikipedia.org/wiki/Great-circle_distance and
* http://en.wikipedia.org/wiki/Haversine_formula for the actual formula and
* also http://www.movable-type.co.uk/scripts/latlong.html
- *
- * @see org.apache.solr.search.function.RadianFunction
*/
public class HaversineFunction extends ValueSource {
- private ValueSource x1;
- private ValueSource y1;
- private ValueSource x2;
- private ValueSource y2;
+ private MultiValueSource p1;
+ private MultiValueSource p2;
+ private boolean convertToRadians = false;
private double radius;
- public HaversineFunction(ValueSource x1, ValueSource y1, ValueSource x2, ValueSource y2, double radius) {
- this.x1 = x1;
- this.y1 = y1;
- this.x2 = x2;
- this.y2 = y2;
+ public HaversineFunction(MultiValueSource p1, MultiValueSource p2, double radius) {
+ this(p1, p2, radius, false);
+ }
+
+ public HaversineFunction(MultiValueSource p1, MultiValueSource p2, double radius, boolean convertToRads){
+ this.p1 = p1;
+ this.p2 = p2;
+ if (p1.dimension() != 2 || p2.dimension() != 2) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal dimension for value sources");
+ }
this.radius = radius;
+ this.convertToRadians = convertToRads;
}
protected String name() {
@@ -59,28 +64,40 @@
/**
* @param doc The doc to score
- * @param x1DV
- * @param y1DV
- * @param x2DV
- * @param y2DV
+ * @param p1DV
+ * @param p2DV
* @return The haversine distance formula
*/
- protected double distance(int doc, DocValues x1DV, DocValues y1DV, DocValues x2DV, DocValues y2DV) {
- double x1 = x1DV.doubleVal(doc); //in radians
- double y1 = y1DV.doubleVal(doc);
- double x2 = x2DV.doubleVal(doc);
- double y2 = y2DV.doubleVal(doc);
+ protected double distance(int doc, DocValues p1DV, DocValues p2DV) {
+ double[] p1D = new double[2];
+ double[] p2D = new double[2];
+ p1DV.doubleVal(doc, p1D);
+ p2DV.doubleVal(doc, p2D);
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+ if (convertToRadians) {
+ x1 = p1D[0] * DistanceUtils.DEGREES_TO_RADIANS;
+ y1 = p1D[1] * DistanceUtils.DEGREES_TO_RADIANS;
+ x2 = p2D[0] * DistanceUtils.DEGREES_TO_RADIANS;
+ y2 = p2D[1] * DistanceUtils.DEGREES_TO_RADIANS;
+ } else {
+ x1 = p1D[0];
+ y1 = p1D[1];
+ x2 = p2D[0];
+ y2 = p2D[1];
+ }
return DistanceUtils.haversine(x1, y1, x2, y2, radius);
}
@Override
public DocValues getValues(Map context, IndexReader reader) throws IOException {
- final DocValues x1DV = x1.getValues(context, reader);
- final DocValues y1DV = y1.getValues(context, reader);
- final DocValues x2DV = x2.getValues(context, reader);
- final DocValues y2DV = y2.getValues(context, reader);
+ final DocValues vals1 = p1.getValues(context, reader);
+
+ final DocValues vals2 = p2.getValues(context, reader);
return new DocValues() {
public float floatVal(int doc) {
return (float) doubleVal(doc);
@@ -95,7 +112,7 @@
}
public double doubleVal(int doc) {
- return (double) distance(doc, x1DV, y1DV, x2DV, y2DV);
+ return (double) distance(doc, vals1, vals2);
}
public String strVal(int doc) {
@@ -106,8 +123,7 @@
public String toString(int doc) {
StringBuilder sb = new StringBuilder();
sb.append(name()).append('(');
- sb.append(x1DV.toString(doc)).append(',').append(y1DV.toString(doc)).append(',')
- .append(x2DV.toString(doc)).append(',').append(y2DV.toString(doc));
+ sb.append(vals1.toString(doc)).append(',').append(vals2.toString(doc));
sb.append(')');
return sb.toString();
}
@@ -116,10 +132,9 @@
@Override
public void createWeight(Map context, Searcher searcher) throws IOException {
- x1.createWeight(context, searcher);
- x2.createWeight(context, searcher);
- y1.createWeight(context, searcher);
- y2.createWeight(context, searcher);
+ p1.createWeight(context, searcher);
+ p2.createWeight(context, searcher);
+
}
@Override
@@ -127,20 +142,16 @@
if (this.getClass() != o.getClass()) return false;
HaversineFunction other = (HaversineFunction) o;
return this.name().equals(other.name())
- && x1.equals(other.x1) &&
- y1.equals(other.y1) &&
- x2.equals(other.x2) &&
- y2.equals(other.y2) && radius == other.radius;
+ && p1.equals(other.p1) &&
+ p2.equals(other.p2) && radius == other.radius;
}
@Override
public int hashCode() {
int result;
long temp;
- result = x1.hashCode();
- result = 31 * result + y1.hashCode();
- result = 31 * result + x2.hashCode();
- result = 31 * result + y2.hashCode();
+ result = p1.hashCode();
+ result = 31 * result + p2.hashCode();
result = 31 * result + name().hashCode();
temp = Double.doubleToRawLongBits(radius);
result = 31 * result + (int) (temp ^ (temp >>> 32));
@@ -150,7 +161,7 @@
public String description() {
StringBuilder sb = new StringBuilder();
sb.append(name()).append('(');
- sb.append(x1).append(',').append(y1).append(',').append(x2).append(',').append(y2);
+ sb.append(p1).append(',').append(p2);
sb.append(')');
return sb.toString();
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java Thu Dec 24 13:03:22 2009
@@ -18,6 +18,7 @@
import org.apache.solr.search.function.DocValues;
import org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.MultiValueSource;
import java.util.List;
@@ -30,8 +31,8 @@
public class SquaredEuclideanFunction extends VectorDistanceFunction {
protected String name = "sqedist";
- public SquaredEuclideanFunction(List<ValueSource> sources1, List<ValueSource> sources2) {
- super(-1, sources1, sources2);//overriding distance, so power doesn't matter here
+ public SquaredEuclideanFunction(MultiValueSource source1, MultiValueSource source2) {
+ super(-1, source1, source2);//overriding distance, so power doesn't matter here
}
@@ -43,11 +44,16 @@
/**
* @param doc The doc to score
*/
- protected double distance(int doc, DocValues[] docValues1, DocValues[] docValues2) {
+ protected double distance(int doc, DocValues dv1, DocValues dv2) {
double result = 0;
- for (int i = 0; i < docValues1.length; i++) {
- result += Math.pow(docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc), 2);
- }
+ double [] vals1 = new double[source1.dimension()];
+ double [] vals2 = new double[source1.dimension()];
+ dv1.doubleVal(doc, vals1);
+ dv2.doubleVal(doc, vals2);
+ for (int i = 0; i < vals1.length; i++) {
+ double v = vals1[i] - vals2[i];
+ result += v * v;
+ }
return result;
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java Thu Dec 24 13:03:22 2009
@@ -21,9 +21,9 @@
import org.apache.solr.common.SolrException;
import org.apache.solr.search.function.DocValues;
import org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.MultiValueSource;
import java.io.IOException;
-import java.util.List;
import java.util.Map;
@@ -41,18 +41,18 @@
* @see SquaredEuclideanFunction for the special case
*/
public class VectorDistanceFunction extends ValueSource {
- protected List<ValueSource> sources1, sources2;
+ protected MultiValueSource source1, source2;
protected float power;
protected float oneOverPower;
- public VectorDistanceFunction(float power, List<ValueSource> sources1, List<ValueSource> sources2) {
- this.power = power;
- this.oneOverPower = 1 / power;
- this.sources1 = sources1;
- this.sources2 = sources2;
- if ((sources1.size() != sources2.size())) {
+ public VectorDistanceFunction(float power, MultiValueSource source1, MultiValueSource source2) {
+ if ((source1.dimension() != source2.dimension())) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources");
}
+ this.power = power;
+ this.oneOverPower = 1 / power;
+ this.source1 = source1;
+ this.source2 = source2;
}
protected String name() {
@@ -63,37 +63,39 @@
* Calculate the distance
*
* @param doc The current doc
- * @param docValues1 The values from the first set of value sources
- * @param docValues2 The values from the second set of value sources
+ * @param dv1 The values from the first MultiValueSource
+ * @param dv2 The values from the second MultiValueSource
* @return The distance
*/
- protected double distance(int doc, DocValues[] docValues1, DocValues[] docValues2) {
+ protected double distance(int doc, DocValues dv1, DocValues dv2) {
double result = 0;
//Handle some special cases:
+ double [] vals1 = new double[source1.dimension()];
+ double [] vals2 = new double[source1.dimension()];
+ dv1.doubleVal(doc, vals1);
+ dv2.doubleVal(doc, vals2);
if (power == 0) {
- for (int i = 0; i < docValues1.length; i++) {
- //sparseness measure
- result += docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc) == 0 ? 0 : 1;
+ for (int i = 0; i < vals1.length; i++) {
+ result += vals1[i] - vals2[i] == 0 ? 0 :1;
}
+
} else if (power == 1.0) {
- for (int i = 0; i < docValues1.length; i++) {
- result += docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc);
+ for (int i = 0; i < vals1.length; i++) {
+ result += vals1[i] - vals2[i];
}
} else if (power == 2.0) {
- for (int i = 0; i < docValues1.length; i++) {
- double v = docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc);
+ for (int i = 0; i < vals1.length; i++) {
+ double v = vals1[i] - vals2[i];
result += v * v;
}
result = Math.sqrt(result);
} else if (power == Integer.MAX_VALUE || Double.isInfinite(power)) {//infininte norm?
- for (int i = 0; i < docValues1.length; i++) {
- //TODO: is this the correct infinite norm?
- result = Math.max(docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc), result);
+ for (int i = 0; i < vals1.length; i++) {
+ result = Math.max(vals1[i], vals2[i]);
}
-
} else {
- for (int i = 0; i < docValues1.length; i++) {
- result += Math.pow(docValues1[i].doubleVal(doc) - docValues2[i].doubleVal(doc), power);
+ for (int i = 0; i < vals1.length; i++) {
+ result += Math.pow(vals1[i] - vals2[i], power);
}
result = Math.pow(result, oneOverPower);
}
@@ -103,19 +105,24 @@
@Override
public DocValues getValues(Map context, IndexReader reader) throws IOException {
- final DocValues[] valsArr1 = new DocValues[sources1.size()];
- int i = 0;
- for (ValueSource source : sources1) {
- valsArr1[i++] = source.getValues(context, reader);
- }
- final DocValues[] valsArr2 = new DocValues[sources2.size()];
- i = 0;
- for (ValueSource source : sources2) {
- valsArr2[i++] = source.getValues(context, reader);
- }
+
+ final DocValues vals1 = source1.getValues(context, reader);
+
+ final DocValues vals2 = source2.getValues(context, reader);
+
return new DocValues() {
+ @Override
+ public byte byteVal(int doc) {
+ return (byte) doubleVal(doc);
+ }
+
+ @Override
+ public short shortVal(int doc) {
+ return (short)doubleVal(doc);
+ }
+
public float floatVal(int doc) {
return (float) doubleVal(doc);
}
@@ -129,7 +136,7 @@
}
public double doubleVal(int doc) {
- return distance(doc, valsArr1, valsArr2);
+ return distance(doc, vals1, vals2);
}
public String strVal(int doc) {
@@ -141,18 +148,8 @@
StringBuilder sb = new StringBuilder();
sb.append(name()).append('(').append(power).append(',');
boolean firstTime = true;
- for (DocValues vals : valsArr1) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(',');
- }
- sb.append(vals.toString(doc));
- }
- for (DocValues vals : valsArr2) {
- sb.append(',');//we will always have valsArr1, else there is an error
- sb.append(vals.toString(doc));
- }
+ sb.append(vals1.toString(doc)).append(',');
+ sb.append(vals2.toString(doc));
sb.append(')');
return sb.toString();
}
@@ -161,12 +158,8 @@
@Override
public void createWeight(Map context, Searcher searcher) throws IOException {
- for (ValueSource source : sources1) {
- source.createWeight(context, searcher);
- }
- for (ValueSource source : sources2) {
- source.createWeight(context, searcher);
- }
+ source1.createWeight(context, searcher);
+ source2.createWeight(context, searcher);
}
@Override
@@ -177,16 +170,16 @@
VectorDistanceFunction that = (VectorDistanceFunction) o;
if (Float.compare(that.power, power) != 0) return false;
- if (!sources1.equals(that.sources1)) return false;
- if (!sources2.equals(that.sources2)) return false;
+ if (!source1.equals(that.source1)) return false;
+ if (!source2.equals(that.source2)) return false;
return true;
}
@Override
public int hashCode() {
- int result = sources1.hashCode();
- result = 31 * result + sources2.hashCode();
+ int result = source1.hashCode();
+ result = 31 * result + source2.hashCode();
result = 31 * result + Float.floatToRawIntBits(power);
return result;
}
@@ -195,19 +188,8 @@
public String description() {
StringBuilder sb = new StringBuilder();
sb.append(name()).append('(').append(power).append(',');
- boolean firstTime = true;
- for (ValueSource source : sources1) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(',');
- }
- sb.append(source);
- }
- for (ValueSource source : sources2) {
- sb.append(',');//we will always have sources1, else there is an error
- sb.append(source);
- }
+ sb.append(source1).append(',');
+ sb.append(source2);
sb.append(')');
return sb.toString();
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/update/DocumentBuilder.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/update/DocumentBuilder.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/update/DocumentBuilder.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/update/DocumentBuilder.java Thu Dec 24 13:03:22 2009
@@ -57,19 +57,35 @@
// we don't check for a null val ourselves because a solr.FieldType
// might actually want to map it to something. If createField()
// returns null, then we don't store the field.
- Field field = sfield.createField(val, boost);
- if (field != null) {
- if (!sfield.multiValued()) {
- String oldValue = map.put(sfield.getName(), val);
- if (oldValue != null) {
- throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"ERROR: multiple values encountered for non multiValued field " + sfield.getName()
- + ": first='" + oldValue + "' second='" + val + "'");
+ if (sfield.isPolyField()) {
+ Fieldable[] fields = sfield.createFields(val, boost);
+ if (fields != null && fields.length > 0) {
+ if (!sfield.multiValued()) {
+ String oldValue = map.put(sfield.getName(), val);
+ if (oldValue != null) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: multiple values encountered for non multiValued field " + sfield.getName()
+ + ": first='" + oldValue + "' second='" + val + "'");
+ }
+ }
+ // Add each field
+ for (Fieldable field : fields) {
+ doc.add(field);
+ }
+ }
+ } else {
+ Field field = sfield.createField(val, boost);
+ if (field != null) {
+ if (!sfield.multiValued()) {
+ String oldValue = map.put(sfield.getName(), val);
+ if (oldValue != null) {
+ throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"ERROR: multiple values encountered for non multiValued field " + sfield.getName()
+ + ": first='" + oldValue + "' second='" + val + "'");
+ }
}
}
-
- // field.setBoost(boost);
doc.add(field);
}
+
}
/**
@@ -147,7 +163,7 @@
for (SchemaField field : schema.getRequiredFields()) {
if (doc.getField(field.getName() ) == null) {
if (field.getDefaultValue() != null) {
- doc.add( field.createField( field.getDefaultValue(), 1.0f ) );
+ addField(doc, field, field.getDefaultValue(), 1.0f);
} else {
if (missingFields==null) {
missingFields = new ArrayList<String>(1);
@@ -176,6 +192,19 @@
Document ret = doc; doc=null;
return ret;
}
+
+
+ private static void addField(Document doc, SchemaField field, String val, float boost) {
+ if (field.isPolyField()) {
+ Fieldable[] farr = field.getType().createFields(field, val, boost);
+ for (Fieldable f : farr) {
+ if (f != null) doc.add(f); // null fields are not added
+ }
+ } else {
+ Field f = field.createField(val, boost);
+ if (f != null) doc.add(f); // null fields are not added
+ }
+ }
/**
@@ -230,7 +259,9 @@
isBinaryField = true;
BinaryField binaryField = (BinaryField) sfield.getType();
Field f = binaryField.createField(sfield,v,boost);
- if(f != null) out.add(f);
+ if(f != null){
+ out.add(f);
+ }
used = true;
} else {
// TODO!!! HACK -- date conversion
@@ -243,10 +274,7 @@
if (sfield != null) {
used = true;
- Field f = sfield.createField(val, boost);
- if (f != null) { // null fields are not added
- out.add(f);
- }
+ addField(out, sfield, val, boost);
}
}
@@ -263,17 +291,21 @@
}
used = true;
- Field f = null;
+ //Don't worry about poly fields here
+ Fieldable [] fields = null;
if (isBinaryField) {
if (destinationField.getType() instanceof BinaryField) {
BinaryField binaryField = (BinaryField) destinationField.getType();
- f = binaryField.createField(destinationField, v, boost);
+ //TODO: safe to assume that binary fields only create one?
+ fields = new Field[]{binaryField.createField(destinationField, v, boost)};
}
} else {
- f = destinationField.createField(cf.getLimitedValue(val), boost);
+ fields = destinationField.createFields(cf.getLimitedValue(val), boost);
}
- if (f != null) { // null fields are not added
- out.add(f);
+ if (fields != null) { // null fields are not added
+ for (Fieldable f : fields) {
+ out.add(f);
+ }
}
}
@@ -297,7 +329,7 @@
for (SchemaField field : schema.getRequiredFields()) {
if (out.getField(field.getName() ) == null) {
if (field.getDefaultValue() != null) {
- out.add( field.createField( field.getDefaultValue(), 1.0f ) );
+ addField(out, field, field.getDefaultValue(), 1.0f);
}
else {
String id = schema.printableUniqueKey( out );
Modified: lucene/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java Thu Dec 24 13:03:22 2009
@@ -231,6 +231,17 @@
}
}
+ public void assertQEx(String message, SolrQueryRequest req, SolrException.ErrorCode code ) {
+ try {
+ h.query(req);
+ fail( message );
+ } catch (SolrException e) {
+ assertEquals( code.code, e.code() );
+ } catch (Exception e2) {
+ throw new RuntimeException("Exception during query", e2);
+ }
+ }
+
/**
* @see TestHarness#optimize
Added: lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java (added)
+++ lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,196 @@
+package org.apache.solr.schema;
+/**
+ * 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.
+ */
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.index.IndexReader;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.util.AbstractSolrTestCase;
+import org.apache.solr.common.SolrException;
+
+import java.util.Map;
+import java.util.Random;
+
+
+/**
+ * Test a whole slew of things related to PolyFields
+ */
+public class PolyFieldTest extends AbstractSolrTestCase {
+
+ @Override
+ public String getSchemaFile() {
+ return "schema.xml";
+ }
+
+ @Override
+ public String getSolrConfigFile() {
+ return "solrconfig.xml";
+ }
+
+ public void testSchemaBasics() throws Exception {
+ IndexSchema schema = h.getCore().getSchema();
+
+
+ SchemaField home = schema.getField("home");
+ assertNotNull(home);
+ assertTrue(home.isPolyField());
+
+ SchemaField[] dynFields = schema.getDynamicFieldPrototypes();
+ boolean seen = false;
+ for (SchemaField dynField : dynFields) {
+ if (dynField.getName().equals("*" + FieldType.POLY_FIELD_SEPARATOR + "double")) {
+ seen = true;
+ }
+ }
+ assertTrue("Didn't find the expected dynamic field", seen);
+ FieldType homeFT = schema.getFieldType("home");
+ assertEquals(home.getType(), homeFT);
+ FieldType xy = schema.getFieldTypeByName("xy");
+ assertNotNull(xy);
+ assertTrue(xy instanceof PointType);
+ assertTrue(xy.isPolyField());
+ home = schema.getFieldOrNull("home_0" + FieldType.POLY_FIELD_SEPARATOR + "double");
+ assertNotNull(home);
+ home = schema.getField("home");
+ assertNotNull(home);
+ homeFT = schema.getPolyFieldType("home");
+ assertNotNull(homeFT);
+
+ home = schema.getField("homed");//sub field suffix
+ assertNotNull(home);
+ assertTrue(home.isPolyField());
+
+ try {
+ FieldType bad = schema.getPolyFieldType("foo");
+ assertTrue(false);
+ } catch (Exception e) {
+ }
+ try {
+ FieldType bad = schema.getPolyFieldTypeNoEx("foo");
+ assertNull(bad);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ }
+
+ public void testPointFieldType() throws Exception {
+ SolrCore core = h.getCore();
+ IndexSchema schema = core.getSchema();
+ SchemaField home = schema.getField("home");
+ assertNotNull(home);
+ assertTrue("home is not a poly field", home.isPolyField());
+ FieldType tmp = home.getType();
+ assertTrue(tmp instanceof PointType);
+ PointType pt = (PointType) tmp;
+ assertEquals(pt.getDimension(), 2);
+ double[] xy = new double[]{35.0, -79.34};
+ String point = xy[0] + "," + xy[1];
+ Fieldable[] fields = home.createFields(point, 2);
+ assertEquals(fields.length, 3);//should be 3, we have a stored field
+ //first two fields contain the values, third is just stored and contains the original
+ for (int i = 0; i < 3; i++) {
+ boolean hasValue = fields[1].tokenStreamValue() != null
+ || fields[1].getBinaryValue() != null
+ || fields[1].stringValue() != null;
+ assertTrue("Doesn't have a value: " + fields[1], hasValue);
+ }
+ /*assertTrue("first field " + fields[0].tokenStreamValue() + " is not 35.0", pt.getSubType().toExternal(fields[0]).equals(String.valueOf(xy[0])));
+ assertTrue("second field is not -79.34", pt.getSubType().toExternal(fields[1]).equals(String.valueOf(xy[1])));
+ assertTrue("third field is not '35.0,-79.34'", pt.getSubType().toExternal(fields[2]).equals(point));*/
+
+
+ home = schema.getField("home_ns");
+ assertNotNull(home);
+ fields = home.createFields(point, 2);
+ assertEquals(fields.length, 2);//should be 2, since we aren't storing
+
+ home = schema.getField("home_ns");
+ assertNotNull(home);
+ try {
+ fields = home.createFields("35.0,foo", 2);
+ assertTrue(false);
+ } catch (Exception e) {
+ //
+ }
+ }
+
+ public void testSearching() throws Exception {
+ for (int i = 0; i < 50; i++) {
+ assertU(adoc("id", "" + i, "home", i + "," + (i * 100), "homed", (i * 1000) + "," + (i * 10000)));
+ }
+ assertU(commit());
+ IndexReader reader = h.getCore().getSearcher().get().getReader();
+ /*for (int i = 0; i < 50; i++){
+ Document doc = reader.document(i);
+ System.out.println("Doc: " + doc.get("homed_0___double"));
+ }*/
+ assertQ(req("fl", "*,score", "q", "*:*"), "//*[@numFound='50']");
+ assertQ(req("fl", "*,score", "q", "home:1,100"),
+ "//*[@numFound='1']",
+ "//str[@name='home'][.='1,100']");
+ assertQ(req("fl", "*,score", "q", "homed:1000,10000"),
+ "//*[@numFound='1']",
+ "//str[@name='homed'][.='1000,10000']");
+ assertQ(req("fl", "*,score", "q",
+ "{!func}sqedist(home, toMultiVS(0, 0))"),
+ "\"//*[@numFound='50']\"");
+ assertQ(req("fl", "*,score", "q",
+ "{!func}dist(2, home, toMultiVS(0, 0))"),
+ "\"//*[@numFound='50']\"");
+
+ assertQ(req("fl", "*,score", "q",
+ "home:[10,10000 TO 30,30000]"),
+ "\"//*[@numFound='3']\"");
+ assertQ(req("fl", "*,score", "q",
+ "homed:[1,1000 TO 2000,35000]"),
+ "\"//*[@numFound='2']\"");
+ //bad
+
+ assertQEx("Query should throw an exception due to incorrect dimensions", req("fl", "*,score", "q",
+ "homed:[1 TO 2000]"), SolrException.ErrorCode.BAD_REQUEST);
+ }
+
+
+
+ public void testSearchDetails() throws Exception {
+ SolrCore core = h.getCore();
+ IndexSchema schema = core.getSchema();
+ double[] xy = new double[]{35.0, -79.34};
+ String point = xy[0] + "," + xy[1];
+ //How about some queries?
+ //don't need a parser for this path currently. This may change
+ assertU(adoc("id", "0", "home_ns", point));
+ assertU(commit());
+ SchemaField home = schema.getField("home_ns");
+ PointType pt = (PointType) home.getType();
+ assertEquals(pt.getDimension(), 2);
+ Query q = pt.getFieldQuery(null, home, point);
+ assertNotNull(q);
+ assertTrue(q instanceof BooleanQuery);
+ //should have two clauses, one for 35.0 and the other for -79.34
+ BooleanQuery bq = (BooleanQuery) q;
+ BooleanClause[] clauses = bq.getClauses();
+ assertEquals(clauses.length, 2);
+
+ }
+}
\ No newline at end of file
Propchange: lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java Thu Dec 24 13:03:22 2009
@@ -16,9 +16,9 @@
* limitations under the License.
*/
+import org.apache.lucene.spatial.geohash.GeoHashUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.util.AbstractSolrTestCase;
-import org.apache.lucene.spatial.geohash.GeoHashUtils;
/**
@@ -44,20 +44,21 @@
assertU(adoc("id", "2", "x_td", "0", "y_td", String.valueOf(Math.PI / 2), "gh_s", GeoHashUtils.encode(32.7693246, -78.9289094)));
assertU(adoc("id", "3", "x_td", String.valueOf(Math.PI / 2), "y_td", String.valueOf(Math.PI / 2), "gh_s", GeoHashUtils.encode(32.7693246, -80.9289094)));
assertU(adoc("id", "4", "x_td", String.valueOf(Math.PI / 4), "y_td", String.valueOf(Math.PI / 4), "gh_s", GeoHashUtils.encode(32.7693246, -81.9289094)));
+ assertU(adoc("id", "5", "x_td", "45.0", "y_td", "45.0",
+ "gh_s", GeoHashUtils.encode(32.7693246, -81.9289094)));
assertU(commit());
//Get the haversine distance between the point 0,0 and the docs above assuming a radius of 1
- assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:1"), "//float[@name='score']='0.0'");
- assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:2"), "//float[@name='score']='" + (float) (Math.PI / 2) + "'");
- assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:3"), "//float[@name='score']='" + (float) (Math.PI / 2) + "'");
- assertQ(req("fl", "*,score", "q", "{!func}hsin(x_td, y_td, 0, 0, 1)", "fq", "id:4"), "//float[@name='score']='1.0471976'");
+ assertQ(req("fl", "*,score", "q", "{!func}hsin(1, x_td, y_td, 0, 0)", "fq", "id:1"), "//float[@name='score']='0.0'");
+ assertQ(req("fl", "*,score", "q", "{!func}hsin(1, x_td, y_td, 0, 0)", "fq", "id:2"), "//float[@name='score']='" + (float) (Math.PI / 2) + "'");
+ assertQ(req("fl", "*,score", "q", "{!func}hsin(1, x_td, y_td, 0, 0)", "fq", "id:3"), "//float[@name='score']='" + (float) (Math.PI / 2) + "'");
+ assertQ(req("fl", "*,score", "q", "{!func}hsin(1, x_td, y_td, 0, 0)", "fq", "id:4"), "//float[@name='score']='1.0471976'");
+ assertQ(req("fl", "*,score", "q", "{!func}hsin(1, x_td, y_td, 0, 0, true)", "fq", "id:5"), "//float[@name='score']='1.0471976'");
//Geo Hash Haversine
//Can verify here: http://www.movable-type.co.uk/scripts/latlong.html, but they use a slightly different radius for the earth, so just be close
- assertQ(req("fl", "*,score", "q", "{!func}ghhsin(gh_s, \"" + GeoHashUtils.encode(32, -79) +
- "\"," + Constants.EARTH_RADIUS_KM +
- ")", "fq", "id:1"), "//float[@name='score']='122.30894'");
- assertQ(req("fl", "*,score", "q", "{!func}ghhsin(gh_s, geohash(32, -79)," + Constants.EARTH_RADIUS_KM +
- ")", "fq", "id:1"), "//float[@name='score']='122.30894'");
+ assertQ(req("fl", "*,score", "q", "{!func}ghhsin(" + Constants.EARTH_RADIUS_KM + ", gh_s, \"" + GeoHashUtils.encode(32, -79) +
+ "\",)", "fq", "id:1"), "//float[@name='score']='122.30894'");
+ assertQ(req("fl", "*,score", "q", "{!func}ghhsin(" + Constants.EARTH_RADIUS_KM + ", gh_s, geohash(32, -79))", "fq", "id:1"), "//float[@name='score']='122.30894'");
}
public void testVector() throws Exception {
@@ -66,6 +67,8 @@
assertU(adoc("id", "3", "x_td", "1", "y_td", "1", "z_td", "1", "w_td", "1"));
assertU(adoc("id", "4", "x_td", "1", "y_td", "0", "z_td", "0", "w_td", "0"));
assertU(adoc("id", "5", "x_td", "2.3", "y_td", "5.5", "z_td", "7.9", "w_td", "-2.4"));
+ assertU(adoc("id", "6", "point", "1.0,0.0"));
+ assertU(adoc("id", "7", "point", "5.5,10.9"));
assertU(commit());
//two dimensions, notice how we only pass in 4 value sources
assertQ(req("fl", "*,score", "q", "{!func}sqedist(x_td, y_td, 0, 0)", "fq", "id:1"), "//float[@name='score']='0.0'");
@@ -111,6 +114,15 @@
assertQ(req("fl", "*,score", "q", "{!func}dist(1, x_td, y_td, 0, 0)", "fq", "id:3"), "//float[@name='score']='" + (float) 2.0 + "'");
assertQ(req("fl", "*,score", "q", "{!func}dist(1, x_td, y_td, 0, 0)", "fq", "id:4"), "//float[@name='score']='1.0'");
assertQ(req("fl", "*,score", "q", "{!func}dist(1, x_td, y_td, 0, 0)", "fq", "id:5"), "//float[@name='score']='" + (float) (2.3 + 5.5) + "'");
+
+
+ //Do point tests:
+ assertQ(req("fl", "*,score", "q", "{!func}dist(1, toMultiVS(x_td, y_td), toMultiVS(0, 0))", "fq", "id:5"),
+ "//float[@name='score']='" + (float) (2.3 + 5.5) + "'");
+
+ assertQ(req("fl", "*,score", "q", "{!func}dist(1, point, toMultiVS(0, 0))", "fq", "id:6"),
+ "//float[@name='score']='" + 0.0f + "'");
+
}
}
Modified: lucene/solr/trunk/src/test/org/apache/solr/update/DocumentBuilderTest.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/update/DocumentBuilderTest.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/update/DocumentBuilderTest.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/update/DocumentBuilderTest.java Thu Dec 24 13:03:22 2009
@@ -22,6 +22,7 @@
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.core.SolrCore;
import org.apache.solr.util.AbstractSolrTestCase;
+import org.apache.solr.schema.FieldType;
/**
*
@@ -59,4 +60,17 @@
Document out = DocumentBuilder.toDocument( doc, core.getSchema() );
assertNull( out.get( "name" ) );
}
+
+ public void testMultiField() throws Exception {
+ SolrCore core = h.getCore();
+
+ // make sure a null value is not indexed
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.addField( "home", "2.2,3.3", 1.0f );
+ Document out = DocumentBuilder.toDocument( doc, core.getSchema() );
+ assertNotNull( out.get( "home" ) );//contains the stored value and term vector, if there is one
+ assertNotNull( out.getField( "home_0" + FieldType.POLY_FIELD_SEPARATOR + "double" ) );
+ assertNotNull( out.getField( "home_1" + FieldType.POLY_FIELD_SEPARATOR + "double" ) );
+ }
+
}
Modified: lucene/solr/trunk/src/test/test-files/solr/conf/schema.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/conf/schema.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/conf/schema.xml (original)
+++ lucene/solr/trunk/src/test/test-files/solr/conf/schema.xml Thu Dec 24 13:03:22 2009
@@ -367,6 +367,12 @@
</fieldtype>
<fieldType name="uuid" class="solr.UUIDField" />
+
+ <!-- Try out some point types -->
+ <fieldType name="xy" class="solr.PointType" dimension="2" subFieldType="double"/>
+ <fieldType name="tenD" class="solr.PointType" dimension="10" subFieldType="double"/>
+ <!-- Use the sub field suffix -->
+ <fieldType name="xyd" class="solr.PointType" dimension="2" subFieldSuffix="*_d"/>
</types>
@@ -392,6 +398,15 @@
<field name="shouldbestored" type="unstored" stored="true"/>
<field name="shouldbeunindexed" type="unstored" indexed="false" stored="true"/>
+ <!-- Test points -->
+ <!-- Test points -->
+ <field name="home" type="xy" indexed="true" stored="true" multiValued="false"/>
+ <field name="homed" type="xyd" indexed="true" stored="true" multiValued="false"/>
+ <field name="home_ns" type="xy" indexed="true" stored="false" multiValued="false"/>
+ <field name="work" type="xy" indexed="true" stored="true" multiValued="false"/>
+
+ <field name="point10" type="tenD" indexed="true" stored="true" multiValued="false"/>
+
<!-- test different combinations of indexed and stored -->
<field name="bind" type="boolean" indexed="true" stored="false"/>
Modified: lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml (original)
+++ lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml Thu Dec 24 13:03:22 2009
@@ -251,6 +251,10 @@
<fieldType name="tdoubles" class="solr.TrieDoubleField" omitNorms="true" positionIncrementGap="0" precisionStep="0" multiValued="true" />
<fieldType name="tdates" class="solr.TrieDateField" omitNorms="true" positionIncrementGap="0" precisionStep="0" multiValued="true" />
+ <!-- Poly field -->
+ <fieldType name="xy" class="solr.PointType" dimension="2" subFieldType="double"/>
+ <fieldType name="xyd" class="solr.PointType" dimension="2" subFieldSuffix="*_d"/>
+
</types>
@@ -275,7 +279,11 @@
<!-- for testing, a type that does a transform to see if it's correctly done everywhere -->
<field name="id" type="sfloat" indexed="true" stored="true" required="true" />
- <field name="text" type="text" indexed="true" stored="false" />
+ <field name="text" type="text" indexed="true" stored="false" />
+
+ <!-- Test a point field for distances -->
+ <field name="point" type="xy" indexed="true" stored="true" multiValued="false"/>
+ <field name="pointD" type="xyd" indexed="true" stored="true" multiValued="false"/>
<!-- Dynamic field definitions. If a field name is not found, dynamicFields
will be used if the name matches any of the patterns.