1
package org.apache.solr.search.function.distance;
3
* Licensed to the Apache Software Foundation (ASF) under one or more
4
* contributor license agreements. See the NOTICE file distributed with
5
* this work for additional information regarding copyright ownership.
6
* The ASF licenses this file to You under the Apache License, Version 2.0
7
* (the "License"); you may not use this file except in compliance with
8
* the License. You may obtain a copy of the License at
10
* http://www.apache.org/licenses/LICENSE-2.0
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
19
import org.apache.lucene.index.IndexReader;
20
import org.apache.lucene.search.Searcher;
21
import org.apache.lucene.spatial.DistanceUtils;
22
import org.apache.solr.common.SolrException;
23
import org.apache.solr.search.function.DocValues;
24
import org.apache.solr.search.function.MultiValueSource;
25
import org.apache.solr.search.function.ValueSource;
27
import java.io.IOException;
32
* Calculate the p-norm for a Vector. See http://en.wikipedia.org/wiki/Lp_space
36
* <li>0 = Sparseness calculation</li>
37
* <li>1 = Manhattan distance</li>
38
* <li>2 = Euclidean distance</li>
39
* <li>Integer.MAX_VALUE = infinite norm</li>
42
* @see SquaredEuclideanFunction for the special case
44
public class VectorDistanceFunction extends ValueSource {
45
protected MultiValueSource source1, source2;
46
protected float power;
47
protected float oneOverPower;
49
public VectorDistanceFunction(float power, MultiValueSource source1, MultiValueSource source2) {
50
if ((source1.dimension() != source2.dimension())) {
51
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources");
54
this.oneOverPower = 1 / power;
55
this.source1 = source1;
56
this.source2 = source2;
59
protected String name() {
64
* Calculate the distance
66
* @param doc The current doc
67
* @param dv1 The values from the first MultiValueSource
68
* @param dv2 The values from the second MultiValueSource
69
* @return The distance
71
protected double distance(int doc, DocValues dv1, DocValues dv2) {
72
//Handle some special cases:
73
double[] vals1 = new double[source1.dimension()];
74
double[] vals2 = new double[source1.dimension()];
75
dv1.doubleVal(doc, vals1);
76
dv2.doubleVal(doc, vals2);
77
return DistanceUtils.vectorDistance(vals1, vals2, power, oneOverPower);
81
public DocValues getValues(Map context, IndexReader reader) throws IOException {
83
final DocValues vals1 = source1.getValues(context, reader);
85
final DocValues vals2 = source2.getValues(context, reader);
88
return new DocValues() {
90
public byte byteVal(int doc) {
91
return (byte) doubleVal(doc);
95
public short shortVal(int doc) {
96
return (short) doubleVal(doc);
100
public float floatVal(int doc) {
101
return (float) doubleVal(doc);
105
public int intVal(int doc) {
106
return (int) doubleVal(doc);
110
public long longVal(int doc) {
111
return (long) doubleVal(doc);
115
public double doubleVal(int doc) {
116
return distance(doc, vals1, vals2);
120
public String strVal(int doc) {
121
return Double.toString(doubleVal(doc));
125
public String toString(int doc) {
126
StringBuilder sb = new StringBuilder();
127
sb.append(name()).append('(').append(power).append(',');
128
boolean firstTime = true;
129
sb.append(vals1.toString(doc)).append(',');
130
sb.append(vals2.toString(doc));
132
return sb.toString();
138
public void createWeight(Map context, Searcher searcher) throws IOException {
139
source1.createWeight(context, searcher);
140
source2.createWeight(context, searcher);
144
public boolean equals(Object o) {
145
if (this == o) return true;
146
if (!(o instanceof VectorDistanceFunction)) return false;
148
VectorDistanceFunction that = (VectorDistanceFunction) o;
150
if (Float.compare(that.power, power) != 0) return false;
151
if (!source1.equals(that.source1)) return false;
152
if (!source2.equals(that.source2)) return false;
158
public int hashCode() {
159
int result = source1.hashCode();
160
result = 31 * result + source2.hashCode();
161
result = 31 * result + Float.floatToRawIntBits(power);
166
public String description() {
167
StringBuilder sb = new StringBuilder();
168
sb.append(name()).append('(').append(power).append(',');
169
sb.append(source1).append(',');
172
return sb.toString();