Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Geo Shape Query #1058

Open
wants to merge 2 commits into
base: release-branch.v6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -26,6 +26,7 @@ before_install:
- docker-compose up -d
- go get -u github.com/google/go-cmp/cmp
- go get -u github.com/fortytw2/leaktest
- go get -u github.com/stretchr/testify/require
- go get . ./aws/... ./config/... ./trace/... ./uritemplates/...
- while ! nc -z localhost 9200; do sleep 1; done
- while ! nc -z localhost 9210; do sleep 1; done
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -334,7 +334,7 @@ The cat APIs are not implemented as of now. We think they are better suited for
- [x] Has Parent Query
- [x] Parent Id Query
- Geo queries
- [ ] GeoShape Query
- [x] GeoShape Query
- [x] Geo Bounding Box Query
- [x] Geo Distance Query
- [x] Geo Polygon Query
Expand Down
37 changes: 37 additions & 0 deletions geo/circle.go
@@ -0,0 +1,37 @@
package geo

import (
"encoding/json"
)

// Circle specified by a center point and radius with units,
// which default to meters.
type Circle struct {
Type string `json:"type"`
Radius string `json:"radius"`
Coordinates []float64 `json:"coordinates"`
}

// NewCircle creates and initializes a new Circle.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a method to verify the arguments?
for example: the order of coordinates, Lon and Lat or Lat and Lon.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, no, there's not, I will implement it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some functions like this in geo_point.go.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are roughly based on GeoPoint.java.

func NewCircle(radius string, coordinates []float64) *Circle {
return &Circle{
Type: TypeCircle,
Radius: radius,
Coordinates: coordinates,
}
}

// UnmarshalJSON decodes the circle data into a GeoJSON geometry.
func (m *Circle) UnmarshalJSON(data []byte) error {
raw := &rawGeometry{}
if err := json.Unmarshal(data, raw); err != nil {
return err
}
return m.decode(raw)
}

func (m *Circle) decode(raw *rawGeometry) error {
m.Type = raw.Type
m.Radius = raw.Radius
return json.Unmarshal(raw.Coordinates, &m.Coordinates)
}
32 changes: 32 additions & 0 deletions geo/envelope.go
@@ -0,0 +1,32 @@
package geo

import "encoding/json"

// Envelope consists of coordinates for upper left and lower right points of the shape
// to represent a bounding rectangle.
type Envelope struct {
Type string `json:"type"`
Coordinates [][]float64 `json:"coordinates"`
}

// NewEnvelope creates and initializes a new Rectangle.
func NewEnvelope(coordinates [][]float64) *Envelope {
return &Envelope{
Type: TypeEnvelope,
Coordinates: coordinates,
}
}

// UnmarshalJSON decodes the envelope data into a GeoJSON geometry.
func (m *Envelope) UnmarshalJSON(data []byte) error {
raw := &rawGeometry{}
if err := json.Unmarshal(data, raw); err != nil {
return err
}
return m.decode(raw)
}

func (m *Envelope) decode(raw *rawGeometry) error {
m.Type = raw.Type
return json.Unmarshal(raw.Coordinates, &m.Coordinates)
}
156 changes: 156 additions & 0 deletions geo/exampledata_test.go
@@ -0,0 +1,156 @@
package geo

// Examples from RFC7946
// https://tools.ietf.org/html/rfc7946

var point = []byte(`
{
"type":"point",
"coordinates":[100.0, 0.0]
}
`)

var multiPoint = []byte(`
{
"type":"multipoint",
"coordinates":[
[100.0, 0.0],
[101.0, 1.0]
]
}
`)

var lineString = []byte(`
{
"type":"linestring",
"coordinates":[
[100.0, 0.0],
[101.0, 1.0]
]
}
`)

var multiLineString = []byte(`

{
"type":"multilinestring",
"coordinates":[
[
[100.0, 0.0],
[101.0, 1.0]
],
[
[102.0, 2.0],
[103.0, 3.0]
]
]
}
`)

var polygon = []byte(`
{
"type":"polygon",
"coordinates":[
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
}
`)

var polygonWithHoles = []byte(`
{
"type":"polygon",
"coordinates":[
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
],
[
[100.2, 0.2],
[100.8, 0.2],
[100.8, 0.8],
[100.2, 0.8],
[100.2, 0.2]
]
]
}

`)

var multiPolygon = []byte(`
{
"type":"multipolygon",
"coordinates":[
[
[
[102.0, 2.0],
[103.0, 2.0],
[103.0, 3.0],
[102.0, 3.0],
[102.0, 2.0]
]
],
[
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
],
[
[100.2, 0.2],
[100.8, 0.2],
[100.8, 0.8],
[100.2, 0.8],
[100.2, 0.2]
]
]
]
}
`)

var geometryCollection = []byte(`
{
"type":"geometrycollection",
"geometries":[
{
"type":"point",
"coordinates":[100.0, 0.0]
},
{
"type":"linestring",
"coordinates":[
[101.0, 0.0],
[102.0, 1.0]
]
}
]
}
`)

var envelope = []byte(`
{
"type":"envelope",
"coordinates":[
[100.0, 1.0],
[101.0, 0.0]
]
}
`)

var circle = []byte(`
{
"type":"circle",
"radius":"25m",
"coordinates":[-109.874838, 44.439550]
}
`)
29 changes: 29 additions & 0 deletions geo/geometry.go
@@ -0,0 +1,29 @@
package geo

import (
"encoding/json"
)

// The geometry types supported by Elasticsearch.
//
// For more details, see:
// https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#spatial-strategy
const (
TypePoint = "point"
TypeMultiPoint = "multipoint"
TypeLineString = "linestring"
TypeMultiLineString = "multilinestring"
TypePolygon = "polygon"
TypeMultiPolygon = "multipolygon"
TypeGeometryCollection = "geometrycollection"
TypeEnvelope = "envelope"
TypeCircle = "circle"
)

// rawGeometry holds generic data used to unmarshal GeoJSON information.
type rawGeometry struct {
Type string `json:"type"`
Coordinates json.RawMessage `json:"coordinates"`
Geometries []rawGeometry `json:"geometries"`
Radius string `json:"radius,omitempty"`
}