/* * 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. */ using System; using Lucene.Net.Documents; using Lucene.Net.Search; using Lucene.Net.Search.Function; using Lucene.Net.Spatial.Queries; using Lucene.Net.Spatial.Util; using Spatial4n.Core.Context; using Spatial4n.Core.Shapes; namespace Lucene.Net.Spatial { /// /// The SpatialStrategy encapsulates an approach to indexing and searching based on shapes. ///

/// Note that a SpatialStrategy is not involved with the Lucene stored field values of shapes, which is /// immaterial to indexing and search. ///

/// Thread-safe. ///

public abstract class SpatialStrategy { protected readonly SpatialContext ctx; protected readonly string fieldName; /// /// Constructs the spatial strategy with its mandatory arguments. /// /// /// protected SpatialStrategy(SpatialContext ctx, string fieldName) { if (ctx == null) throw new ArgumentException("ctx is required", "ctx"); this.ctx = ctx; if (string.IsNullOrEmpty(fieldName)) throw new ArgumentException("fieldName is required", "fieldName"); this.fieldName = fieldName; } public SpatialContext GetSpatialContext() { return ctx; } /// /// The name of the field or the prefix of them if there are multiple /// fields needed internally. /// /// public String GetFieldName() { return fieldName; } /// /// Returns the IndexableField(s) from the shape that are to be /// added to the {@link org.apache.lucene.document.Document}. These fields /// are expected to be marked as indexed and not stored. ///

/// Note: If you want to store the shape as a string for retrieval in search /// results, you could add it like this: ///

document.add(new StoredField(fieldName,ctx.toString(shape)));
/// The particular string representation used doesn't matter to the Strategy since it /// doesn't use it. ///
/// /// Not null nor will it have null elements. public abstract AbstractField[] CreateIndexableFields(Shape shape); public AbstractField CreateStoredField(Shape shape) { return new Field(GetFieldName(), ctx.ToString(shape), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO); } /// /// Make a ValueSource returning the distance between the center of the /// indexed shape and {@code queryPoint}. If there are multiple indexed shapes /// then the closest one is chosen. /// public abstract ValueSource MakeDistanceValueSource(Point queryPoint); /// /// Make a (ConstantScore) Query based principally on {@link org.apache.lucene.spatial.query.SpatialOperation} /// and {@link Shape} from the supplied {@code args}. /// The default implementation is ///
return new ConstantScoreQuery(makeFilter(args));
///
/// /// public virtual ConstantScoreQuery MakeQuery(SpatialArgs args) { return new ConstantScoreQuery(MakeFilter(args)); } /// /// Make a Filter based principally on {@link org.apache.lucene.spatial.query.SpatialOperation} /// and {@link Shape} from the supplied {@code args}. ///

/// If a subclasses implements /// {@link #makeQuery(org.apache.lucene.spatial.query.SpatialArgs)} /// then this method could be simply: ///

return new QueryWrapperFilter(makeQuery(args).getQuery());
///
/// /// public abstract Filter MakeFilter(SpatialArgs args); /// /// Returns a ValueSource with values ranging from 1 to 0, depending inversely /// on the distance from {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point)}. /// The formula is c/(d + c) where 'd' is the distance and 'c' is /// one tenth the distance to the farthest edge from the center. Thus the /// scores will be 1 for indexed points at the center of the query shape and as /// low as ~0.1 at its furthest edges. /// /// /// public ValueSource MakeRecipDistanceValueSource(Shape queryShape) { Rectangle bbox = queryShape.GetBoundingBox(); double diagonalDist = ctx.GetDistCalc().Distance( ctx.MakePoint(bbox.GetMinX(), bbox.GetMinY()), bbox.GetMaxX(), bbox.GetMaxY()); double distToEdge = diagonalDist*0.5; float c = (float) distToEdge*0.1f; //one tenth return new ReciprocalFloatFunction(MakeDistanceValueSource(queryShape.GetCenter()), 1f, c, c); } public override string ToString() { return GetType().Name + " field:" + fieldName + " ctx=" + ctx; } } }