private static void BenchmarkSearch(ISpatialIndex index, int rounds) { var query = new KnnQuery { Coordinate = new GeoCoordinate(52.3667, 4.900), MaxDistance = 10000, MaxResults = 15 }; Console.Write("Searching top {0} within {1} m from [{2}] .. ", query.MaxResults, query.MaxDistance, query.Coordinate); var total = 0L; var timer = new Stopwatch(); for (int i = rounds; i > 0; i--) { timer.Restart(); index.KnnSearch(query); timer.Stop(); total += timer.ElapsedMilliseconds; } Console.WriteLine("ok ({0} ms)", total / rounds); }
private KnnQueryResult InternalKnnSearch(KnnQuery query) { // get search area var searchArea = GetSearchArea(query); // query the quadtree var docs = _quadTree.Search(searchArea); // almost done, but remember we searched a rectangle // so we need to exclude some of these results. // Let's do that while calculating the distance var results = new List<KnnQueryResultItem>(); foreach (var doc in docs) { var distance = query.Coordinate.CalculateDistance(doc.Coordinates); if (distance <= query.MaxDistance) results.Add(new KnnQueryResultItem(doc, distance)); } // this could be done more efficiently by inserting into an ordered structure // unfortunatelly SortedList<> doesn't allow duplicated keys. // but there is definetely space for optimization here results.Sort((x, y) => x.Distance.CompareTo(y.Distance)); // reduce set to max results results = results.Take(query.MaxResults).ToList(); return KnnQueryResult.Success(results); }
public KnnQueryResult KnnSearch(KnnQuery query) { var search = from doc in _docs let distance = query.Coordinate.CalculateDistance(doc.Coordinates) where distance <= query.MaxDistance orderby distance select new KnnQueryResultItem(doc, distance); // list results taking top max var results = search.Take(query.MaxResults).ToList(); return KnnQueryResult.Success(results); }
public KnnQueryResult KnnSearch(KnnQuery query) { if (query == null) throw new ArgumentException("Parameter query cannot be null"); // validate query if (!IsQueryValid(query)) return KnnQueryResult.Fail("Query is not valid. Please verify search parameters"); // execute search var result = InternalKnnSearch(query); return result; }
private Boundary GetSearchArea(KnnQuery query) { var top = query.Coordinate.Add(query.MaxDistance, 0); var bottom = query.Coordinate.Add(-query.MaxDistance, 0); var right = query.Coordinate.Add(0, query.MaxDistance); var left = query.Coordinate.Add(0, -query.MaxDistance); var halfLatitude = (top.Latitude - bottom.Latitude) / 2; var halfLongitude = (right.Longitude - left.Longitude) / 2; var center = new Point(left.Longitude + halfLongitude, bottom.Latitude + halfLatitude); var searchArea = new Boundary(center, halfLongitude, halfLatitude); // TODO: consider borders. search might need to be split into two. return searchArea; }
public LocationSearchResults Search(LocationSearchRequest search) { // TODO: validate search parameter var query = new KnnQuery { Coordinate = search.Coordinate, MaxDistance = search.MaxDistance, MaxResults = search.MaxResults }; // use spatial index to reduce data set var knnQueryResult = _spatialIndex.KnnSearch(query); if (!knnQueryResult.Results.Any()) return LocationSearchResults.ZeroResults(); // now load entities from database var ids = knnQueryResult.Results.Select(i => i.Document.Id).ToArray(); var locations = _locationRepository.FindIn(ids); // build return results by joining Location and Distance var results = new List<LocationSearchResultItem>(); var locationsIndex = locations.ToDictionary(l => l.Id); foreach (var item in knnQueryResult.Results) { if (locationsIndex.ContainsKey(item.Document.Id)) { var location = locationsIndex[item.Document.Id]; results.Add(new LocationSearchResultItem(location, item.Distance)); } } return LocationSearchResults.Success(results); }
private bool IsQueryValid(KnnQuery query) { // Coordinates are required if (query.Coordinate == null) return false; // Max results should be greater than zero if (query.MaxResults <= 0) return false; // Max distance should be greater than zeo if (query.MaxDistance <= 0) return false; // Other validation rules // Max distance shouldn't be greater than ... setttings.. return true; }
public KnnQueryResult KnnSearch(KnnQuery query) { return KnnQueryResult.ZeroResults(); }