Repository: dragonflydb/dragonfly (2026-05-26T17:37:29Z)

Issue:
FT.SEARCH GEO radius truncates decimal distances
### Summary

`FT.SEARCH` accepts decimal GEO radii, but the radius is truncated to an integer before unit conversion.

That means queries like `@location:[-122.08 37.386 0.5 km]` behave like `0 km`, and `1.9 mi` behaves like `1 mi`.

### Why this happens

The parser preserves decimal radii as `double` in `AstGeoNode` (`src/core/search/parser.y`), and `GeoIndex::RadiusSearch` also accepts a `double radius` (`src/core/search/indices.cc`).

But `GeoIndex::RadiusSearch` passes that value into `ConvertToRadiusInMeters(size_t radius, ...)`, so the fractional part is dropped before converting `km` / `mi` / `ft` to meters.

Relevant code paths:

- `src/core/search/parser.y`
- `src/core/search/indices.cc` (`ConvertToRadiusInMeters`)
- `src/core/search/indices.cc` (`GeoIndex::RadiusSearch`)

### Expected behavior

Fractional radii should be honored. For example, `0.5 km` should search within 500 meters, not 0 meters.

### Suggested fix

Change `ConvertToRadiusInMeters` to take `double`, and reject negative or non-finite radii before conversion.

I did a quick issue search first and didn’t find an existing report for this.



Discussion:
@fallintoplace  thanks! Would you like to fix it?
@romange Thank you. The PR is ready in a few minutes.



Patch:
diff --git a/src/core/search/indices.cc b/src/core/search/indices.cc
index fac4b0a3aa4d..74f185551a54 100644
--- a/src/core/search/indices.cc
+++ b/src/core/search/indices.cc
@@ -103,7 +103,7 @@ void IterateAllSuffixes(const absl::flat_hash_set<string>& words,
 // Haversine with earth radius in meters. Used to calculate distance.
 boost::geometry::strategy::distance::haversine haversine_(6372797.560856);
 
-double ConvertToRadiusInMeters(size_t radius, std::string_view arg) {
+double ConvertToRadiusInMeters(double radius, std::string_view arg) {
   const std::string unit = absl::AsciiStrToUpper(arg);
   if (unit == "M") {
     return radius * 1;


Test patch:
diff --git a/src/server/search/search_family_test.cc b/src/server/search/search_family_test.cc
index 9594226613ad..856707cb7914 100644
--- a/src/server/search/search_family_test.cc
+++ b/src/server/search/search_family_test.cc
@@ -4252,22 +4252,27 @@ TEST_F(SearchFamilyTest, GeoSearchHash) {
   Run({"HSET", "city:2", "name", "Palo Alto", "location", "-122.143, 37.444"});
   Run({"HSET", "city:3", "name", "San Jose", "location", "-121.886, 37.338"});
   Run({"HSET", "city:4", "name", "San Francisco", "location", "-122.419, 37.774"});
+  Run({"HSET", "city:5", "name", "Shoreline", "location", "-122.08, 37.389"});
 
   // Search within 30 miles of Mountain View - should find nearby cities
   resp = Run({"FT.SEARCH", "geo_idx", "@location:[-122.08 37.386 30 mi]"});
-  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3"));
+  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3", "city:5"));
 
   // Search within 50 miles - should include San Francisco
   resp = Run({"FT.SEARCH", "geo_idx", "@location:[-122.08 37.386 50 mi]"});
-  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3", "city:4"));
+  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3", "city:4", "city:5"));
 
-  // Search with very small radius - only exact match
+  // Search within 1 km - should include the nearby point.
   resp = Run({"FT.SEARCH", "geo_idx", "@location:[-122.08 37.386 1 km]"});
-  EXPECT_THAT(resp, AreDocIds("city:1"));
+  EXPECT_THAT(resp, AreDocIds("city:1", "city:5"));
+
+  // Fractional radii should not be truncated before unit conversion.
+  resp = Run({"FT.SEARCH", "geo_idx", "@location:[-122.08 37.386 0.5 km]"});
+  EXPECT_THAT(resp, AreDocIds("city:1", "city:5"));
 
   // Search with wildcard - return all geo indexed docs
   resp = Run({"FT.SEARCH", "geo_idx", "@location:*"});
-  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3", "city:4"));
+  EXPECT_THAT(resp, AreDocIds("city:1", "city:2", "city:3", "city:4", "city:5"));
 
   // Combine geo search with text search
   resp = Run({"FT.SEARCH", "geo_idx", "San* @location:[-122.08 37.386 50 mi]"});