public FilteredQuery CreateFilteredQuery(ILuceneQueryService builder, LuceneQueryContext context, string type, JToken filter, Query toFilter) { if (type != "geo_distance") { return(null); } if (!(toFilter is BooleanQuery booleanQuery)) { return(null); } var queryObj = filter as JObject; if (queryObj.Properties().Count() != 2) { return(null); } var ctx = SpatialContext.GEO; var maxLevels = 11; //results in sub-meter precision for geohash // This can also be constructed from SpatialPrefixTreeFactory SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); JProperty distanceProperty = null; JProperty geoProperty = null; foreach (var jProperty in queryObj.Properties()) { if (jProperty.Name.Equals("distance", StringComparison.Ordinal)) { distanceProperty = jProperty; } else { geoProperty = jProperty; } } if (distanceProperty == null || geoProperty == null) { return(null); } var strategy = new RecursivePrefixTreeStrategy(grid, geoProperty.Name); if (!TryParseDistance((string)distanceProperty.Value, out var distanceDegrees)) { return(null); } if (!TryGetPointFromJToken(geoProperty.Value, out var point)) { return(null); } var circle = ctx.MakeCircle(point.X, point.Y, distanceDegrees); var args = new SpatialArgs(SpatialOperation.Intersects, circle); var spatialQuery = strategy.MakeQuery(args); var valueSource = strategy.MakeRecipDistanceValueSource(circle); var valueSourceFilter = new ValueSourceFilter(new QueryWrapperFilter(spatialQuery), valueSource, 0, 1); booleanQuery.Add(new FunctionQuery(valueSource), Occur.MUST); return(new FilteredQuery(booleanQuery, valueSourceFilter)); }
//TODO this is basically old code that hasn't been verified well and should probably be removed public Query MakeQueryDistanceScore(SpatialArgs args) { // For starters, just limit the bbox var shape = args.Shape; if (!(shape is Rectangle || shape is Circle)) { throw new InvalidOperationException("Only Rectangles and Circles are currently supported, found [" + shape.GetType().Name + "]");//TODO } Rectangle bbox = shape.GetBoundingBox(); if (bbox.GetCrossesDateLine()) { throw new InvalidOperationException("Crossing dateline not yet supported"); } ValueSource valueSource = null; Query spatial = null; SpatialOperation op = args.Operation; if (SpatialOperation.Is(op, SpatialOperation.BBoxWithin, SpatialOperation.BBoxIntersects)) { spatial = MakeWithin(bbox); } else if (SpatialOperation.Is(op, SpatialOperation.Intersects, SpatialOperation.IsWithin)) { spatial = MakeWithin(bbox); var circle = args.Shape as Circle; if (circle != null) { // Make the ValueSource valueSource = MakeDistanceValueSource(shape.GetCenter()); var vsf = new ValueSourceFilter( new QueryWrapperFilter(spatial), valueSource, 0, circle.GetRadius()); spatial = new FilteredQuery(new MatchAllDocsQuery(), vsf); } } else if (op == SpatialOperation.IsDisjointTo) { spatial = MakeDisjoint(bbox); } if (spatial == null) { throw new UnsupportedSpatialOperation(args.Operation); } if (valueSource != null) { valueSource = new CachingDoubleValueSource(valueSource); } else { valueSource = MakeDistanceValueSource(shape.GetCenter()); } Query spatialRankingQuery = new FunctionQuery(valueSource); var bq = new BooleanQuery(); bq.Add(spatial, Occur.MUST); bq.Add(spatialRankingQuery, Occur.MUST); return(bq); }