Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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;
        }
Example #5
0
        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;
        }
Example #6
0
        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);
        }
Example #7
0
        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;
        }
Example #8
0
 public KnnQueryResult KnnSearch(KnnQuery query)
 {
     return KnnQueryResult.ZeroResults();
 }