-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support GEOSHAPE field type in RediSearch (#3561)
* Support GEOSHAPE field type in RediSearch * dependency: GeoShape query is limited to PARAM argument only. So I couldn't implement helper functions in query builders. Because of that the dependency library is not required. * example * more comments * format * Address code review
- Loading branch information
Showing
6 changed files
with
281 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/main/java/redis/clients/jedis/search/schemafields/GeoShapeField.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package redis.clients.jedis.search.schemafields; | ||
|
||
import static redis.clients.jedis.search.SearchProtocol.SearchKeyword.GEOSHAPE; | ||
|
||
import redis.clients.jedis.CommandArguments; | ||
import redis.clients.jedis.search.FieldName; | ||
|
||
public class GeoShapeField extends SchemaField { | ||
|
||
public enum CoordinateSystem { | ||
|
||
/** | ||
* For cartesian (X,Y). | ||
*/ | ||
FLAT, | ||
|
||
/** | ||
* For geographic (lon, lat). | ||
*/ | ||
SPHERICAL | ||
} | ||
|
||
private final CoordinateSystem system; | ||
|
||
public GeoShapeField(String fieldName, CoordinateSystem system) { | ||
super(fieldName); | ||
this.system = system; | ||
} | ||
|
||
public GeoShapeField(FieldName fieldName, CoordinateSystem system) { | ||
super(fieldName); | ||
this.system = system; | ||
} | ||
|
||
public static GeoShapeField of(String fieldName, CoordinateSystem system) { | ||
return new GeoShapeField(fieldName, system); | ||
} | ||
|
||
@Override | ||
public GeoShapeField as(String attribute) { | ||
super.as(attribute); | ||
return this; | ||
} | ||
|
||
@Override | ||
public void addParams(CommandArguments args) { | ||
args.addParams(fieldName).add(GEOSHAPE).add(system); | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
src/test/java/redis/clients/jedis/examples/GeoShapeFieldsUsageInRediSearch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package redis.clients.jedis.examples; | ||
|
||
import org.locationtech.jts.geom.Coordinate; | ||
import org.locationtech.jts.geom.Geometry; | ||
import org.locationtech.jts.geom.GeometryFactory; | ||
import org.locationtech.jts.geom.Polygon; | ||
import org.locationtech.jts.io.ParseException; | ||
import org.locationtech.jts.io.WKTReader; | ||
|
||
import redis.clients.jedis.HostAndPort; | ||
import redis.clients.jedis.JedisPooled; | ||
import redis.clients.jedis.UnifiedJedis; | ||
import redis.clients.jedis.search.FTSearchParams; | ||
import redis.clients.jedis.search.SearchResult; | ||
import redis.clients.jedis.search.schemafields.GeoShapeField; | ||
|
||
import static java.util.Collections.singletonMap; | ||
import static org.junit.Assert.assertEquals; | ||
import static redis.clients.jedis.search.RediSearchUtil.toStringMap; | ||
|
||
/** | ||
* As of RediSearch 2.8.4, advanced GEO querying with GEOSHAPE fields is supported. | ||
* | ||
* Any object/library producing a | ||
* <a href="https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry"> well-known | ||
* text (WKT)</a> in {@code toString()} method can be used. | ||
* | ||
* This example uses the <a href="https://github.com/locationtech/jts">JTS</a> library. | ||
* <pre> | ||
* {@code | ||
* <dependency> | ||
* <groupId>org.locationtech.jts</groupId> | ||
* <artifactId>jts-core</artifactId> | ||
* <version>1.19.0</version> | ||
* </dependency> | ||
* } | ||
* </pre> | ||
*/ | ||
public class GeoShapeFieldsUsageInRediSearch { | ||
|
||
public static void main(String[] args) { | ||
|
||
// We'll create geometry objects with GeometryFactory | ||
final GeometryFactory factory = new GeometryFactory(); | ||
|
||
final String host = "localhost"; | ||
final int port = 6379; | ||
final HostAndPort address = new HostAndPort(host, port); | ||
|
||
UnifiedJedis client = new JedisPooled(address); | ||
// client.setDefaultSearchDialect(3); // we can set default search dialect for the client (UnifiedJedis) object | ||
// to avoid setting dialect in every query. | ||
|
||
// creating index | ||
client.ftCreate("geometry-index", | ||
GeoShapeField.of("geometry", GeoShapeField.CoordinateSystem.SPHERICAL) // 'SPHERICAL' is for geographic (lon, lat). | ||
// 'FLAT' coordinate system also available for cartesian (X,Y). | ||
); | ||
|
||
// preparing data | ||
final Polygon small = factory.createPolygon( | ||
new Coordinate[]{new Coordinate(34.9001, 29.7001), | ||
new Coordinate(34.9001, 29.7100), new Coordinate(34.9100, 29.7100), | ||
new Coordinate(34.9100, 29.7001), new Coordinate(34.9001, 29.7001)} | ||
); | ||
|
||
client.hset("small", toStringMap(singletonMap("geometry", small))); // setting data | ||
|
||
final Polygon large = factory.createPolygon( | ||
new Coordinate[]{new Coordinate(34.9001, 29.7001), | ||
new Coordinate(34.9001, 29.7200), new Coordinate(34.9200, 29.7200), | ||
new Coordinate(34.9200, 29.7001), new Coordinate(34.9001, 29.7001)} | ||
); | ||
|
||
client.hset("large", toStringMap(singletonMap("geometry", large))); // setting data | ||
|
||
// searching | ||
final Polygon within = factory.createPolygon( | ||
new Coordinate[]{new Coordinate(34.9000, 29.7000), | ||
new Coordinate(34.9000, 29.7150), new Coordinate(34.9150, 29.7150), | ||
new Coordinate(34.9150, 29.7000), new Coordinate(34.9000, 29.7000)} | ||
); | ||
|
||
SearchResult res = client.ftSearch("geometry-index", | ||
"@geometry:[within $poly]", // querying 'within' condition. | ||
// RediSearch also supports 'contains' condition. | ||
FTSearchParams.searchParams() | ||
.addParam("poly", within) | ||
.dialect(3) // DIALECT '3' is required for this query | ||
); | ||
assertEquals(1, res.getTotalResults()); | ||
assertEquals(1, res.getDocuments().size()); | ||
|
||
// We can parse geometry objects with WKTReader | ||
try { | ||
final WKTReader reader = new WKTReader(); | ||
Geometry object = reader.read(res.getDocuments().get(0).getString("geometry")); | ||
assertEquals(small, object); | ||
} catch (ParseException ex) { | ||
ex.printStackTrace(System.err); | ||
} | ||
} | ||
|
||
// Note: As of RediSearch 2.8.4, only POLYGON and POINT objects are supported. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters