Skip to content

Commit b77be9d

Browse files
author
AJ Roetker
committed
Port Jan's geodistance functions
1 parent c0cb191 commit b77be9d

File tree

6 files changed

+126
-6
lines changed

6 files changed

+126
-6
lines changed

generators/blevegen/blevegenerator.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package blevegen
33
import (
44
"errors"
55
"fmt"
6+
"strconv"
67
"strings"
78
"time"
89

@@ -396,6 +397,40 @@ func (fg *FilterGenerator) funcExpr(node *expr.FuncNode, _ int) (query.Query, er
396397
}
397398

398399
return makeTimeWindowQuery(lhs, threshold.Int64, window.Int64, int64(DayBucket(fg.ts)))
400+
case "geodistance":
401+
if len(node.Args) != 3 {
402+
return nil, fmt.Errorf("'geodistance' function requires 3 arguments, got %d", len(node.Args))
403+
}
404+
lhs, err := fg.fieldType(node.Args[0])
405+
if err != nil {
406+
return nil, err
407+
}
408+
n, ok := node.Args[1].(*expr.StringNode)
409+
if !ok {
410+
return nil, fmt.Errorf("qlindex: unsupported type for 'geodistance' location argument. must be string, got %s", node.Args[1].NodeType())
411+
}
412+
lat, lon, ok := gentypes.StringToLatLng(n.Text)
413+
if !ok {
414+
return nil, fmt.Errorf("qlindex: unsupported format for 'geodistance' location. must be \"latitude,longitude\", got %s", n.Text)
415+
}
416+
var distance float64
417+
switch n := node.Args[2].(type) {
418+
case *expr.NumberNode:
419+
if n.IsFloat {
420+
distance = n.Float64
421+
} else {
422+
distance = float64(n.Int64)
423+
}
424+
case *expr.StringNode:
425+
f, err := strconv.ParseFloat(n.Text, 64)
426+
if err != nil {
427+
return nil, fmt.Errorf("qlindex: unsupported format for 'geodistance' distance. must be number, got %s", n.Text)
428+
}
429+
distance = f
430+
default:
431+
return nil, fmt.Errorf("qlindex: unsupported type for 'geodistance' distance argument. must be number, got %s", node.Args[2].NodeType())
432+
}
433+
return makeGeoDistanceQuery(lhs, lat, lon, distance)
399434
}
400435
return nil, fmt.Errorf("qlindex: unsupported function: %s", node.Name)
401436
}

