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 [1/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...
Author: gsingers
Date: Thu Dec 24 13:03:22 2009
New Revision: 893746
URL: http://svn.apache.org/viewvc?rev=893746&view=rev
Log:
SOLR-1132: Added support for poly fields
Added:
lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java (with props)
lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java (with props)
lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java (with props)
lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java (with props)
lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java (with props)
lucene/solr/trunk/src/test/org/apache/solr/schema/PolyFieldTest.java (with props)
Modified:
lucene/solr/trunk/CHANGES.txt
lucene/solr/trunk/example/exampledocs/hd.xml
lucene/solr/trunk/example/exampledocs/ipod_other.xml
lucene/solr/trunk/example/exampledocs/ipod_video.xml
lucene/solr/trunk/example/exampledocs/mem.xml
lucene/solr/trunk/example/exampledocs/monitor.xml
lucene/solr/trunk/example/exampledocs/monitor2.xml
lucene/solr/trunk/example/exampledocs/mp500.xml
lucene/solr/trunk/example/exampledocs/sd500.xml
lucene/solr/trunk/example/exampledocs/vidcard.xml
lucene/solr/trunk/example/solr/conf/schema.xml
lucene/solr/trunk/src/common/org/apache/solr/common/SolrException.java
lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java
lucene/solr/trunk/src/java/org/apache/solr/schema/TextField.java
lucene/solr/trunk/src/java/org/apache/solr/search/FieldQParserPlugin.java
lucene/solr/trunk/src/java/org/apache/solr/search/SolrQueryParser.java
lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/DocValues.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/DistanceUtils.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/HaversineFunction.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java
lucene/solr/trunk/src/java/org/apache/solr/update/DocumentBuilder.java
lucene/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java
lucene/solr/trunk/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java
lucene/solr/trunk/src/test/org/apache/solr/update/DocumentBuilderTest.java
lucene/solr/trunk/src/test/test-files/solr/conf/schema.xml
lucene/solr/trunk/src/test/test-files/solr/conf/schema11.xml
Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Thu Dec 24 13:03:22 2009
@@ -74,6 +74,9 @@
* SOLR-1653: Add PatternReplaceCharFilter (koji)
+* SOLR-1131: FieldTypes can now output multiple Fields per Type and still be searched. This can be handy for hiding the details of a particular
+ implementation such as in the spatial case. (Chris Mattmann, shalin, noble, gsingers, yonik)
+
Optimizations
----------------------
Modified: lucene/solr/trunk/example/exampledocs/hd.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/hd.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/hd.xml (original)
+++ lucene/solr/trunk/example/exampledocs/hd.xml Thu Dec 24 13:03:22 2009
@@ -28,6 +28,7 @@
<field name="popularity">6</field>
<field name="inStock">true</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+ <field name="store">45.17614,-93.87341</field>
</doc>
<doc>
@@ -42,6 +43,8 @@
<field name="price">350</field>
<field name="popularity">6</field>
<field name="inStock">true</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
</doc>
</add>
Modified: lucene/solr/trunk/example/exampledocs/ipod_other.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/ipod_other.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/ipod_other.xml (original)
+++ lucene/solr/trunk/example/exampledocs/ipod_other.xml Thu Dec 24 13:03:22 2009
@@ -28,6 +28,8 @@
<field name="price">19.95</field>
<field name="popularity">1</field>
<field name="inStock">false</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
<field name="manufacturedate_dt">2005-08-01T16:30:25Z</field>
</doc>
@@ -42,6 +44,8 @@
<field name="price">11.50</field>
<field name="popularity">1</field>
<field name="inStock">false</field>
+ <!-- San Francisco store -->
+ <field name="store">37.7752,-122.4232</field>
<field name="manufacturedate_dt">2006-02-14T23:55:59Z</field>
</doc>
Modified: lucene/solr/trunk/example/exampledocs/ipod_video.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/ipod_video.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/ipod_video.xml (original)
+++ lucene/solr/trunk/example/exampledocs/ipod_video.xml Thu Dec 24 13:03:22 2009
@@ -32,5 +32,7 @@
<field name="price">399.00</field>
<field name="popularity">10</field>
<field name="inStock">true</field>
+ <!-- San Francisco store -->
+ <field name="store">37.7752,-122.4232</field>
<field name="manufacturedate_dt">2005-10-12T08:00:00Z</field>
</doc></add>
Modified: lucene/solr/trunk/example/exampledocs/mem.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/mem.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/mem.xml (original)
+++ lucene/solr/trunk/example/exampledocs/mem.xml Thu Dec 24 13:03:22 2009
@@ -26,6 +26,8 @@
<field name="price">185</field>
<field name="popularity">5</field>
<field name="inStock">true</field>
+ <!-- San Francisco store -->
+ <field name="store">37.7752,-122.4232</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
</doc>
@@ -38,6 +40,8 @@
<field name="price">74.99</field>
<field name="popularity">7</field>
<field name="inStock">true</field>
+ <!-- San Francisco store -->
+ <field name="store">37.7752,-122.4232</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
</doc>
@@ -51,6 +55,8 @@
<!-- note: price & popularity is missing on this one -->
<field name="popularity">0</field>
<field name="inStock">true</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
</doc>
Modified: lucene/solr/trunk/example/exampledocs/monitor.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/monitor.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/monitor.xml (original)
+++ lucene/solr/trunk/example/exampledocs/monitor.xml Thu Dec 24 13:03:22 2009
@@ -27,5 +27,7 @@
<field name="price">2199</field>
<field name="popularity">6</field>
<field name="inStock">true</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
</doc></add>
Modified: lucene/solr/trunk/example/exampledocs/monitor2.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/monitor2.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/monitor2.xml (original)
+++ lucene/solr/trunk/example/exampledocs/monitor2.xml Thu Dec 24 13:03:22 2009
@@ -26,5 +26,7 @@
<field name="price">279.95</field>
<field name="popularity">6</field>
<field name="inStock">true</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
</doc></add>
Modified: lucene/solr/trunk/example/exampledocs/mp500.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/mp500.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/mp500.xml (original)
+++ lucene/solr/trunk/example/exampledocs/mp500.xml Thu Dec 24 13:03:22 2009
@@ -35,5 +35,7 @@
<field name="price">179.99</field>
<field name="popularity">6</field>
<field name="inStock">true</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
</doc></add>
Modified: lucene/solr/trunk/example/exampledocs/sd500.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/sd500.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/sd500.xml (original)
+++ lucene/solr/trunk/example/exampledocs/sd500.xml Thu Dec 24 13:03:22 2009
@@ -31,4 +31,6 @@
<field name="popularity">7</field>
<field name="inStock">true</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+ <!-- Buffalo store -->
+ <field name="store">45.17614,-93.87341</field>
</doc></add>
Modified: lucene/solr/trunk/example/exampledocs/vidcard.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/exampledocs/vidcard.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/exampledocs/vidcard.xml (original)
+++ lucene/solr/trunk/example/exampledocs/vidcard.xml Thu Dec 24 13:03:22 2009
@@ -30,6 +30,7 @@
<field name="weight">16</field>
<field name="price">479.95</field>
<field name="popularity">7</field>
+ <field name="store">40.7143,-74.006</field>
<field name="inStock">false</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z/DAY</field>
</doc>
@@ -50,5 +51,7 @@
<field name="popularity">7</field>
<field name="inStock">false</field>
<field name="manufacturedate_dt">2006-02-13T15:26:37Z/DAY</field>
+ <!-- NYC store -->
+ <field name="store">40.7143,-74.006</field>
</doc>
</add>
Modified: lucene/solr/trunk/example/solr/conf/schema.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/example/solr/conf/schema.xml?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/example/solr/conf/schema.xml (original)
+++ lucene/solr/trunk/example/solr/conf/schema.xml Thu Dec 24 13:03:22 2009
@@ -394,7 +394,12 @@
<!-- since fields of this type are by default not stored or indexed,
any data added to them will be ignored outright. -->
- <fieldtype name="ignored" stored="false" indexed="false" multiValued="true" class="solr.StrField" />
+ <fieldtype name="ignored" stored="false" indexed="false" multiValued="true" class="solr.StrField" />
+
+ <!--
+ A PointType is a Poly Field. It can either declare a subFieldType or a subFieldSuffix
+ -->
+ <fieldType name="location" class="solr.PointType" dimension="2" subFieldType="double"/>
</types>
@@ -440,6 +445,8 @@
<field name="popularity" type="int" indexed="true" stored="true" />
<field name="inStock" type="boolean" indexed="true" stored="true" />
+ <field name="store" type="location" indexed="true" stored="true"/>
+
<!-- Common metadata fields, named specifically to match up with
SolrCell metadata when parsing rich documents such as Word, PDF.
Modified: lucene/solr/trunk/src/common/org/apache/solr/common/SolrException.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/common/org/apache/solr/common/SolrException.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/common/org/apache/solr/common/SolrException.java (original)
+++ lucene/solr/trunk/src/common/org/apache/solr/common/SolrException.java Thu Dec 24 13:03:22 2009
@@ -38,7 +38,7 @@
SERVER_ERROR( 500 ),
SERVICE_UNAVAILABLE( 503 ),
UNKNOWN(0);
- final int code;
+ public final int code;
private ErrorCode( int c )
{
Added: lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,138 @@
+/**
+ * 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.
+ */
+
+package org.apache.solr.schema;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.function.ValueSource;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.params.MapSolrParams;
+
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * A CoordinateFieldType is the base class for {@link org.apache.solr.schema.FieldType}s that have semantics
+ * related to items in a coordinate system.
+ * <br/>
+ * Implementations depend on a delegating work to a sub {@link org.apache.solr.schema.FieldType}, specified by
+ * either the {@link #SUB_FIELD_SUFFIX} or the {@link #SUB_FIELD_TYPE} (the latter is used if both are defined.
+ * <br/>
+ * Example:
+ * <pre><fieldType name="xy" class="solr.PointType" dimension="2" subFieldType="double"/>
+ * </pre>
+ * In theory, classes deriving from this should be able to do things like represent a point, a polygon, a line, etc.
+ * <br/>
+ * NOTE: There can only be one sub Field Type.
+ *
+ */
+public abstract class CoordinateFieldType extends FieldType implements SchemaAware {
+ /**
+ * The dimension of the coordinate system
+ */
+ protected int dimension;
+ protected FieldType subType;
+ public static final String SUB_FIELD_SUFFIX = "subFieldSuffix";
+ public static final String SUB_FIELD_TYPE = "subFieldType";
+ private String suffix;//need to keep this around between init and inform, since dynamic fields aren't created until before inform
+ protected int dynFieldProps;
+
+ public int getDimension() {
+ return dimension;
+ }
+
+ public FieldType getSubType() {
+ return subType;
+ }
+
+ @Override
+ protected void init(IndexSchema schema, Map<String, String> args) {
+
+ //it's not a first class citizen for the IndexSchema
+ SolrParams p = new MapSolrParams(args);
+ String subFT = p.get(SUB_FIELD_TYPE);
+ String subSuffix = p.get(SUB_FIELD_SUFFIX);
+ if (subFT != null) {
+ args.remove(SUB_FIELD_TYPE);
+ subType = schema.getFieldTypeByName(subFT.trim());
+ } else if (subSuffix != null) {
+ args.remove(SUB_FIELD_SUFFIX);
+ suffix = subSuffix;
+ }else {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "The field type: " + typeName
+ + " must specify the " +
+ SUB_FIELD_TYPE + " attribute or the " + SUB_FIELD_SUFFIX + " attribute.");
+ }
+
+ super.init(schema, args);
+ }
+
+ public void inform(IndexSchema schema) {
+ //Can't do this until here b/c the Dynamic Fields are not initialized until here.
+ if (suffix != null){
+ SchemaField sf = schema.getField(suffix);
+ subType = sf.getType();//this means it is already registered
+ dynFieldProps = sf.getProperties();
+ }
+ else if (subType != null) {
+ SchemaField proto = registerPolyFieldDynamicPrototype(schema, subType);
+ dynFieldProps = proto.getProperties();
+ } else {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "The field type: " + typeName
+ + " must specify the " +
+ SUB_FIELD_TYPE + " attribute or the " + SUB_FIELD_SUFFIX + " attribute.");
+ }
+ }
+
+ /**
+ * Helper method for creating a dynamic field SchemaField prototype. Returns a {@link org.apache.solr.schema.SchemaField} with
+ * the {@link org.apache.solr.schema.FieldType} given and a name of "*" + {@link org.apache.solr.schema.FieldType#POLY_FIELD_SEPARATOR} + {@link org.apache.solr.schema.FieldType#typeName}
+ * and props of indexed=true, stored=false.
+ * @param schema the IndexSchema
+ * @param type The {@link org.apache.solr.schema.FieldType} of the prototype.
+ * @return The {@link org.apache.solr.schema.SchemaField}
+ */
+
+ static SchemaField registerPolyFieldDynamicPrototype(IndexSchema schema, FieldType type){
+ String name = "*" + FieldType.POLY_FIELD_SEPARATOR + type.typeName;
+ Map<String, String> props = new HashMap<String, String>();
+ //Just set these, delegate everything else to the field type
+ props.put("indexed", "true");
+ props.put("stored", "false");
+ int p = SchemaField.calcProps(name, type, props);
+ SchemaField proto = SchemaField.create(name,
+ type, p, null);
+ schema.registerDynamicField(proto);
+ return proto;
+ }
+
+
+ /**
+ * Throws UnsupportedOperationException()
+ */
+ public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
+ throw new UnsupportedOperationException();
+ }
+
+}
Propchange: lucene/solr/trunk/src/java/org/apache/solr/schema/CoordinateFieldType.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/FieldType.java Thu Dec 24 13:03:22 2009
@@ -20,14 +20,14 @@
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
-import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.tokenattributes.TermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermRangeQuery;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
import org.apache.solr.search.function.ValueSource;
import org.apache.solr.search.function.OrdFieldSource;
import org.apache.solr.search.Sorting;
@@ -36,11 +36,17 @@
import org.apache.solr.request.TextResponseWriter;
import org.apache.solr.analysis.SolrAnalyzer;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.params.MapSolrParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.ArrayList;
import java.io.Reader;
import java.io.IOException;
@@ -52,6 +58,14 @@
public abstract class FieldType extends FieldProperties {
public static final Logger log = LoggerFactory.getLogger(FieldType.class);
+ /**
+ * The default poly field separator.
+ *
+ * @see #createFields(SchemaField, String, float)
+ * @see #isPolyField()
+ */
+ public static final String POLY_FIELD_SEPARATOR = "___";
+
/** The name of the type (not the name of the field) */
protected String typeName;
/** additional arguments specified in the field type declaration */
@@ -59,9 +73,10 @@
/** properties explicitly set to true */
protected int trueProperties;
/** properties explicitly set to false */
- protected int falseProperties;
+ protected int falseProperties;
int properties;
+
/** Returns true if fields of this type should be tokenized */
public boolean isTokenized() {
return (properties & TOKENIZED) != 0;
@@ -72,6 +87,18 @@
return (properties & MULTIVALUED) != 0;
}
+ /**
+ * A "polyField" is a FieldType that can produce more than one Field per FieldType, via the {@link #createFields(org.apache.solr.schema.SchemaField, String, float)} method. This is useful
+ * when hiding the implementation details of a field from the Solr end user. For instance, a spatial point may be represented by three different field types, all of which may produce 1 or more
+ * fields.
+ * @return true if the {@link #createFields(org.apache.solr.schema.SchemaField, String, float)} method may return more than one field
+ */
+ public boolean isPolyField(){
+ return false;
+ }
+
+
+
/** Returns true if a single field value of this type has multiple logical values
* for the purposes of faceting, sorting, etc. Text fields normally return
* true since each token/word is a logical value.
@@ -85,7 +112,8 @@
* Common boolean properties have already been handled.
*
*/
- protected void init(IndexSchema schema, Map<String,String> args) {
+ protected void init(IndexSchema schema, Map<String, String> args) {
+
}
protected String getArg(String n, Map<String,String> args) {
@@ -191,8 +219,15 @@
* :TODO: clean up and clarify this explanation.
*
* @see #toInternal
+ *
+ *
*/
public Field createField(SchemaField field, String externalVal, float boost) {
+ if (!field.indexed() && !field.stored()) {
+ if (log.isTraceEnabled())
+ log.trace("Ignoring unindexed/unstored field: " + field);
+ return null;
+ }
String val;
try {
val = toInternal(externalVal);
@@ -200,23 +235,123 @@
throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Error while creating field '" + field + "' from value '" + externalVal + "'", e, false);
}
if (val==null) return null;
- if (!field.indexed() && !field.stored()) {
- if (log.isTraceEnabled())
- log.trace("Ignoring unindexed/unstored field: " + field);
- return null;
+
+ return createField(field.getName(), val, getFieldStore(field, val),
+ getFieldIndex(field, val), getFieldTermVec(field, val), field.omitNorms(),
+ field.omitTf(), boost);
+ }
+
+
+
+ /**
+ * Create multiple fields from a single field and multiple values. Fields are named as SchemaField.getName() + {@link #POLY_FIELD_SEPARATOR} + i, where
+ * i starts at 0.
+ * <p/>
+ * If the field is stored, then an extra field gets created that contains the storageVal. It is this field that also
+ *
+ * @param field The {@link org.apache.solr.schema.SchemaField}
+ * @param props The properties to use
+ * @param delegatedType An optional type to use. If null, then field.getType() is used. Useful for poly fields.
+ * @param storageVal If the field stores, then this value will be used for the stored field
+ * @param boost The boost to apply to all fields
+ * @param externalVals The values to use
+ * @return The fields
+ */
+ protected Fieldable[] createFields(SchemaField field, int props,
+ FieldType delegatedType, String storageVal,
+ float boost, String ... externalVals) {
+ int n = field.indexed() ? externalVals.length : 0;
+ n += field.stored() ? 1 : 0;
+ if (delegatedType == null) { //if the type isn't being overriden, then just use the base one
+ delegatedType = field.getType();
}
+ Field[] results = new Field[n];
+ //Field.Store.NO,Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO, true, true
+ if (externalVals.length > 0) {
+ if (field.indexed()) {
+ String name = field.getName() + "_";
+ String suffix = POLY_FIELD_SEPARATOR + delegatedType.typeName;
+
+ int len = name.length();
+ StringBuilder bldr = new StringBuilder(len + 3 + suffix.length());//should be enough buffer to handle most values of j.
+ bldr.append(name);
+ for (int j = 0; j < externalVals.length; j++) {
+ //SchemaField is final, as is name, so we need to recreate each time
+ //put the counter before the separator, b/c dynamic fields can't be asterisks on both the front and the end of the String
+ bldr.append(j).append(suffix);
+ SchemaField sf = SchemaField.create(bldr.toString(),
+ delegatedType, props, null);
+ //schema.getDynamicField(name + "_" + j + POLY_FIELD_SEPARATOR + delegatedType.typeName);
+ /**/
+ //new SchemaField(name, ft, p, defaultValue )
+ //QUESTION: should we allow for vectors, etc? Not sure that it makes sense
+ results[j] = delegatedType.createField(sf, externalVals[j], boost);
+ bldr.setLength(len);//cut the builder back to just the length of the prefix, but keep the capacity
+ }
+ }
+ Field.TermVector fieldTermVec = getFieldTermVec(field, storageVal);
+ if (field.stored() || fieldTermVec.equals(Field.TermVector.YES)
+ || fieldTermVec.equals(Field.TermVector.WITH_OFFSETS)
+ || fieldTermVec.equals(Field.TermVector.WITH_POSITIONS)
+ || fieldTermVec.equals(Field.TermVector.WITH_POSITIONS_OFFSETS)
+ ) {
+
+ //QUESTION: should we allow for vectors, etc? Not sure that it makes sense
+ results[results.length - 1] = createField(field.getName(), storageVal, getFieldStore(field, storageVal),
+ Field.Index.NO,
+ fieldTermVec, field.omitNorms(), field.omitTf(), boost);
+
+ }
+
+ }
+ return results;
+ }
- Field f = new Field(field.getName(),
+ /**
+ * Create the field from native Lucene parts. Mostly intended for use by FieldTypes outputing multiple
+ * Fields per SchemaField
+ * @param name The name of the field
+ * @param val The _internal_ value to index
+ * @param storage {@link org.apache.lucene.document.Field.Store}
+ * @param index {@link org.apache.lucene.document.Field.Index}
+ * @param vec {@link org.apache.lucene.document.Field.TermVector}
+ * @param omitNorms true if norms should be omitted
+ * @param omitTFPos true if term freq and position should be omitted.
+ * @param boost The boost value
+ * @return the {@link org.apache.lucene.document.Field}.
+ */
+ protected Field createField(String name, String val, Field.Store storage, Field.Index index,
+ Field.TermVector vec, boolean omitNorms, boolean omitTFPos, float boost){
+ Field f = new Field(name,
val,
- getFieldStore(field, val),
- getFieldIndex(field, val),
- getFieldTermVec(field, val));
- f.setOmitNorms(field.omitNorms());
- f.setOmitTermFreqAndPositions(field.omitTf());
+ storage,
+ index,
+ vec);
+ f.setOmitNorms(omitNorms);
+ f.setOmitTermFreqAndPositions(omitTFPos);
f.setBoost(boost);
return f;
}
+
+ /**
+ * Given a {@link org.apache.solr.schema.SchemaField}, create one or more {@link org.apache.lucene.document.Field} instances
+ * @param field the {@link org.apache.solr.schema.SchemaField}
+ * @param externalVal The value to add to the field
+ * @param boost The boost to apply
+ * @return The {@link org.apache.lucene.document.Field} instances
+ *
+ * @see #createField(SchemaField, String, float)
+ * @see #isPolyField()
+ */
+ public Fieldable[] createFields(SchemaField field, String externalVal, float boost) {
+ Field f = createField( field, externalVal, boost);
+ if( f != null ) {
+ return new Field[] { f };
+ }
+ return null;
+ }
+
/* Helpers for field construction */
protected Field.TermVector getFieldTermVec(SchemaField field,
String internalVal) {
@@ -226,7 +361,7 @@
else if (field.storeTermPositions())
ftv = Field.TermVector.WITH_POSITIONS;
else if (field.storeTermOffsets())
- ftv = Field.TermVector.WITH_OFFSETS;
+ ftv = Field.TermVector.WITH_OFFSETS;
else if (field.storeTermVector())
ftv = Field.TermVector.YES;
return ftv;
@@ -237,7 +372,7 @@
}
protected Field.Index getFieldIndex(SchemaField field,
String internalVal) {
- return field.indexed() ? (isTokenized() ? Field.Index.TOKENIZED :
+ return field.indexed() ? (isTokenized() ? Field.Index.TOKENIZED :
Field.Index.UN_TOKENIZED) : Field.Index.NO;
}
@@ -265,7 +400,7 @@
}
/**
- * Convert the stored-field format to an external object.
+ * Convert the stored-field format to an external object.
* @see #toInternal
* @since solr 1.3
*/
@@ -290,7 +425,7 @@
// that the indexed form is the same as the stored field form.
return f.stringValue();
}
-
+
/** Given the readable value, return the term value that will match it. */
public String readableToIndexed(String val) {
return toInternal(val);
@@ -321,7 +456,7 @@
termAtt.setTermBuffer(s);
offsetAtt.setOffset(correctOffset(0),correctOffset(n));
return true;
- }
+ }
};
return new TokenStreamInfo(ts, ts);
@@ -335,7 +470,7 @@
* @see #getAnalyzer
*/
protected Analyzer analyzer=new DefaultAnalyzer(256);
-
+
/**
* Analyzer set by schema for text types to use when searching fields
* of this type, subclasses can set analyzer themselves or override
@@ -394,7 +529,7 @@
*/
public abstract void write(TextResponseWriter writer, String name, Fieldable f) throws IOException;
-
+
/**
* Returns the SortField instance that should be used to sort fields
* of this type.
@@ -452,4 +587,36 @@
minInclusive, maxInclusive);
}
+ /**
+ * Returns a Query instance for doing searches against a field.
+ * @param parser The {@link org.apache.solr.search.QParser} calling the method
+ * @param field The {@link org.apache.solr.schema.SchemaField} of the field to search
+ * @param externalVal The String representation of the value to search
+ * @return The {@link org.apache.lucene.search.Query} instance. This implementation returns a {@link org.apache.lucene.search.TermQuery} but overriding queries may not
+ *
+ */
+ public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
+ return new TermQuery(new Term(field.getName(), toInternal(externalVal)));
+ }
+
+
+ /**
+ * Return a collection of all the Fields in the index where the {@link org.apache.solr.schema.SchemaField}
+ * @param polyField The instance of the {@link org.apache.solr.schema.SchemaField} to find the actual field names from
+ * @return The {@link java.util.Collection} of names of the actual fields that are a poly field.
+ *
+ *
+ */
+ /*protected Collection<String> getPolyFieldNames(SchemaField polyField){
+ if (polyField.isPolyField()) {
+ if (polyField != null) {
+ //we need the names of all the fields. Do this lazily and then cache?
+
+
+ }
+ } //TODO: Should we throw an exception here in an else clause?
+ return Collections.emptyList();
+ }*/
+
+
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java Thu Dec 24 13:03:22 2009
@@ -65,6 +65,30 @@
private float version;
private final SolrResourceLoader loader;
+ private final HashMap<String, SchemaField> fields = new HashMap<String,SchemaField>();
+
+
+ private final HashMap<String, FieldType> fieldTypes = new HashMap<String,FieldType>();
+
+ private final List<SchemaField> fieldsWithDefaultValue = new ArrayList<SchemaField>();
+ private final Collection<SchemaField> requiredFields = new HashSet<SchemaField>();
+ private DynamicField[] dynamicFields;
+
+ private Analyzer analyzer;
+ private Analyzer queryAnalyzer;
+
+ private String defaultSearchFieldName=null;
+ private String queryParserDefaultOperator = "OR";
+
+
+ private final Map<String, List<CopyField>> copyFieldsMap = new HashMap<String, List<CopyField>>();
+ private DynamicCopy[] dynamicCopyFields;
+ /**
+ * keys are all fields copied to, count is num of copyField
+ * directives that target them.
+ */
+ private Map<SchemaField, Integer> copyFieldTargetCounts
+ = new HashMap<SchemaField, Integer>();
/**
* Constructs a schema using the specified file name using the normal
* Config path directory searching rules.
@@ -156,10 +180,7 @@
@Deprecated
public String getName() { return name; }
- private final HashMap<String, SchemaField> fields = new HashMap<String,SchemaField>();
- private final HashMap<String, FieldType> fieldTypes = new HashMap<String,FieldType>();
- private final List<SchemaField> fieldsWithDefaultValue = new ArrayList<SchemaField>();
- private final Collection<SchemaField> requiredFields = new HashSet<SchemaField>();
+ ;
/**
* Provides direct access to the Map containing all explicit
@@ -218,7 +239,7 @@
*/
public SimilarityFactory getSimilarityFactory() { return similarityFactory; }
- private Analyzer analyzer;
+
/**
* Returns the Analyzer used when indexing documents for this index
@@ -230,7 +251,7 @@
*/
public Analyzer getAnalyzer() { return analyzer; }
- private Analyzer queryAnalyzer;
+
/**
* Returns the Analyzer used when searching this index
@@ -242,8 +263,7 @@
*/
public Analyzer getQueryAnalyzer() { return queryAnalyzer; }
- private String defaultSearchFieldName=null;
- private String queryParserDefaultOperator = "OR";
+
/**
* A SolrQueryParser linked to this IndexSchema for field datatype
@@ -399,7 +419,7 @@
Config schemaConf = new Config(loader, "schema", is, "/schema/");
Document document = schemaConf.getDocument();
final XPath xpath = schemaConf.getXPath();
-
+ final List<SchemaAware> schemaAware = new ArrayList<SchemaAware>();
Node nd = (Node) xpath.evaluate("/schema/@name", document, XPathConstants.NODE);
if (nd==null) {
log.warn("schema has no name!");
@@ -434,6 +454,9 @@
ft.setAnalyzer(analyzer);
ft.setQueryAnalyzer(queryAnalyzer);
}
+ if (ft instanceof SchemaAware){
+ schemaAware.add((SchemaAware) ft);
+ }
return ft;
}
@@ -494,7 +517,6 @@
SolrException.logOnce(log,null,t);
SolrConfig.severeErrors.add( t );
}
-
log.debug("field defined: " + f);
if( f.getDefaultValue() != null ) {
log.debug(name+" contains default value: " + f.getDefaultValue());
@@ -506,23 +528,7 @@
}
} else if (node.getNodeName().equals("dynamicField")) {
// make sure nothing else has the same path
- boolean dup = false;
- for( DynamicField df : dFields ) {
- if( df.regex.equals( f.name ) ) {
- String msg = "[schema.xml] Duplicate DynamicField definition for '"
- + f.getName() + "' ignoring: "+f.toString();
-
- Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
- SolrException.logOnce(log,null,t);
- SolrConfig.severeErrors.add( t );
- dup = true;
- break;
- }
- }
- if( !dup ) {
- dFields.add(new DynamicField(f));
- log.debug("dynamic field defined: " + f);
- }
+ addDynamicField(dFields, f);
} else {
// we should never get here
throw new RuntimeException("Unknown field type");
@@ -534,6 +540,7 @@
// in DocumentBuilder.getDoc()
requiredFields.addAll(getFieldsWithDefaultValue());
+
// OK, now sort the dynamic fields largest to smallest size so we don't get
// any false matches. We want to act like a compiler tool and try and match
// the largest string possible.
@@ -568,6 +575,9 @@
}
};
}
+ if (similarityFactory instanceof SchemaAware){
+ schemaAware.add((SchemaAware) similarityFactory);
+ }
log.debug("using similarity factory" + similarityFactory.getClass().getName());
}
@@ -652,7 +662,10 @@
entry.getValue()+")");
}
}
-
+ //Run the callbacks on SchemaAware now that everything else is done
+ for (SchemaAware aware : schemaAware) {
+ aware.inform(this);
+ }
} catch (SolrException e) {
SolrConfig.severeErrors.add( e );
throw e;
@@ -664,6 +677,56 @@
// create the field analyzers
refreshAnalyzers();
+
+ }
+
+ private void addDynamicField(List<DynamicField> dFields, SchemaField f) {
+ boolean dup = isDuplicateDynField(dFields, f);
+ if( !dup ) {
+ addDynamicFieldNoDupCheck(dFields, f);
+ } else {
+ String msg = "[schema.xml] Duplicate DynamicField definition for '"
+ + f.getName() + "' ignoring: " + f.toString();
+
+ Throwable t = new SolrException(SolrException.ErrorCode.SERVER_ERROR, msg);
+ SolrException.logOnce(log, null, t);
+ SolrConfig.severeErrors.add(t);
+ }
+ }
+
+ /**
+ * Register one or more new Dynamic Field with the Schema.
+ * @param f The {@link org.apache.solr.schema.SchemaField}
+ */
+ public void registerDynamicField(SchemaField ... f) {
+ List<DynamicField> dynFields = new ArrayList<DynamicField>(Arrays.asList(dynamicFields));
+ for (SchemaField field : f) {
+ if (isDuplicateDynField(dynFields, field) == false) {
+ log.debug("dynamic field creation for schema field: " + field.getName());
+ addDynamicFieldNoDupCheck(dynFields, field);
+ } else {
+ log.debug("dynamic field creation avoided: dynamic field: [" + field.getName() + "] " +
+ "already defined in the schema!");
+ }
+ }
+ Collections.sort(dynFields);
+ dynamicFields = (DynamicField[]) dynFields.toArray(new DynamicField[dynFields.size()]);
+ }
+
+ private void addDynamicFieldNoDupCheck(List<DynamicField> dFields, SchemaField f) {
+ dFields.add(new DynamicField(f));
+ log.debug("dynamic field defined: " + f);
+ }
+
+ private boolean isDuplicateDynField(List<DynamicField> dFields, SchemaField f) {
+ boolean dup = false;
+ for( DynamicField df : dFields ) {
+ if( df.regex.equals( f.name ) ) {
+ dup = true;
+ break;
+ }
+ }
+ return dup;
}
public void registerCopyField( String source, String dest )
@@ -987,7 +1050,7 @@
}
}
- private DynamicField[] dynamicFields;
+
public SchemaField[] getDynamicFieldPrototypes() {
SchemaField[] df = new SchemaField[dynamicFields.length];
for (int i=0;i<dynamicFields.length;i++) {
@@ -1038,42 +1101,43 @@
}
return false;
- }
-
+ }
+
/**
* Returns the SchemaField that should be used for the specified field name, or
* null if none exists.
*
- * @param fieldName may be an explicitly defined field, or a name that
+ * @param fieldName may be an explicitly defined field, a PolyField, or a name that
* matches a dynamic field.
* @see #getFieldType
+ * @see #getField(String)
+ * @return The {@link org.apache.solr.schema.SchemaField}
*/
public SchemaField getFieldOrNull(String fieldName) {
- SchemaField f = fields.get(fieldName);
+ SchemaField f = fields.get(fieldName);
if (f != null) return f;
for (DynamicField df : dynamicFields) {
if (df.matches(fieldName)) return df.makeSchemaField(fieldName);
}
-
+
return f;
}
/**
* Returns the SchemaField that should be used for the specified field name
*
- * @param fieldName may be an explicitly defined field, or a name that
+ * @param fieldName may be an explicitly defined field, a PolyField type, or a name that
* matches a dynamic field.
* @throws SolrException if no such field exists
* @see #getFieldType
+ * @see #getFieldOrNull(String)
+ * @return The {@link SchemaField}
*/
public SchemaField getField(String fieldName) {
- SchemaField f = fields.get(fieldName);
+ SchemaField f = getFieldOrNull(fieldName);
if (f != null) return f;
- for (DynamicField df : dynamicFields) {
- if (df.matches(fieldName)) return df.makeSchemaField(fieldName);
- }
// Hmmm, default field could also be implemented with a dynamic field of "*".
// It would have to be special-cased and only used if nothing else matched.
@@ -1105,6 +1169,16 @@
}
/**
+ * Given the name of a {@link org.apache.solr.schema.FieldType} (not to be confused with {@link #getFieldType(String)} which
+ * takes in the name of a field), return the {@link org.apache.solr.schema.FieldType}.
+ * @param fieldTypeName The name of the {@link org.apache.solr.schema.FieldType}
+ * @return The {@link org.apache.solr.schema.FieldType} or null.
+ */
+ public FieldType getFieldTypeByName(String fieldTypeName){
+ return fieldTypes.get(fieldTypeName);
+ }
+
+ /**
* Returns the FieldType for the specified field name.
*
* <p>
@@ -1149,15 +1223,22 @@
return null;
};
-
- private final Map<String, List<CopyField>> copyFieldsMap = new HashMap<String, List<CopyField>>();
- private DynamicCopy[] dynamicCopyFields;
/**
- * keys are all fields copied to, count is num of copyField
- * directives that target them.
+ *
+ * @param fieldName The name of the field
+ * @return the {@link FieldType} or a {@link org.apache.solr.common.SolrException} if the field is not a poly field.
*/
- private Map<SchemaField, Integer> copyFieldTargetCounts
- = new HashMap<SchemaField, Integer>();
+ public FieldType getPolyFieldType(String fieldName){
+ SchemaField f = fields.get(fieldName);
+ if (f != null && f.isPolyField()) return f.getType();
+ throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"undefined field or not a poly field "+fieldName);
+ }
+
+ public FieldType getPolyFieldTypeNoEx(String fieldName){
+ SchemaField f = fields.get(fieldName);
+ if (f != null && f.isPolyField()) return f.getType();
+ return null;
+ }
/**
* Get all copy fields, both the static and the dynamic ones.
Added: lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,276 @@
+/**
+ * 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.
+ */
+
+package org.apache.solr.schema;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.SortField;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.TextResponseWriter;
+import org.apache.solr.request.XMLWriter;
+import org.apache.solr.search.MultiValueSource;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.function.DocValues;
+import org.apache.solr.search.function.ValueSource;
+import org.apache.solr.search.function.distance.DistanceUtils;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * A point type that indexes a point in an n-dimensional space as separate fields and uses
+ * range queries for bounding box calculations.
+ * <p/>
+ * <p/>
+ * NOTE: There can only be one sub type
+ */
+public class PointType extends CoordinateFieldType {
+ /**
+ * 2 dimensional by default
+ */
+ public static final int DEFAULT_DIMENSION = 2;
+ public static final String DIMENSION = "dimension";
+
+ protected IndexSchema schema; // needed for retrieving SchemaFields
+
+
+ @Override
+ protected void init(IndexSchema schema, Map<String, String> args) {
+ SolrParams p = new MapSolrParams(args);
+ dimension = p.getInt(DIMENSION, DEFAULT_DIMENSION);
+ if (dimension < 1) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "The dimension must be > 0: " + dimension);
+ }
+ args.remove(DIMENSION);
+ this.schema = schema;
+ super.init(schema, args);
+
+ }
+
+
+ @Override
+ public boolean isPolyField() {
+ return true; // really only true if the field is indexed
+ }
+
+ @Override
+ public Fieldable[] createFields(SchemaField field, String externalVal, float boost) {
+ String[] point = DistanceUtils.parsePoint(null, externalVal, dimension);
+ return createFields(field, dynFieldProps, subType, externalVal, boost, point);
+ }
+
+ @Override
+ public ValueSource getValueSource(SchemaField field, QParser parser) {
+ return new PointTypeValueSource(field, dimension, subType, parser);
+ }
+
+
+ //It never makes sense to create a single field, so make it impossible to happen
+ @Override
+ public Field createField(SchemaField field, String externalVal, float boost) {
+ throw new UnsupportedOperationException("PointType uses multiple fields. field=" + field.getName());
+ }
+
+ @Override
+ public void write(XMLWriter xmlWriter, String name, Fieldable f) throws IOException {
+ xmlWriter.writeStr(name, f.stringValue());
+ }
+
+ @Override
+ public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException {
+ writer.writeStr(name, f.stringValue(), false);
+ }
+
+ @Override
+ public SortField getSortField(SchemaField field, boolean top) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Sorting not suported on DualPointType " + field.getName());
+ }
+
+ @Override
+ /**
+ * Care should be taken in calling this with higher order dimensions for performance reasons.
+ */
+ public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
+ //Query could look like: [x1,y1 TO x2,y2] for 2 dimension, but could look like: [x1,y1,z1 TO x2,y2,z2], and can be extrapolated to n-dimensions
+ //thus, this query essentially creates a box, cube, etc.
+ String[] p1 = DistanceUtils.parsePoint(null, part1, dimension);
+ String[] p2 = DistanceUtils.parsePoint(null, part2, dimension);
+ BooleanQuery result = new BooleanQuery(true);
+ String name = field.getName() + "_";
+ String suffix = POLY_FIELD_SEPARATOR + subType.typeName;
+ int len = name.length();
+ StringBuilder bldr = new StringBuilder(len + 3 + suffix.length());//should be enough buffer to handle most values of j.
+ bldr.append(name);
+ for (int i = 0; i < dimension; i++) {
+ bldr.append(i).append(suffix);
+ SchemaField subSF = schema.getField(bldr.toString());
+ // points must currently be ordered... should we support specifying any two opposite corner points?
+
+ /*new TermRangeQuery(
+ field.getName() + i + POLY_FIELD_SEPARATOR + subType.typeName,
+ subType.toInternal(p1[i]),
+ subType.toInternal(p2[i]),
+ minInclusive, maxInclusive);*/
+ result.add(subType.getRangeQuery(parser, subSF, p1[i], p2[i], minInclusive, maxInclusive), BooleanClause.Occur.MUST);
+ bldr.setLength(len);
+ }
+ return result;
+ }
+
+ @Override
+ public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
+ Query result = null;
+
+ String[] p1 = DistanceUtils.parsePoint(null, externalVal, dimension);
+ //TODO: should we assert that p1.length == dimension?
+ BooleanQuery bq = new BooleanQuery(true);
+ String name = field.getName() + "_";
+ String suffix = POLY_FIELD_SEPARATOR + subType.typeName;
+ int len = name.length();
+ StringBuilder bldr = new StringBuilder(len + 3 + suffix.length());//should be enough buffer to handle most values of j.
+ bldr.append(name);
+ for (int i = 0; i < dimension; i++) {
+ bldr.append(i).append(suffix);
+ SchemaField sf1 = schema.getField(bldr.toString());
+ Query tq = subType.getFieldQuery(parser, sf1, p1[i]);
+ //new TermQuery(new Term(bldr.toString(), subType.toInternal(p1[i])));
+ bq.add(tq, BooleanClause.Occur.MUST);
+ bldr.setLength(len);
+ }
+ result = bq;
+
+ return result;
+ }
+
+ class PointTypeValueSource extends MultiValueSource {
+ protected SchemaField field;
+ protected FieldType subType;
+ protected int dimension;
+ private QParser parser;
+
+ public PointTypeValueSource(SchemaField field, int dimension, FieldType subType, QParser parser) {
+ this.field = field;
+ this.dimension = dimension;
+ this.subType = subType;
+ this.parser = parser;
+ }
+
+ @Override
+ public void createWeight(Map context, Searcher searcher) throws IOException {
+ String name = field.getName();
+ String suffix = FieldType.POLY_FIELD_SEPARATOR + subType.typeName;
+ int len = name.length();
+ StringBuilder bldr = new StringBuilder(len + 3 + suffix.length());//should be enough buffer to handle most values of j.
+ bldr.append(name);
+ for (int i = 0; i < dimension; i++) {
+ bldr.append(i).append(suffix);
+ SchemaField sf = schema.getField(bldr.toString());
+ subType.getValueSource(sf, parser).createWeight(context, searcher);
+ bldr.setLength(len);
+ }
+ }
+
+ public int dimension() {
+ return dimension;
+ }
+
+ @Override
+ public DocValues getValues(Map context, IndexReader reader) throws IOException {
+ final DocValues[] valsArr1 = new DocValues[dimension];
+ String name = field.getName();
+ String suffix = FieldType.POLY_FIELD_SEPARATOR + subType.typeName;
+ int len = name.length();
+ StringBuilder bldr = new StringBuilder(len + 3 + suffix.length());//should be enough buffer to handle most values of j.
+ bldr.append(name);
+ for (int i = 0; i < dimension; i++) {
+ bldr.append(i).append(suffix);
+ SchemaField sf = schema.getField(bldr.toString());
+ valsArr1[i] = subType.getValueSource(sf, parser).getValues(context, reader);
+ bldr.setLength(len);
+ }
+ return new DocValues() {
+ //TODO: not sure how to handle the other types at this moment
+ @Override
+ public void doubleVal(int doc, double[] vals) {
+ //TODO: check whether vals.length == dimension or assume its handled elsewhere?
+ for (int i = 0; i < dimension; i++) {
+ vals[i] = valsArr1[i].doubleVal(doc);
+ }
+ }
+
+
+ @Override
+ public String toString(int doc) {
+ StringBuilder sb = new StringBuilder("point(");
+ boolean firstTime = true;
+ for (DocValues docValues : valsArr1) {
+ if (firstTime == false) {
+ sb.append(",");
+ } else {
+ firstTime = true;
+ }
+ sb.append(docValues.toString(doc));
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+ };
+ }
+
+ public String description() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("point(");
+ sb.append("fld=").append(field.name).append(", subType=").append(subType.typeName)
+ .append(", dimension=").append(dimension).append(')');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PointTypeValueSource)) return false;
+
+ PointTypeValueSource that = (PointTypeValueSource) o;
+
+ if (dimension != that.dimension) return false;
+ if (!field.equals(that.field)) return false;
+ if (!subType.equals(that.subType)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = field.hashCode();
+ result = 31 * result + subType.hashCode();
+ result = 31 * result + dimension;
+ return result;
+ }
+}
+
+}
+
+
Propchange: lucene/solr/trunk/src/java/org/apache/solr/schema/PointType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,39 @@
+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.
+ */
+
+
+/**
+* An interface that can be extended to provide a callback mechanism for
+* informing an {@link IndexSchema} instance of changes to it, dynamically
+* performed at runtime.
+*
+* @since SOLR-1131
+ *
+ **/
+public interface SchemaAware {
+ /**
+ * Informs the {@link IndexSchema} provided by the <code>schema</code>
+ * parameter of an event (e.g., a new {@link FieldType} was added, etc.
+ *
+ * @param schema
+ * The {@link IndexSchema} instance that inform of the update to.
+ *
+ * @since SOLR-1131
+ */
+ public void inform(IndexSchema schema);
+}
Propchange: lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaAware.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/SchemaField.java Thu Dec 24 13:03:22 2009
@@ -90,9 +90,23 @@
boolean isTokenized() { return (properties & TOKENIZED)!=0; }
boolean isBinary() { return (properties & BINARY)!=0; }
+
public Field createField(String val, float boost) {
return type.createField(this,val,boost);
}
+
+ public Fieldable[] createFields(String val, float boost) {
+ return type.createFields(this,val,boost);
+ }
+
+ /**
+ * If true, then use {@link #createFields(String, float)}, else use {@link #createField} to save an extra allocation
+ * @return true if this field is a poly field
+ */
+ public boolean isPolyField(){
+ return type.isPolyField();
+ }
+
@Override
public String toString() {
@@ -119,6 +133,29 @@
static SchemaField create(String name, FieldType ft, Map<String,String> props) {
+
+ String defaultValue = null;
+ if( props.containsKey( "default" ) ) {
+ defaultValue = (String)props.get( "default" );
+ }
+ return new SchemaField(name, ft, calcProps(name, ft, props), defaultValue );
+ }
+
+ /**
+ * Create a SchemaField w/ the props specified. Does not support a default value.
+ * @param name The name of the SchemaField
+ * @param ft The {@link org.apache.solr.schema.FieldType} of the field
+ * @param props The props. See {@link #calcProps(String, org.apache.solr.schema.FieldType, java.util.Map)}
+ * @param defValue The default Value for the field
+ * @return The SchemaField
+ *
+ * @see #create(String, FieldType, java.util.Map)
+ */
+ static SchemaField create(String name, FieldType ft, int props, String defValue){
+ return new SchemaField(name, ft, props, defValue);
+ }
+
+ static int calcProps(String name, FieldType ft, Map<String, String> props) {
int trueProps = parseProperties(props,true);
int falseProps = parseProperties(props,false);
@@ -166,12 +203,7 @@
p &= ~falseProps;
p |= trueProps;
-
- String defaultValue = null;
- if( props.containsKey( "default" ) ) {
- defaultValue = (String)props.get( "default" );
- }
- return new SchemaField(name, ft, p, defaultValue );
+ return p;
}
public String getDefaultValue() {
Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/TextField.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/TextField.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/TextField.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/TextField.java Thu Dec 24 13:03:22 2009
@@ -18,12 +18,28 @@
package org.apache.solr.schema;
import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.PhraseQuery;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
+import org.apache.lucene.analysis.tokenattributes.TermAttribute;
+import org.apache.lucene.analysis.CachingTokenFilter;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Analyzer;
import org.apache.solr.request.XMLWriter;
import org.apache.solr.request.TextResponseWriter;
+import org.apache.solr.search.QParser;
import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
import java.io.IOException;
+import java.io.StringReader;
/** <code>TextField</code> is the basic type for configurable text analysis.
* Analyzers for field types using this implementation should be defined in the schema.
@@ -48,4 +64,190 @@
public void write(TextResponseWriter writer, String name, Fieldable f) throws IOException {
writer.writeStr(name, f.stringValue(), true);
}
+
+ @Override
+ public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
+ return parseFieldQuery(parser, getQueryAnalyzer(), field.getName(), externalVal);
+ }
+
+
+ static Query parseFieldQuery(QParser parser, Analyzer analyzer, String field, String queryText) {
+ int phraseSlop = 0;
+ boolean enablePositionIncrements = true;
+
+ // most of the following code is taken from the Lucene QueryParser
+
+ // Use the analyzer to get all the tokens, and then build a TermQuery,
+ // PhraseQuery, or nothing based on the term count
+
+ TokenStream source;
+ try {
+ source = analyzer.reusableTokenStream(field, new StringReader(queryText));
+ source.reset();
+ } catch (IOException e) {
+ source = analyzer.tokenStream(field, new StringReader(queryText));
+ }
+ CachingTokenFilter buffer = new CachingTokenFilter(source);
+ TermAttribute termAtt = null;
+ PositionIncrementAttribute posIncrAtt = null;
+ int numTokens = 0;
+
+ boolean success = false;
+ try {
+ buffer.reset();
+ success = true;
+ } catch (IOException e) {
+ // success==false if we hit an exception
+ }
+ if (success) {
+ if (buffer.hasAttribute(TermAttribute.class)) {
+ termAtt = (TermAttribute) buffer.getAttribute(TermAttribute.class);
+ }
+ if (buffer.hasAttribute(PositionIncrementAttribute.class)) {
+ posIncrAtt = (PositionIncrementAttribute) buffer.getAttribute(PositionIncrementAttribute.class);
+ }
+ }
+
+ int positionCount = 0;
+ boolean severalTokensAtSamePosition = false;
+
+ boolean hasMoreTokens = false;
+ if (termAtt != null) {
+ try {
+ hasMoreTokens = buffer.incrementToken();
+ while (hasMoreTokens) {
+ numTokens++;
+ int positionIncrement = (posIncrAtt != null) ? posIncrAtt.getPositionIncrement() : 1;
+ if (positionIncrement != 0) {
+ positionCount += positionIncrement;
+ } else {
+ severalTokensAtSamePosition = true;
+ }
+ hasMoreTokens = buffer.incrementToken();
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ try {
+ // rewind the buffer stream
+ buffer.reset();
+
+ // close original stream - all tokens buffered
+ source.close();
+ }
+ catch (IOException e) {
+ // ignore
+ }
+
+ if (numTokens == 0)
+ return null;
+ else if (numTokens == 1) {
+ String term = null;
+ try {
+ boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+ } catch (IOException e) {
+ // safe to ignore, because we know the number of tokens
+ }
+ // return newTermQuery(new Term(field, term));
+ return new TermQuery(new Term(field, term));
+ } else {
+ if (severalTokensAtSamePosition) {
+ if (positionCount == 1) {
+ // no phrase query:
+ // BooleanQuery q = newBooleanQuery(true);
+ BooleanQuery q = new BooleanQuery(true);
+ for (int i = 0; i < numTokens; i++) {
+ String term = null;
+ try {
+ boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+ } catch (IOException e) {
+ // safe to ignore, because we know the number of tokens
+ }
+
+ // Query currentQuery = newTermQuery(new Term(field, term));
+ Query currentQuery = new TermQuery(new Term(field, term));
+ q.add(currentQuery, BooleanClause.Occur.SHOULD);
+ }
+ return q;
+ }
+ else {
+ // phrase query:
+ // MultiPhraseQuery mpq = newMultiPhraseQuery();
+ MultiPhraseQuery mpq = new MultiPhraseQuery();
+ mpq.setSlop(phraseSlop);
+ List multiTerms = new ArrayList();
+ int position = -1;
+ for (int i = 0; i < numTokens; i++) {
+ String term = null;
+ int positionIncrement = 1;
+ try {
+ boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+ if (posIncrAtt != null) {
+ positionIncrement = posIncrAtt.getPositionIncrement();
+ }
+ } catch (IOException e) {
+ // safe to ignore, because we know the number of tokens
+ }
+
+ if (positionIncrement > 0 && multiTerms.size() > 0) {
+ if (enablePositionIncrements) {
+ mpq.add((Term[])multiTerms.toArray(new Term[0]),position);
+ } else {
+ mpq.add((Term[])multiTerms.toArray(new Term[0]));
+ }
+ multiTerms.clear();
+ }
+ position += positionIncrement;
+ multiTerms.add(new Term(field, term));
+ }
+ if (enablePositionIncrements) {
+ mpq.add((Term[])multiTerms.toArray(new Term[0]),position);
+ } else {
+ mpq.add((Term[])multiTerms.toArray(new Term[0]));
+ }
+ return mpq;
+ }
+ }
+ else {
+ // PhraseQuery pq = newPhraseQuery();
+ PhraseQuery pq = new PhraseQuery();
+ pq.setSlop(phraseSlop);
+ int position = -1;
+
+
+ for (int i = 0; i < numTokens; i++) {
+ String term = null;
+ int positionIncrement = 1;
+
+ try {
+ boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+ if (posIncrAtt != null) {
+ positionIncrement = posIncrAtt.getPositionIncrement();
+ }
+ } catch (IOException e) {
+ // safe to ignore, because we know the number of tokens
+ }
+
+ if (enablePositionIncrements) {
+ position += positionIncrement;
+ pq.add(new Term(field, term),position);
+ } else {
+ pq.add(new Term(field, term));
+ }
+ }
+ return pq;
+ }
+ }
+
+ }
+
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/FieldQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/FieldQParserPlugin.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/FieldQParserPlugin.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/FieldQParserPlugin.java Thu Dec 24 13:03:22 2009
@@ -28,6 +28,7 @@
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.TextField;
+import org.apache.solr.schema.SchemaField;
import java.io.IOException;
import java.io.StringReader;
@@ -52,99 +53,9 @@
public Query parse() throws ParseException {
String field = localParams.get(QueryParsing.F);
String queryText = localParams.get(QueryParsing.V);
- FieldType ft = req.getSchema().getFieldType(field);
- if (!(ft instanceof TextField)) {
- String internal = ft.toInternal(queryText);
- return new TermQuery(new Term(field, internal));
- }
-
- int phraseSlop = 0;
- Analyzer analyzer = req.getSchema().getQueryAnalyzer();
-
- // most of the following code is taken from the Lucene QueryParser
-
- // Use the analyzer to get all the tokens, and then build a TermQuery,
- // PhraseQuery, or nothing based on the term count
-
- TokenStream source = null;
- try {
- source = analyzer.reusableTokenStream(field, new StringReader(queryText));
- source.reset();
- } catch (IOException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
- ArrayList<Token> lst = new ArrayList<Token>();
- Token t;
- int positionCount = 0;
- boolean severalTokensAtSamePosition = false;
-
- while (true) {
- try {
- t = source.next();
- }
- catch (IOException e) {
- t = null;
- }
- if (t == null)
- break;
- lst.add(t);
- if (t.getPositionIncrement() != 0)
- positionCount += t.getPositionIncrement();
- else
- severalTokensAtSamePosition = true;
- }
- try {
- source.close();
- }
- catch (IOException e) {
- // ignore
- }
-
- if (lst.size() == 0)
- return null;
- else if (lst.size() == 1) {
- t = lst.get(0);
- return new TermQuery(new Term(field, new String(t.termBuffer(), 0, t.termLength())));
- } else {
- if (severalTokensAtSamePosition) {
- if (positionCount == 1) {
- // no phrase query:
- BooleanQuery q = new BooleanQuery(true);
- for (int i = 0; i < lst.size(); i++) {
- t = (org.apache.lucene.analysis.Token) lst.get(i);
- TermQuery currentQuery = new TermQuery(
- new Term(field, new String(t.termBuffer(), 0, t.termLength())));
- q.add(currentQuery, BooleanClause.Occur.SHOULD);
- }
- return q;
- }
- else {
- // phrase query:
- MultiPhraseQuery mpq = new MultiPhraseQuery();
- mpq.setSlop(phraseSlop);
- ArrayList multiTerms = new ArrayList();
- for (int i = 0; i < lst.size(); i++) {
- t = (org.apache.lucene.analysis.Token) lst.get(i);
- if (t.getPositionIncrement() == 1 && multiTerms.size() > 0) {
- mpq.add((Term[])multiTerms.toArray(new Term[0]));
- multiTerms.clear();
- }
- multiTerms.add(new Term(field, new String(t.termBuffer(), 0, t.termLength())));
- }
- mpq.add((Term[])multiTerms.toArray(new Term[0]));
- return mpq;
- }
- }
- else {
- PhraseQuery q = new PhraseQuery();
- q.setSlop(phraseSlop);
- for (int i = 0; i < lst.size(); i++) {
- Token token = lst.get(i);
- q.add(new Term(field, new String(token.termBuffer(), 0, token.termLength())));
- }
- return q;
- }
- }
+ SchemaField sf = req.getSchema().getField(field);
+ FieldType ft = sf.getType();
+ return ft.getFieldQuery(this, sf, queryText);
}
};
}
Added: lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,29 @@
+package org.apache.solr.search;
+/**
+ * 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.solr.search.function.ValueSource;
+
+
+/**
+ * A {@link ValueSource} that abstractly represents {@link ValueSource}s for
+ * poly fields, and other things.
+ **/
+public abstract class MultiValueSource extends ValueSource {
+
+ public abstract int dimension();
+}
Propchange: lucene/solr/trunk/src/java/org/apache/solr/search/MultiValueSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/SolrQueryParser.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/SolrQueryParser.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/SolrQueryParser.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/SolrQueryParser.java Thu Dec 24 13:03:22 2009
@@ -34,6 +34,7 @@
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.TrieField;
import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.TextField;
// TODO: implement the analysis of simple fields with
// FieldType.toInternal() instead of going through the
@@ -145,6 +146,12 @@
return parser.subQuery(queryText, null).getQuery();
}
}
+ //Intercept poly fields, as they get expanded by default to an OR clause of
+ SchemaField sf = schema.getField(field);
+ //TODO: is there anyway to avoid this instance of check?
+ if (sf != null&& !(sf.getType() instanceof TextField)){//we have a poly field, deal with it specially by delegating to the FieldType
+ return sf.getType().getFieldQuery(parser, sf, queryText);
+ }
// default to a normal field query
return super.getFieldQuery(field, queryText);
Added: lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java?rev=893746&view=auto
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java Thu Dec 24 13:03:22 2009
@@ -0,0 +1,164 @@
+package org.apache.solr.search;
+/**
+ * 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.index.IndexReader;
+import org.apache.lucene.search.Searcher;
+import org.apache.solr.search.function.DocValues;
+import org.apache.solr.search.function.ValueSource;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Converts individual ValueSource instances to leverage the DocValues *Val functions that work with multiple values,
+ * i.e. {@link org.apache.solr.search.function.DocValues#doubleVal(int, double[])}
+ */
+//Not crazy about the name, but...
+public class ToMultiValueSource extends MultiValueSource {
+ protected List<ValueSource> sources;
+
+
+ public ToMultiValueSource(List<ValueSource> sources) {
+ this.sources = sources;
+ }
+
+ public List<ValueSource> getSources() {
+ return sources;
+ }
+
+ public int dimension() {
+ return sources.size();
+ }
+
+ @Override
+ public DocValues getValues(Map context, IndexReader reader) throws IOException {
+ int size = sources.size();
+ final DocValues[] valsArr = new DocValues[size];
+ for (int i = 0; i < size; i++) {
+ valsArr[i] = sources.get(i).getValues(context, reader);
+ }
+ return new DocValues() {
+ @Override
+ public void byteVal(int doc, byte[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].byteVal(doc);
+ }
+ }
+
+ @Override
+ public void shortVal(int doc, short[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].shortVal(doc);
+ }
+ }
+
+ @Override
+ public void floatVal(int doc, float[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].floatVal(doc);
+ }
+ }
+
+ @Override
+ public void intVal(int doc, int[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].intVal(doc);
+ }
+ }
+
+ @Override
+ public void longVal(int doc, long[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].longVal(doc);
+ }
+ }
+
+ @Override
+ public void doubleVal(int doc, double[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].doubleVal(doc);
+ }
+ }
+
+ @Override
+ public void strVal(int doc, String[] vals) {
+ for (int i = 0; i < valsArr.length; i++) {
+ vals[i] = valsArr[i].strVal(doc);
+ }
+ }
+
+ @Override
+ public String toString(int doc) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("toMultiVS(");
+ boolean firstTime = true;
+ for (DocValues vals : valsArr) {
+ if (firstTime) {
+ firstTime = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(vals.toString(doc));
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+ };
+ }
+
+ public void createWeight(Map context, Searcher searcher) throws IOException {
+ for (ValueSource source : sources)
+ source.createWeight(context, searcher);
+ }
+
+
+ public String description() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("toMultiVS(");
+ boolean firstTime = true;
+ for (ValueSource source : sources) {
+ if (firstTime) {
+ firstTime = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(source);
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ToMultiValueSource)) return false;
+
+ ToMultiValueSource that = (ToMultiValueSource) o;
+
+ if (!sources.equals(that.sources)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return sources.hashCode();
+ }
+}
Propchange: lucene/solr/trunk/src/java/org/apache/solr/search/ToMultiValueSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java Thu Dec 24 13:03:22 2009
@@ -41,6 +41,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Collections;
/**
* A factory that parses user queries to generate ValueSource instances.
@@ -202,6 +203,11 @@
};
}
});
+ addParser("toMultiVS", new ValueSourceParser(){
+ public ValueSource parse(FunctionQParser fp) throws ParseException{
+ return new ToMultiValueSource(fp.parseValueSourceList());
+ }
+ });
addParser("query", new ValueSourceParser() {
// boost(query($q),rating)
public ValueSource parse(FunctionQParser fp) throws ParseException {
@@ -224,22 +230,47 @@
addParser("hsin", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
- ValueSource x1 = fp.parseValueSource();
- ValueSource y1 = fp.parseValueSource();
- ValueSource x2 = fp.parseValueSource();
- ValueSource y2 = fp.parseValueSource();
double radius = fp.parseDouble();
+ MultiValueSource pv1;
+ MultiValueSource pv2;
- return new HaversineFunction(x1, y1, x2, y2, radius);
+ ValueSource one = fp.parseValueSource();
+ ValueSource two = fp.parseValueSource();
+ if (fp.hasMoreArguments()) {
+ List<ValueSource> s1 = new ArrayList<ValueSource>();
+ s1.add(one);
+ s1.add(two);
+ pv1 = new ToMultiValueSource(s1);
+ ValueSource x2 = fp.parseValueSource();
+ ValueSource y2 = fp.parseValueSource();
+ List<ValueSource> s2 = new ArrayList<ValueSource>();
+ s2.add(x2);
+ s2.add(y2);
+ pv2 = new ToMultiValueSource(s2);
+ } else {
+ //check to see if we have multiValue source
+ if (one instanceof MultiValueSource && two instanceof MultiValueSource){
+ pv1 = (MultiValueSource) one;
+ pv2 = (MultiValueSource) two;
+ } else {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "Input must either be 2 MultiValueSources, or there must be 4 ValueSources");
+ }
+ }
+ boolean convert = false;
+ if (fp.hasMoreArguments()){
+ convert = Boolean.parseBoolean(fp.parseArg());
+ }
+ return new HaversineFunction(pv1, pv2, radius, convert);
}
});
addParser("ghhsin", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
+ double radius = fp.parseDouble();
ValueSource gh1 = fp.parseValueSource();
ValueSource gh2 = fp.parseValueSource();
- double radius = fp.parseDouble();
return new GeohashHaversineFunction(gh1, gh2, radius);
}
@@ -393,15 +424,9 @@
addParser("sqedist", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
List<ValueSource> sources = fp.parseValueSourceList();
- if (sources.size() % 2 != 0) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources. There must be an even number of sources");
- }
- int dim = sources.size() / 2;
- List<ValueSource> sources1 = new ArrayList<ValueSource>(dim);
- List<ValueSource> sources2 = new ArrayList<ValueSource>(dim);
- //Get dim value sources for the first vector
- splitSources(dim, sources, sources1, sources2);
- return new SquaredEuclideanFunction(sources1, sources2);
+ MVResult mvr = getMultiValueSources(sources);
+
+ return new SquaredEuclideanFunction(mvr.mv1, mvr.mv2);
}
});
@@ -409,14 +434,8 @@
public ValueSource parse(FunctionQParser fp) throws ParseException {
float power = fp.parseFloat();
List<ValueSource> sources = fp.parseValueSourceList();
- if (sources.size() % 2 != 0) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources. There must be an even number of sources");
- }
- int dim = sources.size() / 2;
- List<ValueSource> sources1 = new ArrayList<ValueSource>(dim);
- List<ValueSource> sources2 = new ArrayList<ValueSource>(dim);
- splitSources(dim, sources, sources1, sources2);
- return new VectorDistanceFunction(power, sources1, sources2);
+ MVResult mvr = getMultiValueSources(sources);
+ return new VectorDistanceFunction(power, mvr.mv1, mvr.mv2);
}
});
addParser("ms", new DateValueSourceParser());
@@ -445,6 +464,44 @@
}
}
+ private static MVResult getMultiValueSources(List<ValueSource> sources) {
+ MVResult mvr = new MVResult();
+ if (sources.size() % 2 != 0) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources. There must be an even number of sources");
+ }
+ if (sources.size() == 2) {
+
+ //check to see if these are MultiValueSource
+ boolean s1MV = sources.get(0) instanceof MultiValueSource;
+ boolean s2MV = sources.get(1) instanceof MultiValueSource;
+ if (s1MV && s2MV) {
+ mvr.mv1 = (MultiValueSource) sources.get(0);
+ mvr.mv2 = (MultiValueSource) sources.get(1);
+ } else if (s1MV ||
+ s2MV) {
+ //if one is a MultiValueSource, than the other one needs to be too.
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Illegal number of sources. There must be an even number of sources");
+ } else {
+ mvr.mv1 = new ToMultiValueSource(Collections.singletonList(sources.get(0)));
+ mvr.mv2 = new ToMultiValueSource(Collections.singletonList(sources.get(1)));
+ }
+ } else {
+ int dim = sources.size() / 2;
+ List<ValueSource> sources1 = new ArrayList<ValueSource>(dim);
+ List<ValueSource> sources2 = new ArrayList<ValueSource>(dim);
+ //Get dim value sources for the first vector
+ splitSources(dim, sources, sources1, sources2);
+ mvr.mv1 = new ToMultiValueSource(sources1);
+ mvr.mv2 = new ToMultiValueSource(sources2);
+ }
+
+ return mvr;
+ }
+
+ private static class MVResult {
+ MultiValueSource mv1;
+ MultiValueSource mv2;
+ }
}
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/function/DocValues.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/function/DocValues.java?rev=893746&r1=893745&r2=893746&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/function/DocValues.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/function/DocValues.java Thu Dec 24 13:03:22 2009
@@ -48,6 +48,15 @@
public String strVal(int doc) { throw new UnsupportedOperationException(); }
public abstract String toString(int doc);
+ //For Functions that can work with multiple values from the same document. This does not apply to all functions
+ public void byteVal(int doc, byte [] vals) { throw new UnsupportedOperationException(); }
+ public void shortVal(int doc, short [] vals) { throw new UnsupportedOperationException(); }
+
+ public void floatVal(int doc, float [] vals) { throw new UnsupportedOperationException(); }
+ public void intVal(int doc, int [] vals) { throw new UnsupportedOperationException(); }
+ public void longVal(int doc, long [] vals) { throw new UnsupportedOperationException(); }
+ public void doubleVal(int doc, double [] vals) { throw new UnsupportedOperationException(); }
+ public void strVal(int doc, String [] vals) { throw new UnsupportedOperationException(); }
public Explanation explain(int doc) {
return new Explanation(floatVal(doc), toString(doc));