Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
PrefixTreeStrategy.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 #if !NET35
20 using System.Collections.Concurrent;
21 #else
22 using Lucene.Net.Support.Compatibility;
23 #endif
24 using System.Collections.Generic;
25 using Lucene.Net.Analysis;
26 using Lucene.Net.Analysis.Tokenattributes;
27 using Lucene.Net.Documents;
28 using Lucene.Net.Search.Function;
29 using Lucene.Net.Spatial.Prefix.Tree;
30 using Lucene.Net.Spatial.Queries;
31 using Lucene.Net.Spatial.Util;
32 using Spatial4n.Core.Shapes;
33 
34 namespace Lucene.Net.Spatial.Prefix
35 {
36  /// <summary>
37  /// Abstract SpatialStrategy which provides common functionality for those
38  /// Strategys which use {@link SpatialPrefixTree}s
39  /// </summary>
40  public abstract class PrefixTreeStrategy : SpatialStrategy
41  {
42  protected readonly SpatialPrefixTree grid;
43 
44  private readonly IDictionary<String, PointPrefixTreeFieldCacheProvider> provider =
45  new ConcurrentDictionary<string, PointPrefixTreeFieldCacheProvider>();
46 
47  protected int defaultFieldValuesArrayLen = 2;
48  protected double distErrPct = SpatialArgs.DEFAULT_DISTERRPCT; // [ 0 TO 0.5 ]
49 
50  protected PrefixTreeStrategy(SpatialPrefixTree grid, String fieldName)
51  : base(grid.GetSpatialContext(), fieldName)
52  {
53  this.grid = grid;
54  }
55 
56  /* Used in the in-memory ValueSource as a default ArrayList length for this field's array of values, per doc. */
57 
58  public void SetDefaultFieldValuesArrayLen(int defaultFieldValuesArrayLen)
59  {
60  this.defaultFieldValuesArrayLen = defaultFieldValuesArrayLen;
61  }
62 
63  /// <summary>
64  /// The default measure of shape precision affecting indexed and query shapes.
65  /// Specific shapes at index and query time can use something different.
66  /// @see org.apache.lucene.spatial.query.SpatialArgs#getDistErrPct()
67  /// </summary>
68  public double DistErrPct { get; set; }
69 
70  public override AbstractField[] CreateIndexableFields(Shape shape)
71  {
72  double distErr = SpatialArgs.CalcDistanceFromErrPct(shape, distErrPct, ctx);
73  return CreateIndexableFields(shape, distErr);
74  }
75 
76  public AbstractField[] CreateIndexableFields(Shape shape, double distErr)
77  {
78  int detailLevel = grid.GetLevelForDistance(distErr);
79  var cells = grid.GetNodes(shape, detailLevel, true);//true=intermediates cells
80  //If shape isn't a point, add a full-resolution center-point so that
81  // PointPrefixTreeFieldCacheProvider has the center-points.
82  // TODO index each center of a multi-point? Yes/no?
83  if (!(shape is Point))
84  {
85  Point ctr = shape.GetCenter();
86  //TODO should be smarter; don't index 2 tokens for this in CellTokenStream. Harmless though.
87  cells.Add(grid.GetNodes(ctr, grid.GetMaxLevels(), false)[0]);
88  }
89 
90  //TODO is CellTokenStream supposed to be re-used somehow? see Uwe's comments:
91  // http://code.google.com/p/lucene-spatial-playground/issues/detail?id=4
92 
93  return new AbstractField[]
94  {
95  new Field(GetFieldName(), new CellTokenStream(cells.GetEnumerator()))
96  {OmitNorms = true, OmitTermFreqAndPositions = true}
97  };
98  }
99 
100  /// <summary>
101  /// Outputs the tokenString of a cell, and if its a leaf, outputs it again with the leaf byte.
102  /// </summary>
103  protected class CellTokenStream : TokenStream
104  {
105  private ITermAttribute termAtt;
106  private readonly IEnumerator<Node> iter;
107 
108  public CellTokenStream(IEnumerator<Node> tokens)
109  {
110  this.iter = tokens;
111  Init();
112  }
113 
114  private void Init()
115  {
116  termAtt = AddAttribute<ITermAttribute>();
117  }
118 
119  private string nextTokenStringNeedingLeaf;
120 
121  public override bool IncrementToken()
122  {
123  ClearAttributes();
124  if (nextTokenStringNeedingLeaf != null)
125  {
126  termAtt.Append(nextTokenStringNeedingLeaf);
127  termAtt.Append((char)Node.LEAF_BYTE);
128  nextTokenStringNeedingLeaf = null;
129  return true;
130  }
131  if (iter.MoveNext())
132  {
133  Node cell = iter.Current;
134  var token = cell.GetTokenString();
135  termAtt.Append(token);
136  if (cell.IsLeaf())
137  nextTokenStringNeedingLeaf = token;
138  return true;
139  }
140  return false;
141  }
142 
143  protected override void Dispose(bool disposing)
144  {
145  }
146  }
147 
148  public ShapeFieldCacheProvider<Point> GetCacheProvider()
149  {
151  if (!provider.TryGetValue(GetFieldName(), out p) || p == null)
152  {
153  lock (this)
154  {//double checked locking idiom is okay since provider is threadsafe
155  if (!provider.ContainsKey(GetFieldName()))
156  {
157  p = new PointPrefixTreeFieldCacheProvider(grid, GetFieldName(), defaultFieldValuesArrayLen);
158  provider[GetFieldName()] = p;
159  }
160  }
161  }
162  return p;
163  }
164 
165  public override ValueSource MakeDistanceValueSource(Point queryPoint)
166  {
167  var p = (PointPrefixTreeFieldCacheProvider)GetCacheProvider();
168  return new ShapeFieldCacheDistanceValueSource(ctx, p, queryPoint);
169  }
170 
171  public SpatialPrefixTree GetGrid()
172  {
173  return grid;
174  }
175  }
176 }