generators/blevegen/blevegenerator_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ func NewBleveIndexerMemOnly() (*BleveIndexer, error) {
3636
documentMapping := bleve.NewDocumentMapping()
3737
keywordFieldMapping := bleve.NewKeywordFieldMapping()
3838
keywordFieldMapping.Name = "title"
39-
//keywordFieldMapping.Store = false
40-
// keywordFieldMapping.IncludeTermVectors = false
41-
// keywordFieldMapping.IncludeInAll = false
42-
// keywordFieldMapping.DocValues = false
39+
keywordFieldMapping.Store = false
40+
keywordFieldMapping.IncludeTermVectors = false
41+
keywordFieldMapping.IncludeInAll = false
42+
keywordFieldMapping.DocValues = false
4343
documentMapping.Fields = append(documentMapping.Fields, keywordFieldMapping)
4444
indexMapping.AddDocumentMapping("book", documentMapping)
4545
allDocumentMapping := bleve.NewDocumentMapping()
46-
// allDocumentMapping.Enabled = false
46+
allDocumentMapping.Enabled = false
4747
indexMapping.AddDocumentMapping("_all", allDocumentMapping)
48-
// indexMapping.StoreDynamic = false
48+
indexMapping.StoreDynamic = false
4949
// indexMapping.DocValuesDynamic = false
5050
// indexMapping.IndexDynamic = false
5151

generators/blevegen/bridgeutil.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,14 @@ func makeDateBetweenQuery(fieldName string, lower, upper any) (query.Query, erro
283283
return dateRangeQuery, nil
284284
}
285285

286+
func makeGeoDistanceQuery(lhs *gentypes.FieldType, lat, lon, distance float64) (query.Query, error) {
287+
// Create a geo distance query
288+
distanceQuery := query.NewGeoDistanceQuery(lon, lat, fmt.Sprintf("%fkm", distance))
289+
distanceQuery.SetField(lhs.Field)
290+
291+
return distanceQuery, nil
292+
}
293+
286294
// makeWildcard returns a wildcard/prefix query for Bleve
287295
func makeWildcard(lhs *gentypes.FieldType, value string, addStars bool) (query.Query, error) {
288296
fieldName := lhs.Field

generators/esgen/esgenerator.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package esgen
33
import (
44
"errors"
55
"fmt"
6+
"strconv"
67
"strings"
78
"time"
89

@@ -326,6 +327,53 @@ func (fg *FilterGenerator) funcExpr(node *expr.FuncNode, _ int) (any, error) {
326327
}
327328

328329
return makeTimeWindowQuery(lhs, threshold.Int64, window.Int64, int64(DayBucket(fg.ts)))
330+
case "geodistance":
331+
if len(node.Args) != 3 {
332+
return nil, fmt.Errorf("'geodistance' function requires 3 arguments, got %d", len(node.Args))
333+
}
334+
lhs, err := fg.fieldType(node.Args[0])
335+
if err != nil {
336+
return nil, err
337+
}
338+
n, ok := node.Args[1].(*expr.StringNode)
339+
if !ok {
340+
return nil, fmt.Errorf("qlindex: unsupported type for 'geodistance' location argument. must be string, got %s", node.Args[1].NodeType())
341+
}
342+
lat, lon, ok := gentypes.StringToLatLng(n.Text)
343+
if !ok {
344+
return nil, fmt.Errorf("qlindex: unsupported format for 'geodistance' location. must be \"latitude,longitude\", got %s", n.Text)
345+
}
346+
var distance float64
347+
switch n := node.Args[2].(type) {
348+
case *expr.NumberNode:
349+
if n.IsFloat {
350+
distance = n.Float64
351+
} else {
352+
distance = float64(n.Int64)
353+
}
354+
case *expr.StringNode:
355+
f, err := strconv.ParseFloat(n.Text, 64)
356+
if err != nil {
357+
return nil, fmt.Errorf("qlindex: unsupported format for 'geodistance' distance. must be number, got %s", n.Text)
358+
}
359+
distance = f
360+
default:
361+
return nil, fmt.Errorf("qlindex: unsupported type for 'geodistance' distance argument. must be number, got %s", node.Args[2].NodeType())
362+
}
363+
return makeGeoDistanceQuery(lhs, lat, lon, distance), nil
329364
}
330365
return nil, fmt.Errorf("qlindex: unsupported function: %s", node.Name)
331366
}
367+
368+
func makeGeoDistanceQuery(lhs *gentypes.FieldType, lat, lon, distance float64) any {
369+
return &GeoDistanceFilter{
370+
GeoDistance: map[string]any{
371+
"distance": fmt.Sprintf("%fkm", distance),
372+
fmt.Sprintf("%s.location", lhs.Field): map[string]any{
373+
"lat": lat,
374+
"lon": lon,
375+
},
376+
"distance_type": "plane",
377+
},
378+
}
379+
}

generators/esgen/estypes.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,7 @@ func wcFunc(val string, addStars bool) string {
209209
func Wildcard(field, value string, addStars bool) *wildcard {
210210
return &wildcard{Wildcard: map[string]string{field: wcFunc(value, addStars)}}
211211
}
212+
213+
type GeoDistanceFilter struct {
214+
GeoDistance map[string]any `json:"geo_distance"`
215+
}

generators/gentypes/utils.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package gentypes
2+
3+
import (
4+
"strconv"
5+
"strings"
6+
)
7+
8+
func StringToLatLng(s string) (float64, float64, bool) {
9+
if len(s) < 1 {
10+
return 0, 0, false
11+
}
12+
parts := strings.Split(s, ",")
13+
if len(parts) != 2 {
14+
return 0, 0, false
15+
}
16+
first, err := strconv.ParseFloat(strings.TrimSpace(parts[0]), 64)
17+
if err != nil {
18+
return 0, 0, false
19+
}
20+
second, err := strconv.ParseFloat(strings.TrimSpace(parts[1]), 64)
21+
if err != nil {
22+
return 0, 0, false
23+
}
24+
return first, second, true
25+
}

0 commit comments

Comments
 (0)