Skip to content

Commit

Permalink
MB-64766: Decoding geo distances from the sort results (#2137)
Browse files Browse the repository at this point in the history
  • Loading branch information
Likith101 authored Feb 10, 2025
1 parent de678d6 commit 0cc82a6
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
17 changes: 17 additions & 0 deletions search/collector/topn.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"strconv"
"time"

"github.com/blevesearch/bleve/v2/numeric"
"github.com/blevesearch/bleve/v2/search"
"github.com/blevesearch/bleve/v2/size"
index "github.com/blevesearch/bleve_index_api"
Expand Down Expand Up @@ -500,7 +501,23 @@ func (hc *TopNCollector) finalizeResults(r index.IndexReader) error {
doc.Complete(nil)
return nil
})
if err != nil {
return err
}

// Decode geo sort keys back to its distance values
for i, so := range hc.sort {
if _, ok := so.(*search.SortGeoDistance); ok {
for _, dm := range hc.results {
// The string is a int64 bit representation of a float64 distance
distInt, err := numeric.PrefixCoded(dm.Sort[i]).Int64()
if err != nil {
return err
}
dm.Sort[i] = strconv.FormatFloat(numeric.Int64ToFloat64(distInt), 'f', -1, 64)
}
}
}
return err
}

Expand Down
75 changes: 75 additions & 0 deletions search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4406,3 +4406,78 @@ func TestSynonymSearchQueries(t *testing.T) {
t.Fatal(err)
}
}

func TestGeoDistanceInSort(t *testing.T) {
tmpIndexPath := createTmpIndexPath(t)
defer cleanupTmpIndexPath(t, tmpIndexPath)

fm := mapping.NewGeoPointFieldMapping()
imap := mapping.NewIndexMapping()
imap.DefaultMapping.AddFieldMappingsAt("geo", fm)

idx, err := New(tmpIndexPath, imap)
if err != nil {
t.Fatal(err)
}

defer func() {
err = idx.Close()
if err != nil {
t.Fatal(err)
}
}()

qp := []float64{0, 0}

docs := []struct {
id string
point []float64
distance float64
}{
{
id: "1",
point: []float64{1, 1},
distance: geo.Haversin(1, 1, qp[0], qp[1]) * 1000,
},
{
id: "2",
point: []float64{2, 2},
distance: geo.Haversin(2, 2, qp[0], qp[1]) * 1000,
},
{
id: "3",
point: []float64{3, 3},
distance: geo.Haversin(3, 3, qp[0], qp[1]) * 1000,
},
}

for _, doc := range docs {
idx.Index(doc.id, map[string]interface{}{"geo": doc.point})
}

q := NewGeoDistanceQuery(qp[0], qp[1], "1000000m")
q.SetField("geo")
req := NewSearchRequest(q)
req.Sort = make(search.SortOrder, 0)
req.Sort = append(req.Sort, &search.SortGeoDistance{
Field: "geo",
Desc: false,
Unit: "m",
Lon: qp[0],
Lat: qp[1],
})
res, err := idx.Search(req)
if err != nil {
t.Fatal(err)
}

for i, doc := range res.Hits {
hitDist, err := strconv.ParseFloat(doc.Sort[0], 64)
if err != nil {
t.Fatal(err)
}
if math.Abs(hitDist-docs[i].distance) > 1 {
t.Fatalf("distance error greater than 1 meter, expected distance - %v, got - %v", docs[i].distance, hitDist)
}
}
}

0 comments on commit 0cc82a6

Please sign in to comment.