Repository: blevesearch/bleve
Pull request #1672 (2022-04-07 02:01:36)

Adding new construct methods for circle, geometrycollection
shapes. Updating the query unit tests.


Patch:
diff --git a/search/query/geo_shape.go b/search/query/geo_shape.go
index 47c8a1d6..1fa7b13b 100644
--- a/search/query/geo_shape.go
+++ b/search/query/geo_shape.go
@@ -35,13 +35,54 @@ type GeoShapeQuery struct {
 	BoostVal *Boost   `json:"boost,omitempty"`
 }
 
-func NewGeoShapeQuery(coordinates [][][][]float64, typ, relation string) *GeoShapeQuery {
+// NewGeoShapeQuery creates a geoshape query for the
+// given shape type. This method can be used for
+// creating geoshape queries for shape types like: point,
+// linestring, polygon, multipoint, multilinestring,
+// multipolygon and envelope.
+func NewGeoShapeQuery(coordinates [][][][]float64, typ,
+	relation string) (*GeoShapeQuery, error) {
 	s, _, err := geo.NewGeoJsonShape(coordinates, typ)
 	if err != nil {
-		return nil
+		return nil, err
 	}
 
-	return &GeoShapeQuery{Geometry: Geometry{Shape: s, Relation: relation}}
+	return &GeoShapeQuery{Geometry: Geometry{Shape: s,
+		Relation: relation}}, nil
+}
+
+// NewGeoShapeCircleQuery creates a geoshape query for the
+// given center point and the radius. Radius formats supported:
+// "5in" "5inch" "7yd" "7yards" "9ft" "9feet" "11km" "11kilometers"
+// "3nm" "3nauticalmiles" "13mm" "13millimeters" "15cm" "15centimeters"
+// "17mi" "17miles" "19m" "19meters" If the unit cannot be determined,
+// the entire string is parsed and the unit of meters is assumed.
+func NewGeoShapeCircleQuery(coordinates []float64, radius,
+	relation string) (*GeoShapeQuery, error) {
+	radiusInMeters, err := geo.ParseDistance(radius)
+	if err != nil {
+		return nil, err
+	}
+	s, _, err := geo.NewGeoCircleShape(coordinates, radiusInMeters)
+	if err != nil {
+		return nil, err
+	}
+
+	return &GeoShapeQuery{Geometry: Geometry{Shape: s,
+		Relation: relation}}, nil
+}
+
+// NewGeometryCollectionQuery creates a geoshape query for the
+// given geometrycollection coordinates and types.
+func NewGeometryCollectionQuery(coordinates [][][][][]float64, types []string,
+	relation string) (*GeoShapeQuery, error) {
+	s, _, err := geo.NewGeometryCollection(coordinates, types)
+	if err != nil {
+		return nil, err
+	}
+
+	return &GeoShapeQuery{Geometry: Geometry{Shape: s,
+		Relation: relation}}, nil
 }
 
 func (q *GeoShapeQuery) SetBoost(b float64) {
@@ -68,7 +109,8 @@ func (q *GeoShapeQuery) Searcher(i index.IndexReader,
 		field = m.DefaultSearchField()
 	}
 
-	return searcher.NewGeoShapeSearcher(i, q.Geometry.Shape, q.Geometry.Relation, field, q.BoostVal.Value(), options)
+	return searcher.NewGeoShapeSearcher(i, q.Geometry.Shape, q.Geometry.Relation, field,
+		q.BoostVal.Value(), options)
 }
 
 func (q *GeoShapeQuery) Validate() error {


Test patch:
diff --git a/search/query/query_test.go b/search/query/query_test.go
index ffa9c5b8..1794f16d 100644
--- a/search/query/query_test.go
+++ b/search/query/query_test.go
@@ -450,42 +450,41 @@ func TestGeoShapeQuery(t *testing.T) {
 		err    bool
 	}{
 		{
-			input: []byte(`{      
+			input: []byte(`{
 				"field" : "region",
 				 "geometry": {
 					 "shape": {
 						 "type": "polygon",
-						"coordinates": [
-							[                 
-							[                   
+						"coordinates": [[
+							[
 								74.1357421875,
 								30.600093873550072
-							],              
-							[                  
+							],
+							[
 								67.0166015625,
 								21.57571893245848
-							],              
-							[                  
+							],
+							[
 								68.8623046875,
 								9.145486056167277
-							],              
-							[                  
+							],
+							[
 								83.1884765625,
 								4.083452772038619
-							],              
-							[                  
+							],
+							[
 								88.9892578125,
 								22.67484735118852
-							],              
-							[                   
+							],
+							[
 								74.1357421875,
 								30.600093873550072
-							]]]                       
+							]]]
 						},
 					  "relation": "intersects"
 			  }}`),
 			output: func() Query {
-				q := NewGeoShapeQuery([][][][]float64{{{{74.1357421875, 30.600093873550072},
+				q, _ := NewGeoShapeQuery([][][][]float64{{{{74.1357421875, 30.600093873550072},
 					{67.0166015625, 21.57571893245848}, {68.8623046875, 9.145486056167277},
 					{83.1884765625, 4.083452772038619}, {88.9892578125, 22.67484735118852},
 					{74.1357421875, 30.600093873550072}}}}, geo.PolygonType, "intersects")
@@ -493,6 +492,256 @@ func TestGeoShapeQuery(t *testing.T) {
 				return q
 			}(),
 		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "multipolygon",
+						 "coordinates": [
+							 [[
+								[
+									77.58268117904663,
+									12.980513152175025
+								],
+								[
+									77.58147954940794,
+									12.977983107483992
+								],
+								[
+									77.58708000183104,
+									12.97886130773254
+								],
+								[
+									77.58268117904663,
+									12.980513152175025
+								]
+							]],
+							[[
+								[
+									77.5864577293396,
+									12.97762764459667
+								],
+								[
+									77.58879661560059,
+									12.975076660730531
+								],
+								[
+									77.59115695953369,
+									12.979216768855913
+								],
+								[
+									77.5864577293396,
+									12.97762764459667
+								]
+							]]
+						]
+					},
+					"relation": "contains"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{
+					{{{77.58268117904663, 12.980513152175025},
+						{77.58147954940794, 12.977983107483992}, {77.58708000183104, 12.97886130773254},
+						{77.58268117904663, 12.980513152175025}}},
+					{{{77.5864577293396, 12.97762764459667}, {77.58879661560059, 12.975076660730531},
+						{77.59115695953369, 12.979216768855913}, {77.5864577293396, 12.97762764459667}}}},
+					geo.MultiPolygonType, "contains")
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "point",
+						 "coordinates": [77.58268117904663, 12.980513152175025]
+					},
+					"relation": "contains"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{
+					{{{77.58268117904663, 12.980513152175025}}}},
+					geo.PointType, "contains")
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "multipoint",
+						 "coordinates": [[77.58268117904663, 12.980513152175025],
+						 [77.5864577293396, 12.97762764459667]]
+					},
+					"relation": "intersects"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{
+					{{{77.58268117904663, 12.980513152175025},
+						{77.5864577293396, 12.97762764459667}}}},
+					geo.MultiPointType, "intersects")
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "linestring",
+						 "coordinates": [[77.58268117904663, 12.980513152175025],
+						 [77.5864577293396, 12.97762764459667]]
+					},
+					"relation": "intersects"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{
+					{{{77.58268117904663, 12.980513152175025},
+						{77.5864577293396, 12.97762764459667}}}},
+					geo.LineStringType, "intersects")
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "multilinestring",
+						 "coordinates": [
+						[[77.58268117904663, 12.980513152175025],
+						 [77.5864577293396, 12.97762764459667]],
+						 [[77.5864577293396,12.97762764459667],
+						 [77.58879661560059, 12.975076660730531]]]
+					},
+					"relation": "intersects"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{{
+					{{77.58268117904663, 12.980513152175025},
+						{77.5864577293396, 12.97762764459667}},
+					{{77.5864577293396, 12.97762764459667},
+						{77.58879661560059, 12.975076660730531}}}},
+					geo.MultiLineStringType, "intersects")
+
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "envelope",
+						 "coordinates": [[77.58268117904663, 12.980513152175025],
+						 [77.5864577293396, 12.97762764459667]]
+					},
+					"relation": "within"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeQuery([][][][]float64{{
+					{{77.58268117904663, 12.980513152175025},
+						{77.5864577293396, 12.97762764459667}}}},
+					geo.EnvelopeType, "within")
+
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				 "geometry": {
+					 "shape": {
+						 "type": "circle",
+						 "coordinates": [77.58268117904663, 12.980513152175025],
+						 "radius": "100m"
+					},
+					"relation": "within"
+			  }}`),
+			output: func() Query {
+				q, _ := NewGeoShapeCircleQuery([]float64{
+					77.58268117904663, 12.980513152175025},
+					"100m", "within")
+
+				q.SetField("region")
+				return q
+			}(),
+		},
+		{
+			input: []byte(`{
+				"field" : "region",
+				"geometry": {
+					"shape": {
+					  "type": "geometrycollection",
+					  "geometries": [
+						{
+						  "type": "point",
+						  "coordinates": [
+							77.59158611297607,
+							12.972002899506203
+						  ]
+						},
+						{
+						  "type": "linestring",
+						  "coordinates": [
+							[
+							  77.58851766586304,
+							  12.973152950670608
+							],
+							[
+							  77.58937597274779,
+							  12.972212000113458
+							]
+						  ]
+						},
+						{
+						  "type": "polygon",
+						  "coordinates": [
+							[
+							  [
+								77.59055614471436,
+								12.974721193688106
+							  ],
+							  [
+								77.58954763412476,
+								12.97350841995465
+							  ],
+							  [
+								77.59141445159912,
+								12.973382960265356
+							  ],
+							  [
+								77.59055614471436,
+								12.974721193688106
+							  ]
+							]
+						  ]
+						}
+					  ]
+					},
+					"relation": "contains"
+				  }}`),
+			output: func() Query {
+				q, _ := NewGeometryCollectionQuery([][][][][]float64{
+					{{{{77.59158611297607, 12.972002899506203}}}},
+					{{{{77.58851766586304, 12.973152950670608}, {77.58937597274779, 12.972212000113458}}}},
+					{{{{77.59055614471436, 12.974721193688106}, {77.58954763412476, 12.97350841995465},
+						{77.59141445159912, 12.973382960265356}, {77.59055614471436, 12.974721193688106}}}},
+				},
+					[]string{"point", "linestring", "polygon"}, "contains")
+				q.SetField("region")
+				return q
+			}(),
+		},
 	}
 
 	for i, test := range tests {