|
| 1 | +--- |
| 2 | +categories: |
| 3 | +- docs |
| 4 | +- develop |
| 5 | +- stack |
| 6 | +- oss |
| 7 | +- rs |
| 8 | +- rc |
| 9 | +- oss |
| 10 | +- kubernetes |
| 11 | +- clients |
| 12 | +description: Learn how to use geospatial fields and perform geospatial queries in Redis |
| 13 | +linkTitle: Geospatial |
| 14 | +math: true |
| 15 | +title: Geospatial |
| 16 | +weight: 14 |
| 17 | +--- |
| 18 | + |
| 19 | +Redis Query Engine supports geospatial data. This feature |
| 20 | +lets you store geographical locations and geometric shapes |
| 21 | +in the fields of JSON objects. |
| 22 | + |
| 23 | +{{< note >}}Take care not to confuse the geospatial indexing |
| 24 | +features in Redis Query Engine with the |
| 25 | +[Geospatial data type]({{< relref "/develop/data-types/geospatial" >}}) |
| 26 | +that Redis also supports. Although there are some similarities between |
| 27 | +these two features, the data type is intended for simpler use |
| 28 | +cases and doesn't have the range of format options and queries |
| 29 | +available in Redis Query Engine. |
| 30 | +{{< /note >}} |
| 31 | + |
| 32 | +You can index these fields and use queries to find the objects |
| 33 | +by their location or the relationship of their shape to other shapes. |
| 34 | +For example, if you add the locations of a set of shops, you can |
| 35 | +find all the shops within 5km of a user's position or determine |
| 36 | +which ones are within the boundary of a particular town. |
| 37 | + |
| 38 | +Redis uses coordinate points to represent geospatial locations. |
| 39 | +You can store individual points but you can also |
| 40 | +use a set of points to define a polygon shape (the shape of a |
| 41 | +town, for example). You can query several types of interactions |
| 42 | +between points and shapes, such as whether a point lies within |
| 43 | +a shape or whether two shapes overlap. |
| 44 | + |
| 45 | +Redis can interpret coordinates either as geographical longitude |
| 46 | +and latitude or as Cartesian coordinates on a flat plane. |
| 47 | +Geographical coordinates are ideal for large real-world locations |
| 48 | +and areas (such as towns and countries). Cartesian coordinates |
| 49 | +are more suitable for smaller areas (such as rooms in a building) |
| 50 | +or for games, simulations, and other artificial scenarios. |
| 51 | + |
| 52 | +## Storing geospatial data |
| 53 | + |
| 54 | +Redis supports two different |
| 55 | +[schema types]({{< relref "/develop/interact/search-and-query/basic-constructs/field-and-type-options" >}}) |
| 56 | +for geospatial data: |
| 57 | + |
| 58 | +- [`GEO`](#geo): This uses a simple format where individual geospatial |
| 59 | + points are specified as numeric longitude-latitude pairs. |
| 60 | + |
| 61 | +- [`GEOSHAPE`](#geoshape): [Redis Community Edition]({{< relref "/operate/oss_and_stack" >}}) also |
| 62 | + supports `GEOSHAPE` indexing in v7.2 and later. |
| 63 | + This uses a subset of the |
| 64 | + [Well-Known Text (WKT)](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) |
| 65 | + format to specify both points and polygons using either geographical |
| 66 | + coordinates or Cartesian coordinates. A |
| 67 | + `GEOSHAPE` field supports more advanced queries than `GEO`, |
| 68 | + such as checking if one shape overlaps or contains another. |
| 69 | + |
| 70 | +The sections below describe these schema types in more detail. |
| 71 | + |
| 72 | +## `GEO` |
| 73 | + |
| 74 | +A `GEO` index lets you represent geospatial data either as |
| 75 | +a string containing a longitude-latitude pair (for example, |
| 76 | +"-104.991531, 39.742043") or as a JSON array of these |
| 77 | +strings. Note that the longitude value comes first in the |
| 78 | +string. |
| 79 | + |
| 80 | +For example, you could index the `location` fields of the |
| 81 | +the [JSON]({{< relref "/develop/data-types/json" >}}) objects |
| 82 | +shown below as `GEO`: |
| 83 | + |
| 84 | +```json |
| 85 | +{ |
| 86 | + "description": "Navy Blue Slippers", |
| 87 | + "price": 45.99, |
| 88 | + "city": "Denver", |
| 89 | + "location": "-104.991531, 39.742043" |
| 90 | +} |
| 91 | + |
| 92 | +{ |
| 93 | + "description": "Bright Red Boots", |
| 94 | + "price": 185.75, |
| 95 | + "city": "Various", |
| 96 | + "location": [ |
| 97 | + "-104.991531, 39.742043", |
| 98 | + "-105.0618814,40.5150098" |
| 99 | + ] |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +`GEO` fields allow only basic point and radius queries. |
| 104 | +For example, the query below finds products within a 100 mile radius of Colorado Springs |
| 105 | +(Longitude=-104.800644, Latitude=38.846127). |
| 106 | + |
| 107 | +```bash |
| 108 | +FT.SEARCH productidx '@location:[-104.800644 38.846127 100 mi]' |
| 109 | +``` |
| 110 | + |
| 111 | +See [Geospatial queries]({{< relref "/develop/interact/search-and-query/query/geo-spatial" >}}) |
| 112 | +for more information about the available query options and see |
| 113 | +[Geospatial indexing]({{< relref "/develop/interact/search-and-query/indexing/geoindex" >}}) |
| 114 | +for examples of indexing `GEO` fields. |
| 115 | + |
| 116 | +## `GEOSHAPE` |
| 117 | + |
| 118 | +Fields indexed as `GEOSHAPE` support the `POINT` and `POLYGON` primitives from the |
| 119 | +[Well-Known Text](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) |
| 120 | +representation of geometry. The `POINT` primitive defines a single point |
| 121 | +in a similar way to a `GEO` field. |
| 122 | +The `geom` field of the example JSON object shown below specifies a point |
| 123 | +(in Cartesian coordinates, using the standard x,y order): |
| 124 | + |
| 125 | +```json |
| 126 | +{ |
| 127 | + "name": "Purple Point", |
| 128 | + "geom": "POINT (2 2)" |
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +The `POLYGON` primitive can approximate the outline of any shape using a |
| 133 | +sequence of points. Specify the coordinates of the corners in the order they |
| 134 | +occur around the shape (either clockwise or counter-clockwise) and ensure the |
| 135 | +shape is "closed" by making the final coordinate exactly the same as the first. |
| 136 | + |
| 137 | +Note that `POLYGON` requires double parentheses around the coordinate list. |
| 138 | +This is because you can specify additional shapes as a comma-separated list |
| 139 | +that define "holes" within the enclosing polygon. The holes must have the opposite |
| 140 | +winding order to the outer polygon (so, if the outer polygon uses a clockwise winding |
| 141 | +order, the holes must use counter-clockwise). |
| 142 | +The `geom` field of the example JSON object shown below specifies a |
| 143 | +square using Cartesian coordinates in a clockwise winding order: |
| 144 | + |
| 145 | +```json |
| 146 | +{ |
| 147 | + "name": "Green Square", |
| 148 | + "geom": "POLYGON ((1 1, 1 3, 3 3, 3 1, 1 1))" |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +The following examples define one `POINT` and three `POLYGON` primitives, |
| 153 | +which are shown in the image below: |
| 154 | + |
| 155 | +``` |
| 156 | +POINT (2 2) |
| 157 | +POLYGON ((1 1, 1 3, 3 3, 3 1, 1 1)) |
| 158 | +POLYGON ((2 2.5, 2 3.5, 3.5 3.5, 3.5 2.5, 2 2.5)) |
| 159 | +POLYGON ((3.5 1, 3.75 2, 4 1, 3.5 1)) |
| 160 | +``` |
| 161 | + |
| 162 | +{{< image filename="/images/dev/rqe/geoshapes.jpg" >}} |
| 163 | + |
| 164 | +You can run various types of queries against a geospatial index. For |
| 165 | +example, the query below returns one primitive that lies within the boundary |
| 166 | +of the green square (from the example above) but omits the square itself: |
| 167 | + |
| 168 | +```bash |
| 169 | +> FT.SEARCH geomidx "(-@name:(Green Square) @geom:[WITHIN $qshape])" PARAMS 2 qshape "POLYGON ((1 1, 1 3, 3 3, 3 1, 1 1))" RETURN 1 name DIALECT 4 |
| 170 | + |
| 171 | +1) (integer) 1 |
| 172 | +2) "shape:4" |
| 173 | +3) 1) "name" |
| 174 | + 2) "[\"Purple Point\"]" |
| 175 | +``` |
| 176 | + |
| 177 | +There are four query operations that you can use with `GEOSHAPE` fields: |
| 178 | + |
| 179 | +- `WITHIN`: Find points or shapes that lie entirely within an |
| 180 | + enclosing shape that you specify in the query. |
| 181 | +- `CONTAINS`: Find shapes that completely contain the specified point |
| 182 | + or shape. |
| 183 | +- `INTERSECTS`: Find shapes whose boundary overlaps another specified |
| 184 | + shape. |
| 185 | +- `DISJOINT`: Find shapes whose boundary does not overlap another specified |
| 186 | + shape. |
| 187 | + |
| 188 | +See |
| 189 | +[Geospatial queries]({{< relref "/develop/interact/search-and-query/query/geo-spatial" >}}) |
| 190 | +for more information about these query types and see |
| 191 | +[Geospatial indexing]({{< relref "/develop/interact/search-and-query/indexing/geoindex" >}}) |
| 192 | +for examples of indexing `GEOSHAPE` fields. |
| 193 | + |
| 194 | +## Limitations of geographical coordinates |
| 195 | + |
| 196 | +Planet Earth is actually shaped more like an |
| 197 | +[ellipsoid](https://en.wikipedia.org/wiki/Earth_ellipsoid) than a perfect sphere. |
| 198 | +The spherical coordinate system used by Redis Query Engine is a close |
| 199 | +approximation to the shape of the Earth but not exact. For most practical |
| 200 | +uses of geospatial queries, the approximation works very well, but you |
| 201 | +shouldn't rely on it if you need very precise location data (for example, to track |
| 202 | +the GPS locations of boats in an emergency response system). |
0 commit comments