You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2012/09/21 15:16:06 UTC
svn commit: r1388475 - in /lucene.net/trunk: src/contrib/Spatial/Prefix/
src/contrib/Spatial/Prefix/Tree/ src/contrib/Spatial/Queries/
test/contrib/Spatial/Prefix/
Author: synhershko
Date: Fri Sep 21 13:16:06 2012
New Revision: 1388475
URL: http://svn.apache.org/viewvc?rev=1388475&view=rev
Log:
LUCENE-4186 distErrPct upgrade
Modified:
lucene.net/trunk/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
lucene.net/trunk/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
lucene.net/trunk/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/QuadPrefixTree.cs
lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/SpatialPrefixTree.cs
lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgs.cs
lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgsParser.cs
lucene.net/trunk/test/contrib/Spatial/Prefix/TestRecursivePrefixTreeStrategy.cs
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs Fri Sep 21 13:16:06 2012
@@ -34,42 +34,53 @@ using Spatial4n.Core.Shapes;
namespace Lucene.Net.Spatial.Prefix
{
- public abstract class PrefixTreeStrategy : SpatialStrategy
- {
- protected readonly SpatialPrefixTree grid;
- private readonly IDictionary<String, PointPrefixTreeFieldCacheProvider> provider = new ConcurrentDictionary<string, PointPrefixTreeFieldCacheProvider>();
- protected int defaultFieldValuesArrayLen = 2;
- protected double distErrPct = SpatialArgs.DEFAULT_DIST_PRECISION;
+ public abstract class PrefixTreeStrategy : SpatialStrategy
+ {
+ protected readonly SpatialPrefixTree grid;
+
+ private readonly IDictionary<String, PointPrefixTreeFieldCacheProvider> provider =
+ new ConcurrentDictionary<string, PointPrefixTreeFieldCacheProvider>();
+
+ protected int defaultFieldValuesArrayLen = 2;
+ protected double distErrPct = SpatialArgs.DEFAULT_DISTERRPCT; // [ 0 TO 0.5 ]
+
+ protected PrefixTreeStrategy(SpatialPrefixTree grid, String fieldName)
+ : base(grid.GetSpatialContext(), fieldName)
+ {
+ this.grid = grid;
+ }
+
+ /** Used in the in-memory ValueSource as a default ArrayList length for this field's array of values, per doc. */
+
+ public void SetDefaultFieldValuesArrayLen(int defaultFieldValuesArrayLen)
+ {
+ this.defaultFieldValuesArrayLen = defaultFieldValuesArrayLen;
+ }
+
+ /// <summary>
+ /// The default measure of shape precision affecting indexed and query shapes.
+ /// Specific shapes at index and query time can use something different.
+ /// @see org.apache.lucene.spatial.query.SpatialArgs#getDistErrPct()
+ /// </summary>
+ public double DistErrPct { get; set; }
- protected PrefixTreeStrategy(SpatialPrefixTree grid, String fieldName)
- : base(grid.GetSpatialContext(), fieldName)
- {
- this.grid = grid;
- }
-
- /** Used in the in-memory ValueSource as a default ArrayList length for this field's array of values, per doc. */
- public void SetDefaultFieldValuesArrayLen(int defaultFieldValuesArrayLen)
- {
- this.defaultFieldValuesArrayLen = defaultFieldValuesArrayLen;
- }
-
- /** See {@link SpatialPrefixTree#getMaxLevelForPrecision(com.spatial4j.core.shape.Shape, double)}. */
- public void SetDistErrPct(double distErrPct)
+ public override AbstractField[] CreateIndexableFields(Shape shape)
{
- this.distErrPct = distErrPct;
+ double distErr = SpatialArgs.CalcDistanceFromErrPct(shape, distErrPct, ctx);
+ return CreateIndexableFields(shape, distErr);
}
- public override AbstractField[] CreateIndexableFields(Shape shape)
- {
- int detailLevel = grid.GetMaxLevelForPrecision(shape, distErrPct);
- var cells = grid.GetNodes(shape, detailLevel, true);//true=intermediates cells
+ public AbstractField[] CreateIndexableFields(Shape shape, double distErr)
+ {
+ int detailLevel = grid.GetLevelForDistance(distErr);
+ var cells = grid.GetNodes(shape, detailLevel, true);//true=intermediates cells
//If shape isn't a point, add a full-resolution center-point so that
- // PrefixFieldCacheProvider has the center-points.
+ // PointPrefixTreeFieldCacheProvider has the center-points.
// TODO index each center of a multi-point? Yes/no?
if (!(shape is Point))
{
Point ctr = shape.GetCenter();
- //TODO should be smarter; don't index 2 tokens for this in CellTokenizer. Harmless though.
+ //TODO should be smarter; don't index 2 tokens for this in CellTokenStream. Harmless though.
cells.Add(grid.GetNodes(ctr, grid.GetMaxLevels(), false)[0]);
}
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs Fri Sep 21 13:16:06 2012
@@ -49,7 +49,7 @@ namespace Lucene.Net.Spatial.Prefix
Shape shape = args.GetShape();
- int detailLevel = grid.GetMaxLevelForPrecision(shape, args.GetDistPrecision());
+ int detailLevel = grid.GetLevelForDistance(args.ResolveDistErr(ctx, distErrPct));
return new RecursivePrefixTreeFilter(GetFieldName(), grid, shape, prefixGridScanLevel, detailLevel);
}
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs Fri Sep 21 13:16:06 2012
@@ -45,7 +45,7 @@ namespace Lucene.Net.Spatial.Prefix
throw new UnsupportedSpatialOperation(op);
Shape shape = args.GetShape();
- int detailLevel = grid.GetMaxLevelForPrecision(shape, args.GetDistPrecision());
+ int detailLevel = grid.GetLevelForDistance(args.ResolveDistErr(ctx, distErrPct));
var cells = grid.GetNodes(shape, detailLevel, false);
var filter = new TermsFilter();
foreach (Node cell in cells)
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs Fri Sep 21 13:16:06 2012
@@ -66,6 +66,8 @@ namespace Lucene.Net.Spatial.Prefix.Tree
public override int GetLevelForDistance(double dist)
{
+ if (dist == 0)
+ return maxLevels;//short circuit
int level = GeohashUtils.LookupHashLenForWidthHeight(dist, dist);
return Math.Max(Math.Min(level, maxLevels), 1);
}
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/QuadPrefixTree.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/QuadPrefixTree.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/QuadPrefixTree.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/QuadPrefixTree.cs Fri Sep 21 13:16:06 2012
@@ -21,7 +21,6 @@ using System.Diagnostics;
using System.Text;
using Spatial4n.Core.Context;
using Spatial4n.Core.Shapes;
-using Spatial4n.Core.Shapes.Impl;
namespace Lucene.Net.Spatial.Prefix.Tree
{
@@ -111,6 +110,8 @@ namespace Lucene.Net.Spatial.Prefix.Tree
public override int GetLevelForDistance(double dist)
{
+ if (dist == 0)//short circuit
+ return maxLevels;
for (int i = 0; i < maxLevels - 1; i++)
{
//note: level[i] is actually a lookup for level i+1
Modified: lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/SpatialPrefixTree.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/SpatialPrefixTree.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/SpatialPrefixTree.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Prefix/Tree/SpatialPrefixTree.cs Fri Sep 21 13:16:06 2012
@@ -27,7 +27,7 @@ using Spatial4n.Core.Shapes;
namespace Lucene.Net.Spatial.Prefix.Tree
{
/// <summary>
- /// A Spatial Prefix Tree, or Trie, which decomposes shapes into prefixed strings at variable lengths corresponding to
+ /// A spatial Prefix Tree, or Trie, which decomposes shapes into prefixed strings at variable lengths corresponding to
/// variable precision. Each string corresponds to a spatial region.
///
/// Implementations of this class should be thread-safe and immutable once initialized.
@@ -59,31 +59,6 @@ namespace Lucene.Net.Spatial.Prefix.Tree
return GetType().Name + "(maxLevels:" + maxLevels + ",ctx:" + ctx + ")";
}
- /// <summary>
- /// See {@link com.spatial4j.core.query.SpatialArgs#getDistPrecision()}.
- /// A grid level looked up via {@link #getLevelForDistance(double)} is returned.
- /// </summary>
- /// <param name="shape"></param>
- /// <param name="precision">0 to 0.5</param>
- /// <returns>1 to maxLevels</returns>
- public int GetMaxLevelForPrecision(Shape shape, double precision)
- {
- if (precision < 0 || precision > 0.5)
- {
- throw new ArgumentException("Precision " + precision + " must be between [0 to 0.5]", "precision");
- }
- if (precision == 0 || shape is Point)
- {
- return maxLevels;
- }
- Rectangle bbox = shape.GetBoundingBox();
- //The diagonal distance should be the same computed from any opposite corner,
- // and this is the longest distance that might be occurring within the shape.
- double diagonalDist = ctx.GetDistCalc().Distance(
- ctx.MakePoint(bbox.GetMinX(), bbox.GetMinY()), bbox.GetMaxX(), bbox.GetMaxY());
- return GetLevelForDistance(diagonalDist*0.5*precision);
- }
-
/// <summary>
/// Returns the level of the largest grid in which its longest side is less
/// than or equal to the provided distance (in degrees). Consequently {@link
Modified: lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgs.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgs.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgs.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgs.cs Fri Sep 21 13:16:06 2012
@@ -17,6 +17,7 @@
using System;
using System.Text;
+using Spatial4n.Core.Context;
using Spatial4n.Core.Exceptions;
using Spatial4n.Core.Shapes;
@@ -36,25 +37,63 @@ namespace Lucene.Net.Spatial.Queries
{
public class SpatialArgs
{
- public static double DEFAULT_DIST_PRECISION = 0.025d;
+ public static readonly double DEFAULT_DISTERRPCT = 0.025d;
public SpatialOperation Operation { get; set; }
-
private Shape shape;
- private double distPrecision = DEFAULT_DIST_PRECISION;
-
- public SpatialArgs(SpatialOperation operation)
- {
- this.Operation = operation;
- }
public SpatialArgs(SpatialOperation operation, Shape shape)
{
+ if (operation == null || shape == null)
+ throw new ArgumentException("operation and shape are required");
this.Operation = operation;
this.shape = shape;
}
- /// <summary>
+ /// <summary>
+ /// Computes the distance given a shape and the {@code distErrPct}. The
+ /// algorithm is the fraction of the distance from the center of the query
+ /// shape to its furthest bounding box corner.
+ /// </summary>
+ /// <param name="shape">Mandatory.</param>
+ /// <param name="distErrPct">0 to 0.5</param>
+ /// <param name="ctx">Mandatory</param>
+ /// <returns>A distance (in degrees).</returns>
+ public static double CalcDistanceFromErrPct(Shape shape, double distErrPct, SpatialContext ctx)
+ {
+ if (distErrPct < 0 || distErrPct > 0.5)
+ {
+ throw new ArgumentException("distErrPct " + distErrPct + " must be between [0 to 0.5]", "distErrPct");
+ }
+ if (distErrPct == 0 || shape is Point)
+ {
+ return 0;
+ }
+ Rectangle bbox = shape.GetBoundingBox();
+ //The diagonal distance should be the same computed from any opposite corner,
+ // and this is the longest distance that might be occurring within the shape.
+ double diagonalDist = ctx.GetDistCalc().Distance(
+ ctx.MakePoint(bbox.GetMinX(), bbox.GetMinY()), bbox.GetMaxX(), bbox.GetMaxY());
+ return diagonalDist*0.5*distErrPct;
+ }
+
+ /// <summary>
+ /// Gets the error distance that specifies how precise the query shape is. This
+ /// looks at {@link #getDistErr()}, {@link #getDistErrPct()}, and {@code
+ /// defaultDistErrPct}.
+ /// </summary>
+ /// <param name="ctx"></param>
+ /// <param name="defaultDistErrPct">0 to 0.5</param>
+ /// <returns>>= 0</returns>
+ public double ResolveDistErr(SpatialContext ctx, double defaultDistErrPct)
+ {
+ if (DistErr != null)
+ return DistErr.Value;
+ double? distErrPct = (this.distErrPct ?? defaultDistErrPct);
+ return CalcDistanceFromErrPct(shape, distErrPct.Value, ctx);
+ }
+
+ /// <summary>
/// Check if the arguments make sense -- throw an exception if not
/// </summary>
public void Validate()
@@ -67,12 +106,7 @@ namespace Lucene.Net.Spatial.Queries
public override String ToString()
{
- var str = new StringBuilder();
- str.Append(Operation.GetName()).Append('(');
- str.Append(shape.ToString());
- str.Append(" distPrec=").AppendFormat("{0:0.00}%", distPrecision * 100);
- str.Append(')');
- return str.ToString();
+ return SpatialArgsParser.WriteSpatialArgs(this);
}
//------------------------------------------------
@@ -95,24 +129,29 @@ namespace Lucene.Net.Spatial.Queries
this.shape = shape;
}
- /// <summary>
- /// A measure of acceptable error of the shape. It is specified as the
- /// fraction of the distance from the center of the query shape to its furthest
- /// bounding box corner. This effectively inflates the size of the shape but
- /// should not shrink it.
- /// <p/>
- /// The default is {@link #DEFAULT_DIST_PRECISION}
- /// </summary>
- /// <returns>0 to 0.5</returns>
- public Double GetDistPrecision()
- {
- return distPrecision;
- }
-
- public void SetDistPrecision(double? distPrecision)
- {
- if (distPrecision != null)
- this.distPrecision = distPrecision.Value;
- }
+ /// <summary>
+ /// A measure of acceptable error of the shape as a fraction. This effectively
+ /// inflates the size of the shape but should not shrink it.
+ /// <p/>
+ /// The default is {@link #DEFAULT_DIST_PRECISION}
+ /// </summary>
+ /// <returns>0 to 0.5</returns>
+ public double? DistErrPct
+ {
+ get { return distErrPct; }
+ set
+ {
+ if (value != null)
+ distErrPct = value.Value;
+ }
+ }
+ private double? distErrPct;
+
+ /// <summary>
+ /// The acceptable error of the shape. This effectively inflates the
+ /// size of the shape but should not shrink it.
+ /// </summary>
+ /// <returns>>= 0</returns>
+ public double? DistErr { get; set; }
}
}
Modified: lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgsParser.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgsParser.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgsParser.cs (original)
+++ lucene.net/trunk/src/contrib/Spatial/Queries/SpatialArgsParser.cs Fri Sep 21 13:16:06 2012
@@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
+using System.Text;
using Spatial4n.Core.Context;
using Spatial4n.Core.Exceptions;
using Spatial4n.Core.Io;
@@ -26,7 +27,32 @@ namespace Lucene.Net.Spatial.Queries
{
public class SpatialArgsParser
{
- public SpatialArgs Parse(String v, SpatialContext ctx)
+ /// <summary>
+ /// Writes a close approximation to the parsed input format.
+ /// </summary>
+ /// <param name="args"></param>
+ /// <returns></returns>
+ public static String WriteSpatialArgs(SpatialArgs args)
+ {
+ var str = new StringBuilder();
+ str.Append(args.Operation.GetName());
+ str.Append('(');
+ str.Append(args.GetShape());
+ if (args.DistErrPct != null)
+ str.Append(" distErrPct=").Append(String.Format("{0:0.00}%", args.DistErrPct*100d));
+ if (args.DistErr != null)
+ str.Append(" distErr=").Append(args.DistErr);
+ str.Append(')');
+ return str.ToString();
+ }
+
+ /// <summary>
+ /// Parses a string such as "Intersects(-10,20,-8,22) distErrPct=0.025".
+ /// </summary>
+ /// <param name="v"></param>
+ /// <param name="ctx"></param>
+ /// <returns></returns>
+ public SpatialArgs Parse(String v, SpatialContext ctx)
{
int idx = v.IndexOf('(');
int edx = v.LastIndexOf(')');
@@ -55,13 +81,15 @@ namespace Lucene.Net.Spatial.Queries
if (body.Length > 0)
{
Dictionary<String, String> aa = ParseMap(body);
- args.SetDistPrecision(ReadDouble(aa["distPrec"]));
- if (aa.Count > 3)
+ args.DistErrPct = ReadDouble(aa["distErrPct"]); aa.Remove("distErrPct");
+ args.DistErr = ReadDouble(aa["distErr"]); aa.Remove("distErr");
+ if (aa.Count != 0)
{
throw new ArgumentException("unused parameters: " + aa);
}
}
}
+ args.Validate();
return args;
}
@@ -77,6 +105,12 @@ namespace Lucene.Net.Spatial.Queries
return bool.TryParse(v, out ret) ? ret : defaultValue;
}
+ /// <summary>
+ /// Parses "a=b c=d f" (whitespace separated) into name-value pairs. If there
+ /// is no '=' as in 'f' above then it's short for f=f.
+ /// </summary>
+ /// <param name="body"></param>
+ /// <returns></returns>
protected static Dictionary<String, String> ParseMap(String body)
{
var map = new Dictionary<String, String>();
Modified: lucene.net/trunk/test/contrib/Spatial/Prefix/TestRecursivePrefixTreeStrategy.cs
URL: http://svn.apache.org/viewvc/lucene.net/trunk/test/contrib/Spatial/Prefix/TestRecursivePrefixTreeStrategy.cs?rev=1388475&r1=1388474&r2=1388475&view=diff
==============================================================================
--- lucene.net/trunk/test/contrib/Spatial/Prefix/TestRecursivePrefixTreeStrategy.cs (original)
+++ lucene.net/trunk/test/contrib/Spatial/Prefix/TestRecursivePrefixTreeStrategy.cs Fri Sep 21 13:16:06 2012
@@ -38,7 +38,7 @@ namespace Lucene.Net.Contrib.Spatial.Tes
private void init(int maxLength)
{
this.maxLength = maxLength;
- this.ctx = SpatialContext.GEO_KM;
+ this.ctx = SpatialContext.GEO;
var grid = new GeohashPrefixTree(ctx, maxLength);
this.strategy = new RecursivePrefixTreeStrategy(grid, GetType().Name);
}
@@ -80,22 +80,22 @@ namespace Lucene.Net.Contrib.Spatial.Tes
const double DIST = 35.75; //35.7499...
assertEquals(DIST, ctx.GetDistCalc().Distance(iPt, qPt), 0.001);
- //distPrec will affect the query shape precision. The indexed precision
+ //distErrPct will affect the query shape precision. The indexed precision
// was set to nearly zilch via init(GeohashPrefixTree.getMaxLevelsPossible());
- const double distPrec = 0.025; //the suggested default, by the way
- const double distMult = 1 + distPrec;
+ const double distErrPct = 0.025; //the suggested default, by the way
+ const double distMult = 1 + distErrPct;
assertTrue(35.74*distMult >= DIST);
- checkHits(q(qPt, 35.74, distPrec), 1, null);
+ checkHits(q(qPt, 35.74, distErrPct), 1, null);
assertTrue(30*distMult < DIST);
- checkHits(q(qPt, 30, distPrec), 0, null);
+ checkHits(q(qPt, 30, distErrPct), 0, null);
assertTrue(33*distMult < DIST);
- checkHits(q(qPt, 33, distPrec), 0, null);
+ checkHits(q(qPt, 33, distErrPct), 0, null);
assertTrue(34*distMult < DIST);
- checkHits(q(qPt, 34, distPrec), 0, null);
+ checkHits(q(qPt, 34, distErrPct), 0, null);
}
[Test]
@@ -172,11 +172,11 @@ namespace Lucene.Net.Contrib.Spatial.Tes
}//randomTest()
- private SpatialArgs q(Point pt, double dist, double distPrec = 0.0)
+ private SpatialArgs q(Point pt, double dist, double distErrPct = 0.0)
{
Shape shape = ctx.MakeCircle(pt, dist);
var args = new SpatialArgs(SpatialOperation.Intersects, shape);
- args.SetDistPrecision(distPrec);
+ args.DistErrPct = distErrPct;
return args;
}