private static Term CreateTerm(string name, QueryFieldValue queryFieldValue) { string numval; switch (queryFieldValue.Datatype) { case IndexableDataType.String: return(new Term(name, queryFieldValue.StringValue)); case IndexableDataType.Int: numval = NumericUtils.IntToPrefixCoded(queryFieldValue.IntValue); break; case IndexableDataType.Long: numval = NumericUtils.LongToPrefixCoded(queryFieldValue.LongValue); break; case IndexableDataType.Float: numval = NumericUtils.FloatToPrefixCoded(queryFieldValue.SingleValue); break; case IndexableDataType.Double: numval = NumericUtils.DoubleToPrefixCoded(queryFieldValue.DoubleValue); break; default: throw new SnNotSupportedException("Unknown IndexableDataType enum value: " + queryFieldValue.Datatype); } var numterm = new Term(name, numval); return(numterm); }
public void AddPoint(int id, string name, double lat, double lng, IndexWriter currentWriter) { EnsureDistanceMatrixReady(); var writer = currentWriter != null ? currentWriter : MakeWriter(true, IndexWriter.MaxFieldLength.UNLIMITED); Document doc = new Document(); doc.Add(new Field("name", name, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field("PostID", Convert.ToString(id), Field.Store.YES, Field.Index.UN_TOKENIZED)); // convert the lat / long to lucene fields doc.Add(new Field(LatField, NumericUtils.DoubleToPrefixCoded(lat), Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.Add(new Field(LngField, NumericUtils.DoubleToPrefixCoded(lng), Field.Store.YES, Field.Index.NOT_ANALYZED)); // add a default meta field to make searching all documents easy doc.Add(new Field("metafile", "doc", Field.Store.YES, Field.Index.ANALYZED)); int ctpsize = _ctps.Count; for (int i = 0; i < ctpsize; i++) { CartesianTierPlotter ctp = _ctps[i]; var boxId = ctp.GetTierBoxId(lat, lng); doc.Add(new Field(ctp.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); } writer.AddDocument(doc); if (currentWriter == null) // if we're not using the passed along writer, which is supposed to be terminated by the caller, then end our new writer { FinishWriter(writer); } }
private Query CreateValueQuery(QueryFieldValue value) { var currentField = _currentField.Peek(); string numval; switch (value.Datatype) { case IndexableDataType.String: return(CreateStringValueQuery(value, currentField)); case IndexableDataType.Int: numval = NumericUtils.IntToPrefixCoded(value.IntValue); break; case IndexableDataType.Long: numval = NumericUtils.LongToPrefixCoded(value.LongValue); break; case IndexableDataType.Float: numval = NumericUtils.FloatToPrefixCoded(value.SingleValue); break; case IndexableDataType.Double: numval = NumericUtils.DoubleToPrefixCoded(value.DoubleValue); break; default: throw new NotImplementedException("Unknown IndexableDataType enum value: " + value.Datatype); } var numterm = new Term(currentField.Name, numval); return(new TermQuery(numterm)); }
private void AddPoint(IndexWriter writer, String name, double lat, double lng) { Document doc = new Document(); doc.Add(new Field("name", name, Field.Store.YES, Field.Index.ANALYZED)); // convert the lat / long to lucene fields doc.Add(new Field(LatField, NumericUtils.DoubleToPrefixCoded(lat), Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.Add(new Field(LngField, NumericUtils.DoubleToPrefixCoded(lng), Field.Store.YES, Field.Index.NOT_ANALYZED)); // add a default meta field to make searching all documents easy doc.Add(new Field("metafile", "doc", Field.Store.YES, Field.Index.ANALYZED)); int ctpsize = _ctps.Count; for (int i = 0; i < ctpsize; i++) { CartesianTierPlotter ctp = _ctps[i]; var boxId = ctp.GetTierBoxId(lat, lng); doc.Add(new Field(ctp.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); } writer.AddDocument(doc); }
public static string Tier(int id, double lat, double lng) { if (id < MinTier || id > MaxTier) { throw new ArgumentException( string.Format("tier id should be between {0} and {1}", MinTier, MaxTier), "id"); } var boxId = Ctps[id - MinTier].GetTierBoxId(lat, lng); return(NumericUtils.DoubleToPrefixCoded(boxId)); }
private static string NumericStringToSortableNumeric(string value) { var number = NumberUtil.StringToNumber(value); if (number is long) { return(NumericUtils.LongToPrefixCoded((long)number)); } if (number is double) { return(NumericUtils.DoubleToPrefixCoded((double)number)); } throw new ArgumentException("Unknown type for " + number.GetType() + " which started as " + value); }
public static EncodedFacetRange CreateFrom(FacetRange range) { var result = new EncodedFacetRange { Label = range.Label, FromInclusive = range.FromInclusive, ToInclusive = range.ToInclusive }; if (range.FromValue != null) { result.FromValue = NumericUtils.DoubleToPrefixCoded(range.FromValue.Value); } if (range.ToValue != null) { result.ToValue = NumericUtils.DoubleToPrefixCoded(range.ToValue.Value); } return(result); }
/// <summary> /// Makes a TermQuery for the given MappedField and expression. /// </summary> /// <param name="field"> /// The MappedField to create the query for. /// </param> /// <param name="term"> /// The constant to match in the query. /// </param> /// <returns> /// An instance of TermQuery. /// </returns> private static TermQuery MakeTermQuery(MappedField field, Expression term) { Debug.Assert(null != field, "The mapped field must not be null."); Debug.Assert(null != term, "The term must not be null."); string queryTerm; switch (field.Type) { case MappedField.FieldType.Float: queryTerm = NumericUtils.FloatToPrefixCoded(field.GetValueFromExpression <float>(term)); break; case MappedField.FieldType.Double: queryTerm = NumericUtils.DoubleToPrefixCoded(field.GetValueFromExpression <double>(term)); break; case MappedField.FieldType.Short: queryTerm = NumericUtils.IntToPrefixCoded(field.GetValueFromExpression <short>(term)); break; case MappedField.FieldType.Int: queryTerm = NumericUtils.IntToPrefixCoded(field.GetValueFromExpression <int>(term)); break; case MappedField.FieldType.Long: queryTerm = NumericUtils.LongToPrefixCoded(field.GetValueFromExpression <long>(term)); break; case MappedField.FieldType.String: queryTerm = field.GetValueFromExpression <string>(term); break; default: throw new InvalidOperationException(String.Format( "Cannot make a TermQuery for field '{0}' of type {1}.", field.Name, field.Type)); } return(new TermQuery(new Term(field.Name, queryTerm))); }
internal static string ToPrefixCoded(this ValueType value) { if (value is int) { return(NumericUtils.IntToPrefixCoded((int)value)); } if (value is long) { return(NumericUtils.LongToPrefixCoded((long)value)); } if (value is double) { return(NumericUtils.DoubleToPrefixCoded((double)value)); } if (value is float) { return(NumericUtils.FloatToPrefixCoded((float)value)); } throw new NotSupportedException("ValueType " + value.GetType() + " not supported."); }
public void Set(string name, object value, Document document, Field.Store store, Field.Index index, float?boost) { var service = (Service)value; var location = service.Location; var lat = new Field("Location_Latitude", NumericUtils.DoubleToPrefixCoded(location.Y), Field.Store.YES, Field.Index.NOT_ANALYZED); var lng = new Field("Location_Longitude", NumericUtils.DoubleToPrefixCoded(location.X), Field.Store.YES, Field.Index.NOT_ANALYZED); document.Add(lat); document.Add(lng); document.Add(new Field("metafile", "doc", Field.Store.YES, Field.Index.ANALYZED)); int ctpsize = Ctps.Count; for (int i = 0; i < ctpsize; i++) { CartesianTierPlotter ctp = Ctps[i]; var boxId = ctp.GetTierBoxId(location.Y, location.X); document.Add(new Field(ctp.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS)); } }
/// <summary> /// Converts to searchable. /// </summary> /// <param name="value">The value.</param> /// <param name="tryConvertToNumber">if set to <c>true</c> [try convert to number].</param> /// <returns></returns> public static string ConvertToSearchable(object value, bool tryConvertToNumber = true) { if (value == null || String.IsNullOrEmpty(value.ToString())) { return(String.Empty); } if (tryConvertToNumber) { decimal decimalVal; int intVal; // Try converting to a known type if (Decimal.TryParse(value.ToString(), out decimalVal)) { value = decimalVal; } else if (Int32.TryParse(value.ToString(), out intVal)) { value = intVal; } } if (value is string) { return(value.ToString()); } if (value is decimal) { return(NumericUtils.DoubleToPrefixCoded(double.Parse(value.ToString()))); } if (value.GetType() != typeof(int) || value.GetType() != typeof(long) || value.GetType() != typeof(double)) { return(value.ToString()); } return(NumericUtils.DoubleToPrefixCoded((double)value)); }
private static (string Value, RangeType Type) ConvertFieldValue(string value, ValueTokenType type) { switch (type) { case ValueTokenType.Long: var lng = QueryBuilder.ParseInt64WithSeparators(value); return(NumericUtils.DoubleToPrefixCoded(lng), RangeType.Double); case ValueTokenType.Double: var dbl = double.Parse(value, CultureInfo.InvariantCulture); return(NumericUtils.DoubleToPrefixCoded(dbl), RangeType.Double); case ValueTokenType.String: return(value, RangeType.None); case ValueTokenType.Null: return(null, RangeType.None); default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } }
private static string GetFilterValue(string value, bool isBooleanField) { if (string.IsNullOrEmpty(value)) { return(string.Empty); } if (isBooleanField) { return(bool.Parse(value).ToStringInvariant()); } var dateValue = ConvertToDateTimeTicks(value); if (dateValue != null) { return(NumericUtils.LongToPrefixCoded(dateValue.Value)); } var dobuleValue = ConvertToDouble(value); return(dobuleValue != null?NumericUtils.DoubleToPrefixCoded(dobuleValue.Value) : value); }
private static string ConvertFieldValue(string field, string value) { if (NumberUtil.IsNull(value)) { return(null); } var rangeType = FieldUtil.GetRangeTypeFromFieldName(field); switch (rangeType) { case RangeType.Long: var longValue = NumberUtil.StringToLong(value); return(NumericUtils.LongToPrefixCoded(longValue.Value)); case RangeType.Double: var doubleValue = NumberUtil.StringToDouble(value); return(NumericUtils.DoubleToPrefixCoded(doubleValue.Value)); default: return(value); } }
private static (string Value, RangeType Type) ConvertFieldValue(string value, ValueTokenType type, BlittableJsonReaderObject queryParameters) { switch (type) { case ValueTokenType.Long: var lng = QueryBuilder.ParseInt64WithSeparators(value); return(NumericUtils.DoubleToPrefixCoded(lng), RangeType.Double); case ValueTokenType.Double: var dbl = double.Parse(value, CultureInfo.InvariantCulture); return(NumericUtils.DoubleToPrefixCoded(dbl), RangeType.Double); case ValueTokenType.String: return(value, RangeType.None); case ValueTokenType.Null: return(null, RangeType.None); case ValueTokenType.Parameter: queryParameters.TryGet(value, out object o); var rangeType = RangeType.None; if (o is long l) { o = NumericUtils.DoubleToPrefixCoded(l); rangeType = RangeType.Double; } else if (o is LazyNumberValue lnv) { o = NumericUtils.DoubleToPrefixCoded((double)lnv); rangeType = RangeType.Double; } return(o?.ToString(), rangeType); default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } }
public override DocIdSet GetDocIdSet(IndexReader reader) { var bits = new OpenBitSet(reader.MaxDoc()); TermDocs termDocs = reader.TermDocs(); List <double> area = _shape.Area; int sz = area.Count; // iterate through each boxid for (int i = 0; i < sz; i++) { double boxId = area[i]; termDocs.Seek(new Term(_fieldName, NumericUtils.DoubleToPrefixCoded(boxId))); // iterate through all documents // which have this boxId while (termDocs.Next()) { bits.FastSet(termDocs.Doc()); } } return(bits); }
private string ConvertToTermValue(IndexValue value) { switch (value.Type) { case IndexValueType.String: return(value.StringValue); case IndexValueType.StringArray: throw new NotSupportedException(); case IndexValueType.Bool: return(value.BooleanValue ? IndexValue.Yes : IndexValue.No); case IndexValueType.Int: return(NumericUtils.IntToPrefixCoded(value.IntegerValue)); case IndexValueType.Long: return(NumericUtils.LongToPrefixCoded(value.LongValue)); case IndexValueType.Float: return(NumericUtils.FloatToPrefixCoded(value.SingleValue)); case IndexValueType.Double: return(NumericUtils.DoubleToPrefixCoded(value.DoubleValue)); case IndexValueType.DateTime: return(NumericUtils.LongToPrefixCoded(value.DateTimeValue.Ticks)); default: throw new ArgumentOutOfRangeException(); } }
public static string Lng(double value) { return(NumericUtils.DoubleToPrefixCoded(value)); }
/// <summary> /// /// </summary> /// <param name="lookQuery">The query to parse</param> /// <param name="parsingContext"></param> private static void ParseLocationQuery(ParsingContext parsingContext, LookQuery lookQuery) { if (lookQuery.LocationQuery == null) { return; } parsingContext.QueryAdd(new TermQuery(new Term(LookConstants.HasLocationField, "1")), BooleanClause.Occur.MUST); if (lookQuery.LocationQuery.Boundary != null) // limit results within an lat lng fixed view (eg, typical map bounds) { parsingContext.QueryAdd( new TermRangeQuery( LookConstants.LocationField + "_Latitude", NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMin), NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMax), true, true), BooleanClause.Occur.MUST); parsingContext.QueryAdd( new TermRangeQuery( LookConstants.LocationField + "_Longitude", NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMin), NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMax), true, true), BooleanClause.Occur.MUST); } if (lookQuery.LocationQuery.Location != null) // location set, so can calculate distance { double maxDistance = LookService._maxDistance; if (lookQuery.LocationQuery.MaxDistance != null) { maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance); } var distanceQueryBuilder = new DistanceQueryBuilder( lookQuery.LocationQuery.Location.Latitude, lookQuery.LocationQuery.Location.Longitude, maxDistance, LookConstants.LocationField + "_Latitude", LookConstants.LocationField + "_Longitude", LookConstants.LocationTierFieldPrefix, true); parsingContext.Filter = distanceQueryBuilder.Filter; if (lookQuery.SortOn == SortOn.Distance) { parsingContext.Sort = new Sort( new SortField( LookConstants.DistanceField, new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter))); } parsingContext.GetDistance = new Func <int, double?>(x => { if (distanceQueryBuilder.DistanceFilter.Distances.ContainsKey(x)) { return(distanceQueryBuilder.DistanceFilter.Distances[x]); } return(null); }); } }
/// <summary> /// Do the indexing and set the field values onto the Lucene document /// </summary> /// <param name="indexingContext"></param> /// <param name="document"></param> internal static void Index(IndexingContext indexingContext, Document document) { if (indexingContext.Item != null) { var publishedItemType = indexingContext?.HostItem?.ItemType ?? indexingContext.Item.ItemType; var hasNodeField = new Field( LookConstants.HasNodeField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var nodeIdField = new Field( LookConstants.NodeIdField, indexingContext.Item.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); var nodeKeyField = new Field( LookConstants.NodeKeyField, indexingContext.Item.GetGuidKey().ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); var nodeTypeField = new Field( LookConstants.NodeTypeField, publishedItemType.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO); var nodeAliasField = new Field( LookConstants.NodeAliasField, indexingContext.Item.DocumentTypeAlias, Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.NO); document.Add(hasNodeField); document.Add(nodeIdField); document.Add(nodeKeyField); document.Add(nodeTypeField); document.Add(nodeAliasField); if (publishedItemType == PublishedItemType.Content) { var culture = indexingContext?.HostItem?.GetCulture() ?? indexingContext.Item.GetCulture(); if (culture != null) { var cultureField = new Field( LookConstants.CultureField, culture.LCID.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.NO); document.Add(cultureField); } } if (indexingContext.HostItem != null) { var isDetachedField = new Field( LookConstants.IsDetachedField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); // indexing detached item, so store the host context id so we can return the detached item var hostIdField = new Field( LookConstants.HostIdField, indexingContext.HostItem.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); document.Add(isDetachedField); document.Add(hostIdField); } } if (LookService.Instance.NameIndexer != null) { string name = null; try { name = LookService.Instance.NameIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in name indexer", exception); } if (name != null) { var hasNameField = new Field( LookConstants.HasNameField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var nameField = new Field( LookConstants.NameField, name, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES); // field for lower case searching var nameFieldLowered = new Field( LookConstants.NameField + "_Lowered", name.ToLower(), Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.YES); var nameSortedField = new Field( LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField, name.ToLower(), // force case insentive sorting Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.NO); document.Add(hasNameField); document.Add(nameField); document.Add(nameFieldLowered); document.Add(nameSortedField); } } if (LookService.Instance.DateIndexer != null) { DateTime?date = null; try { date = LookService.Instance.DateIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in date indexer", exception); } if (date != null) { var hasDateField = new Field( LookConstants.HasDateField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var dateValue = DateTools.DateToString(date.Value, DateTools.Resolution.SECOND); var dateField = new Field( LookConstants.DateField, dateValue, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES); var dateSortedField = new Field( LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, dateValue, Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.NO); document.Add(hasDateField); document.Add(dateField); document.Add(dateSortedField); } } if (LookService.Instance.TextIndexer != null) { string text = null; try { text = LookService.Instance.TextIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in text indexer", exception); } if (text != null) { var hasTextField = new Field( LookConstants.HasTextField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var textField = new Field( LookConstants.TextField, text, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES); document.Add(hasTextField); document.Add(textField); } } if (LookService.Instance.TagIndexer != null) { LookTag[] tags = null; try { tags = LookService.Instance.TagIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in tag indexer", exception); } if (tags != null) { foreach (var tag in tags) { var hasTagsField = new Field( LookConstants.HasTagsField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); // add all tags to a common field (serialized such that Tag objects can be restored from this) var allTagsField = new Field( LookConstants.AllTagsField, tag.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); // add the tag value to a specific field - this is used for searching on var tagField = new Field( LookConstants.TagsField + tag.Group, tag.Name, Field.Store.YES, Field.Index.NOT_ANALYZED); document.Add(hasTagsField); document.Add(allTagsField); document.Add(tagField); } } } if (LookService.Instance.LocationIndexer != null) { Location location = null; try { location = LookService.Instance.LocationIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in location indexer", exception); } if (location != null) { var hasLocationField = new Field( LookConstants.HasLocationField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var locationField = new Field( LookConstants.LocationField, location.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); var locationLatitudeField = new Field( LookConstants.LocationField + "_Latitude", NumericUtils.DoubleToPrefixCoded(location.Latitude), Field.Store.YES, Field.Index.NOT_ANALYZED); var locationLongitudeField = new Field( LookConstants.LocationField + "_Longitude", NumericUtils.DoubleToPrefixCoded(location.Longitude), Field.Store.YES, Field.Index.NOT_ANALYZED); document.Add(hasLocationField); document.Add(locationField); document.Add(locationLatitudeField); document.Add(locationLongitudeField); foreach (var cartesianTierPlotter in LookService.Instance.CartesianTierPlotters) { var boxId = cartesianTierPlotter.GetTierBoxId(location.Latitude, location.Longitude); var tierField = new Field( cartesianTierPlotter.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS); document.Add(tierField); } } } }
/// <summary> /// Perform a Look search /// </summary> /// <param name="lookQuery">A LookQuery model for the search criteria</param> /// <returns>A LookResult model for the search response</returns> public static LookResult Search(LookQuery lookQuery) { // flag to indicate whether there are any query clauses in the supplied LookQuery bool hasQuery = lookQuery?.Compiled != null ? true : false; if (lookQuery == null) { return(LookResult.Error("LookQuery object was null")); } if (lookQuery.SearchingContext == null) // supplied by unit test to skip examine dependency { // attempt to get searching context from examine searcher name lookQuery.SearchingContext = LookService.GetSearchingContext(lookQuery.SearcherName); if (lookQuery.SearchingContext == null) { return(LookResult.Error("SearchingContext was null")); } } if (lookQuery.Compiled == null) { BooleanQuery query = null; // the lucene query being built Filter filter = null; // used for geospatial queries Sort sort = null; Func <string, IHtmlString> getHighlight = x => null; Func <int, double?> getDistance = x => null; query = new BooleanQuery(); #region RawQuery if (!string.IsNullOrWhiteSpace(lookQuery.RawQuery)) { hasQuery = true; query.Add( new QueryParser(Lucene.Net.Util.Version.LUCENE_29, null, lookQuery.SearchingContext.Analyzer).Parse(lookQuery.RawQuery), BooleanClause.Occur.MUST); } #endregion #region ExamineQuery if (lookQuery.ExamineQuery != null) { var luceneSearchCriteria = lookQuery.ExamineQuery as LuceneSearchCriteria; // will be of type LookSearchCriteria when using the custom Look indexer/searcher if (luceneSearchCriteria != null && luceneSearchCriteria.Query != null) { hasQuery = true; query.Add(luceneSearchCriteria.Query, BooleanClause.Occur.MUST); } } #endregion #region NodeQuery if (lookQuery.NodeQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasNodeField, "1")), BooleanClause.Occur.MUST); // HasType if (lookQuery.NodeQuery.Type != null) { query.Add( new TermQuery( new Term(LookConstants.NodeTypeField, lookQuery.NodeQuery.Type.ToString())), BooleanClause.Occur.MUST); } // HasTypeAny if (lookQuery.NodeQuery.TypeAny != null && lookQuery.NodeQuery.TypeAny.Any()) { var nodeTypeQuery = new BooleanQuery(); foreach (var nodeType in lookQuery.NodeQuery.TypeAny) { nodeTypeQuery.Add( new TermQuery( new Term(LookConstants.NodeTypeField, nodeType.ToString())), BooleanClause.Occur.SHOULD); } query.Add(nodeTypeQuery, BooleanClause.Occur.MUST); } // Detached switch (lookQuery.NodeQuery.DetachedQuery) { case DetachedQuery.ExcludeDetached: query.Add( new TermQuery(new Term(LookConstants.IsDetachedField, "1")), BooleanClause.Occur.MUST_NOT); break; case DetachedQuery.OnlyDetached: query.Add( new TermQuery(new Term(LookConstants.IsDetachedField, "1")), BooleanClause.Occur.MUST); break; } // HasCulture if (lookQuery.NodeQuery.Culture != null) { query.Add( new TermQuery( new Term(LookConstants.CultureField, lookQuery.NodeQuery.Culture.LCID.ToString())), BooleanClause.Occur.MUST); } // HasCultureAny if (lookQuery.NodeQuery.CultureAny != null && lookQuery.NodeQuery.CultureAny.Any()) { var nodeCultureQuery = new BooleanQuery(); foreach (var nodeCulture in lookQuery.NodeQuery.CultureAny) { nodeCultureQuery.Add( new TermQuery( new Term(LookConstants.CultureField, nodeCulture.LCID.ToString())), BooleanClause.Occur.SHOULD); } query.Add(nodeCultureQuery, BooleanClause.Occur.MUST); } // HasAlias if (lookQuery.NodeQuery.Alias != null) { query.Add( new TermQuery( new Term(LookConstants.NodeAliasField, lookQuery.NodeQuery.Alias.ToString())), BooleanClause.Occur.MUST); } // HasAliasAny if (lookQuery.NodeQuery.AliasAny != null && lookQuery.NodeQuery.AliasAny.Any()) { var nodeAliasQuery = new BooleanQuery(); foreach (var typeAlias in lookQuery.NodeQuery.AliasAny) { nodeAliasQuery.Add( new TermQuery( new Term(LookConstants.NodeAliasField, typeAlias)), BooleanClause.Occur.SHOULD); } query.Add(nodeAliasQuery, BooleanClause.Occur.MUST); } // Ids if (lookQuery.NodeQuery.Ids != null && lookQuery.NodeQuery.Ids.Any()) { if (lookQuery.NodeQuery.NotIds != null) { var conflictIds = lookQuery.NodeQuery.Ids.Where(x => lookQuery.NodeQuery.NotIds.Contains(x)); if (conflictIds.Any()) { return(LookResult.Error($"Conflict in NodeQuery, Ids: '{ string.Join(",", conflictIds) }' are in both Ids and NotIds")); } } var idQuery = new BooleanQuery(); foreach (var id in lookQuery.NodeQuery.Ids) { idQuery.Add( new TermQuery(new Term(LookConstants.NodeIdField, id.ToString())), BooleanClause.Occur.SHOULD); } query.Add(idQuery, BooleanClause.Occur.MUST); } // Keys if (lookQuery.NodeQuery.Keys != null && lookQuery.NodeQuery.Keys.Any()) { if (lookQuery.NodeQuery.NotKeys != null) { var conflictKeys = lookQuery.NodeQuery.Keys.Where(x => lookQuery.NodeQuery.NotKeys.Contains(x)); if (conflictKeys.Any()) { return(LookResult.Error($"Conflict in NodeQuery, keys: '{ string.Join(",", conflictKeys) }' are in both Keys and NotKeys")); } } var keyQuery = new BooleanQuery(); foreach (var key in lookQuery.NodeQuery.Keys) { keyQuery.Add( new TermQuery(new Term(LookConstants.NodeKeyField, key.GuidToLuceneString())), BooleanClause.Occur.SHOULD); } query.Add(keyQuery, BooleanClause.Occur.MUST); } // NotId if (lookQuery.NodeQuery.NotId != null) { query.Add( new TermQuery(new Term(LookConstants.NodeIdField, lookQuery.NodeQuery.NotId.ToString())), BooleanClause.Occur.MUST_NOT); } // NotIds if (lookQuery.NodeQuery.NotIds != null && lookQuery.NodeQuery.NotIds.Any()) { foreach (var exculudeId in lookQuery.NodeQuery.NotIds) { query.Add( new TermQuery(new Term(LookConstants.NodeIdField, exculudeId.ToString())), BooleanClause.Occur.MUST_NOT); } } // NotKey if (lookQuery.NodeQuery.NotKey != null) { query.Add( new TermQuery(new Term(LookConstants.NodeKeyField, lookQuery.NodeQuery.NotKey.ToString())), BooleanClause.Occur.MUST_NOT); } // NotKeys if (lookQuery.NodeQuery.NotKeys != null && lookQuery.NodeQuery.NotKeys.Any()) { foreach (var excludeKey in lookQuery.NodeQuery.NotKeys) { query.Add( new TermQuery(new Term(LookConstants.NodeKeyField, excludeKey.GuidToLuceneString())), BooleanClause.Occur.MUST_NOT); } } } #endregion #region NameQuery if (lookQuery.NameQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasNameField, "1")), BooleanClause.Occur.MUST); string wildcard1 = null; string wildcard2 = null; // incase Contains specified with StartsWith and/or EndsWith if (!string.IsNullOrEmpty(lookQuery.NameQuery.StartsWith)) { if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is)) { if (!lookQuery.NameQuery.Is.StartsWith(lookQuery.NameQuery.StartsWith)) { return(LookResult.Error("Conflict in NameQuery between Is and StartsWith")); } } else { wildcard1 = lookQuery.NameQuery.StartsWith + "*"; } } if (!string.IsNullOrEmpty(lookQuery.NameQuery.EndsWith)) { if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is)) { if (!lookQuery.NameQuery.Is.EndsWith(lookQuery.NameQuery.EndsWith)) { return(LookResult.Error("Conflict in NameQuery between Is and EndsWith")); } } else { if (wildcard1 == null) { wildcard1 = "*" + lookQuery.NameQuery.EndsWith; } else { wildcard1 += lookQuery.NameQuery.EndsWith; } } } if (!string.IsNullOrEmpty(lookQuery.NameQuery.Contains)) { if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is)) { if (!lookQuery.NameQuery.Is.Contains(lookQuery.NameQuery.Contains)) { return(LookResult.Error("Conflict in NameQuery between Is and Contains")); } } else { if (wildcard1 == null) { wildcard1 = "*" + lookQuery.NameQuery.Contains + "*"; } else { wildcard2 = "*" + lookQuery.NameQuery.Contains + "*"; } } } var nameField = lookQuery.NameQuery.CaseSensitive ? LookConstants.NameField : LookConstants.NameField + "_Lowered"; if (wildcard1 != null) { var wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard1 : wildcard1.ToLower(); query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST); if (wildcard2 != null) { wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard2 : wildcard2.ToLower(); query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST); } } if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is)) { var isText = lookQuery.NameQuery.CaseSensitive ? lookQuery.NameQuery.Is : lookQuery.NameQuery.Is.ToLower(); query.Add(new TermQuery(new Term(nameField, isText)), BooleanClause.Occur.MUST); } } #endregion #region DateQuery if (lookQuery.DateQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasDateField, "1")), BooleanClause.Occur.MUST); if (lookQuery.DateQuery.After.HasValue || lookQuery.DateQuery.Before.HasValue) { var includeLower = lookQuery.DateQuery.After == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeExclusiveAfterInclusive; var includeUpper = lookQuery.DateQuery.Before == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeInclusiveAfterExclusive; query.Add( new TermRangeQuery( LookConstants.DateField, lookQuery.DateQuery.After.DateToLuceneString() ?? DateTime.MinValue.DateToLuceneString(), lookQuery.DateQuery.Before.DateToLuceneString() ?? DateTime.MaxValue.DateToLuceneString(), includeLower, includeUpper), BooleanClause.Occur.MUST); } } #endregion #region TextQuery if (lookQuery.TextQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasTextField, "1")), BooleanClause.Occur.MUST); if (!string.IsNullOrWhiteSpace(lookQuery.TextQuery.SearchText)) { var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, LookConstants.TextField, lookQuery.SearchingContext.Analyzer); Query searchTextQuery = null; try { searchTextQuery = queryParser.Parse(lookQuery.TextQuery.SearchText); } catch { return(LookResult.Error($"Unable to parse LookQuery.TextQuery.SearchText: '{ lookQuery.TextQuery.SearchText }' into a Lucene query")); } if (searchTextQuery != null) { query.Add(searchTextQuery, BooleanClause.Occur.MUST); if (lookQuery.TextQuery.GetHighlight) { var queryScorer = new QueryScorer(searchTextQuery.Rewrite(lookQuery.SearchingContext.IndexSearcher.GetIndexReader())); var highlighter = new Highlighter(new SimpleHTMLFormatter("<strong>", "</strong>"), queryScorer); getHighlight = (x) => { var tokenStream = lookQuery.SearchingContext.Analyzer.TokenStream(LookConstants.TextField, new StringReader(x)); var highlight = highlighter.GetBestFragments( tokenStream, x, 1, // max number of fragments "..."); return(new HtmlString(highlight)); }; } } } } #endregion #region TagQuery if (lookQuery.TagQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasTagsField, "1")), BooleanClause.Occur.MUST); // Has if (lookQuery.TagQuery.Has != null) { query.Add( new TermQuery(new Term(LookConstants.TagsField + lookQuery.TagQuery.Has.Group, lookQuery.TagQuery.Has.Name)), BooleanClause.Occur.MUST); } // Not if (lookQuery.TagQuery.Not != null) { query.Add( new TermQuery(new Term(LookConstants.TagsField + lookQuery.TagQuery.Not.Group, lookQuery.TagQuery.Not.Name)), BooleanClause.Occur.MUST_NOT); } // HasAll if (lookQuery.TagQuery.HasAll != null && lookQuery.TagQuery.HasAll.Any()) { foreach (var tag in lookQuery.TagQuery.HasAll) { query.Add( new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)), BooleanClause.Occur.MUST); } } // HasAllOr if (lookQuery.TagQuery.HasAllOr != null && lookQuery.TagQuery.HasAllOr.Any() && lookQuery.TagQuery.HasAllOr.SelectMany(x => x).Any()) { var orQuery = new BooleanQuery(); foreach (var tagCollection in lookQuery.TagQuery.HasAllOr) { if (tagCollection.Any()) { var allTagQuery = new BooleanQuery(); foreach (var tag in tagCollection) { allTagQuery.Add( new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)), BooleanClause.Occur.MUST); } orQuery.Add(allTagQuery, BooleanClause.Occur.SHOULD); } } query.Add(orQuery, BooleanClause.Occur.MUST); } // HasAny if (lookQuery.TagQuery.HasAny != null && lookQuery.TagQuery.HasAny.Any()) { var anyTagQuery = new BooleanQuery(); foreach (var tag in lookQuery.TagQuery.HasAny) { anyTagQuery.Add( new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)), BooleanClause.Occur.SHOULD); } query.Add(anyTagQuery, BooleanClause.Occur.MUST); } // HasAnyAnd if (lookQuery.TagQuery.HasAnyAnd != null && lookQuery.TagQuery.HasAnyAnd.Any()) { foreach (var tagCollection in lookQuery.TagQuery.HasAnyAnd) { if (tagCollection.Any()) { var anyTagQuery = new BooleanQuery(); foreach (var tag in tagCollection) { anyTagQuery.Add( new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)), BooleanClause.Occur.SHOULD); } query.Add(anyTagQuery, BooleanClause.Occur.MUST); } } } // NotAny if (lookQuery.TagQuery.NotAny != null && lookQuery.TagQuery.NotAny.Any()) { foreach (var tag in lookQuery.TagQuery.NotAny) { query.Add( new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)), BooleanClause.Occur.MUST_NOT); } } } #endregion #region LocationQuery if (lookQuery.LocationQuery != null) { hasQuery = true; query.Add(new TermQuery(new Term(LookConstants.HasLocationField, "1")), BooleanClause.Occur.MUST); if (lookQuery.LocationQuery.Boundary != null) // limit results within an lat lng fixed view (eg, typical map bounds) { query.Add( new TermRangeQuery( LookConstants.LocationField + "_Latitude", NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMin), NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMax), true, true), BooleanClause.Occur.MUST); query.Add( new TermRangeQuery( LookConstants.LocationField + "_Longitude", NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMin), NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMax), true, true), BooleanClause.Occur.MUST); } if (lookQuery.LocationQuery.Location != null) // location set, so can calculate distance { double maxDistance = LookService._maxDistance; if (lookQuery.LocationQuery.MaxDistance != null) { maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance); } var distanceQueryBuilder = new DistanceQueryBuilder( lookQuery.LocationQuery.Location.Latitude, lookQuery.LocationQuery.Location.Longitude, maxDistance, LookConstants.LocationField + "_Latitude", LookConstants.LocationField + "_Longitude", LookConstants.LocationTierFieldPrefix, true); filter = distanceQueryBuilder.Filter; if (lookQuery.SortOn == SortOn.Distance) { sort = new Sort( new SortField( LookConstants.DistanceField, new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter))); } getDistance = new Func <int, double?>(x => { if (distanceQueryBuilder.DistanceFilter.Distances.ContainsKey(x)) { return(distanceQueryBuilder.DistanceFilter.Distances[x]); } return(null); }); } } #endregion if (hasQuery) { switch (lookQuery.SortOn) { case SortOn.Name: // a -> z sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField, SortField.STRING)); break; case SortOn.DateAscending: // oldest -> newest sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, false)); break; case SortOn.DateDescending: // newest -> oldest sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, true)); break; // SortOn.Distance already set (if valid) } lookQuery.Compiled = new LookQueryCompiled( lookQuery, query, filter, sort ?? new Sort(SortField.FIELD_SCORE), getHighlight, getDistance); } } if (!hasQuery) { return(LookResult.Error("No query clauses supplied")); // empty failure } TopDocs topDocs = lookQuery .SearchingContext .IndexSearcher .Search( lookQuery.Compiled.Query, lookQuery.Compiled.Filter, LookService._maxLuceneResults, lookQuery.Compiled.Sort); if (topDocs.TotalHits > 0) { List <Facet> facets = null; if (lookQuery.TagQuery != null && lookQuery.TagQuery.FacetOn != null) { facets = new List <Facet>(); Query facetQuery = lookQuery.Compiled.Filter != null ? (Query) new FilteredQuery(lookQuery.Compiled.Query, lookQuery.Compiled.Filter) : lookQuery.Compiled.Query; // do a facet query for each group in the array foreach (var group in lookQuery.TagQuery.FacetOn.TagGroups) { var simpleFacetedSearch = new SimpleFacetedSearch( lookQuery.SearchingContext.IndexSearcher.GetIndexReader(), LookConstants.TagsField + group); var facetResult = simpleFacetedSearch.Search(facetQuery); facets.AddRange( facetResult .HitsPerFacet .Select( x => new Facet() { Tags = new LookTag[] { new LookTag(group, x.Name.ToString()) }, Count = Convert.ToInt32(x.HitCount) } )); } } return(new LookResult( lookQuery, topDocs, facets != null ? facets.ToArray() : new Facet[] { })); } return(LookResult.Empty()); // empty success }
private static void IndexLocation(IndexingContext indexingContext, Document document) { if (indexingContext.Cancelled) { return; } var locationIndexer = LookService.GetLocationIndexer(indexingContext.IndexerName); if (locationIndexer != null) { Location location = null; try { location = locationIndexer(indexingContext); } catch (Exception exception) { LogHelper.WarnWithException(typeof(LookService), "Error in location indexer", exception); } if (location != null) { var hasLocationField = new Field( LookConstants.HasLocationField, "1", Field.Store.NO, Field.Index.NOT_ANALYZED); var locationField = new Field( LookConstants.LocationField, location.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED); var locationLatitudeField = new Field( LookConstants.LocationField + "_Latitude", NumericUtils.DoubleToPrefixCoded(location.Latitude), Field.Store.YES, Field.Index.NOT_ANALYZED); var locationLongitudeField = new Field( LookConstants.LocationField + "_Longitude", NumericUtils.DoubleToPrefixCoded(location.Longitude), Field.Store.YES, Field.Index.NOT_ANALYZED); document.Add(hasLocationField); document.Add(locationField); document.Add(locationLatitudeField); document.Add(locationLongitudeField); foreach (var cartesianTierPlotter in LookService.Instance._cartesianTierPlotters) { var boxId = cartesianTierPlotter.GetTierBoxId(location.Latitude, location.Longitude); var tierField = new Field( cartesianTierPlotter.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS); document.Add(tierField); } } } }
private string GetTermText(Term term) { var fieldName = term.Field(); var fieldText = term.Text(); if (fieldText == null) { return(null); } var fieldType = default(IndexValueType); if (!(LuceneSearchManager?.IndexFieldTypeInfo?.TryGetValue(fieldName, out fieldType) ?? false)) { switch (fieldName) { case "NodeTimestamp": case "VersionTimestamp": fieldType = IndexValueType.Long; break; default: var c = fieldText.ToCharArray(); for (var i = 0; i < c.Length; i++) { if (c[i] < ' ') { c[i] = '.'; } } return(new string(c)); } } var pt = Providers.Instance.StorageSchema.PropertyTypes[fieldName]; if (pt == null) { switch (fieldName) { case "CreatedBy": case "ModifiedBy": case "Owner": case "VersionCreatedBy": case "VersionModifiedBy": case "Workspace": fieldType = IndexValueType.Int; break; //case "NodeTimestamp": //case "VersionTimestamp": // fieldType = IndexValueType.Long; // break; } } else { if (pt.DataType == DataType.Reference) { fieldType = IndexValueType.Int; } } string check; switch (fieldType) { case IndexValueType.Bool: case IndexValueType.String: case IndexValueType.StringArray: return(fieldText); case IndexValueType.Int: var intValue = NumericUtils.PrefixCodedToInt(fieldText); check = NumericUtils.IntToPrefixCoded(intValue); if (check != fieldText) { return(null); } return(Convert.ToString(intValue, CultureInfo.InvariantCulture)); case IndexValueType.Long: var longValue = NumericUtils.PrefixCodedToLong(fieldText); check = NumericUtils.LongToPrefixCoded(longValue); if (check != fieldText) { return(null); } return(Convert.ToString(longValue, CultureInfo.InvariantCulture)); case IndexValueType.Float: var floatValue = NumericUtils.PrefixCodedToFloat(fieldText); check = NumericUtils.FloatToPrefixCoded(floatValue); if (check != fieldText) { return(null); } return(Convert.ToString(floatValue, CultureInfo.InvariantCulture)); case IndexValueType.Double: var doubleValue = NumericUtils.PrefixCodedToDouble(fieldText); check = NumericUtils.DoubleToPrefixCoded(doubleValue); if (check != fieldText) { return(null); } return(Convert.ToString(doubleValue, CultureInfo.InvariantCulture)); case IndexValueType.DateTime: var ticksValue = NumericUtils.PrefixCodedToLong(fieldText); check = NumericUtils.LongToPrefixCoded(ticksValue); if (check != fieldText) { return(null); } var d = new DateTime(ticksValue); if (d.Hour == 0 && d.Minute == 0 && d.Second == 0) { return(d.ToString("yyyy-MM-dd")); } if (d.Second == 0) { return(d.ToString("yyyy-MM-dd HH:mm")); } return(d.ToString("yyyy-MM-dd HH:mm:ss")); default: throw new NotSupportedException("Unknown IndexFieldType: " + fieldType); } }
/// <summary> /// Used to create the additional search fields /// </summary> /// <param name="sender"></param> /// <param name="e"></param> internal static void DocumentWriting(object sender, DocumentWritingEventArgs e) { if (e.Fields.ContainsKey(LookService.DateField)) // it's storing a date value as a long type { if (long.TryParse(e.Fields[LookService.DateField], out long ticks)) { e.Document.RemoveFields(LookService.DateField); var dateField = new NumericField( LookService.DateField, Field.Store.YES, false) .SetLongValue(ticks); var dateSortedField = new NumericField( LuceneIndexer.SortedFieldNamePrefix + LookService.DateField, Field.Store.NO, //we don't want to store the field because we're only using it to sort, not return data true) .SetLongValue(ticks); e.Document.Add(dateField); e.Document.Add(dateSortedField); } } if (e.Fields.ContainsKey(LookService.NameField)) { var name = e.Fields[LookService.NameField]; e.Document.RemoveFields(LookService.NameField); var nameField = new Field( LookService.NameField, name, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES); var nameSortedField = new Field( LuceneIndexer.SortedFieldNamePrefix + LookService.NameField, name.ToLower(), Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.NO); e.Document.Add(nameField); e.Document.Add(nameSortedField); } if (e.Fields.ContainsKey(LookService.LocationField)) { var location = new Location(e.Fields[LookService.LocationField]); var locationLatitudeField = new Field( LookService.LocationField + "_Latitude", NumericUtils.DoubleToPrefixCoded(location.Latitude), Field.Store.YES, Field.Index.NOT_ANALYZED); var locationLongitudeField = new Field( LookService.LocationField + "_Longitude", NumericUtils.DoubleToPrefixCoded(location.Longitude), Field.Store.YES, Field.Index.NOT_ANALYZED); e.Document.Add(locationLatitudeField); e.Document.Add(locationLongitudeField); foreach (var cartesianTierPlotter in LookService.Instance.CartesianTierPlotters) { var boxId = cartesianTierPlotter.GetTierBoxId(location.Latitude, location.Longitude); var tierField = new Field( cartesianTierPlotter.GetTierFieldName(), NumericUtils.DoubleToPrefixCoded(boxId), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS); e.Document.Add(tierField); } } }