Skip to content

SQL: Add initial geo support - 7.x #42135

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

Merged
merged 1 commit into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions docs/reference/sql/functions/geo.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
[role="xpack"]
[testenv="basic"]
[[sql-functions-geo]]
=== Geo Functions

The geo functions work with geometries stored in `geo_point` and `geo_shape` fields, or returned by other geo functions.

==== Limitations

Both <<geo-point, `geo_point`>> and <<geo-shape, `geo_shape`>> types are represented in SQL as geometry and can be used
interchangeably with the following exceptions:

* `geo_shape` fields don't have doc values, therefore these fields cannot be used for filtering, grouping or sorting.

* `geo_points` fields are indexed and have doc values by default, however only latitude and longitude are stored and
indexed with some loss of precision from the original values (4.190951585769653E-8 for the latitude and
8.381903171539307E-8 for longitude). The altitude component is accepted but not stored in doc values nor indexed.
Therefore calling `ST_Z` function in the filtering, grouping or sorting will return `null`.

==== Geometry Conversion

[[sql-functions-geo-st-as-wkt]]
===== `ST_AsWKT`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_AsWKT(geometry<1>)
--------------------------------------------------

*Input*:

<1> geometry

*Output*: string

.Description:

Returns the WKT representation of the `geometry`.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[aswkt]
--------------------------------------------------


[[sql-functions-geo-st-wkt-to-sql]]
===== `ST_WKTToSQL`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_WKTToSQL(string<1>)
--------------------------------------------------

*Input*:

<1> string WKT representation of geometry

*Output*: geometry

.Description:

Returns the geometry from WKT representation.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[aswkt]
--------------------------------------------------

==== Geometry Properties

[[sql-functions-geo-st-geometrytype]]
===== `ST_GeometryType`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_GeometryType(geometry<1>)
--------------------------------------------------

*Input*:

<1> geometry

*Output*: string

.Description:

Returns the type of the `geometry` such as POINT, MULTIPOINT, LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, GEOMETRYCOLLECTION, ENVELOPE or CIRCLE.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[geometrytype]
--------------------------------------------------

[[sql-functions-geo-st-x]]
===== `ST_X`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_X(geometry<1>)
--------------------------------------------------

*Input*:

<1> geometry

*Output*: double

.Description:

Returns the longitude of the first point in the geometry.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[x]
--------------------------------------------------

[[sql-functions-geo-st-y]]
===== `ST_Y`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_Y(geometry<1>)
--------------------------------------------------

*Input*:

<1> geometry

*Output*: double

.Description:

Returns the the latitude of the first point in the geometry.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[y]
--------------------------------------------------

[[sql-functions-geo-st-z]]
===== `ST_Z`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_Z(geometry<1>)
--------------------------------------------------

*Input*:

<1> geometry

*Output*: double

.Description:

Returns the altitude of the first point in the geometry.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[z]
--------------------------------------------------

[[sql-functions-geo-st-distance]]
===== `ST_Distance`

.Synopsis:
[source, sql]
--------------------------------------------------
ST_Distance(geometry<1>, geometry<2>)
--------------------------------------------------

*Input*:

<1> source geometry
<2> target geometry

*Output*: Double

.Description:

Returns the distance between geometries in meters. Both geometries have to be points.

["source","sql",subs="attributes,macros"]
--------------------------------------------------
include-tagged::{sql-specs}/docs/geo.csv-spec[distance]
--------------------------------------------------
9 changes: 9 additions & 0 deletions docs/reference/sql/functions/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@
** <<sql-functions-conditional-least>>
** <<sql-functions-conditional-nullif>>
** <<sql-functions-conditional-nvl>>
* <<sql-functions-geo>>
** <<sql-functions-geo-st-as-wkt>>
** <<sql-functions-geo-st-distance>>
** <<sql-functions-geo-st-geometrytype>>
** <<sql-functions-geo-st-wkt-to-sql>>
** <<sql-functions-geo-st-x>>
** <<sql-functions-geo-st-y>>
** <<sql-functions-geo-st-z>>
* <<sql-functions-system>>
** <<sql-functions-system-database>>
** <<sql-functions-system-user>>
Expand All @@ -149,5 +157,6 @@ include::search.asciidoc[]
include::math.asciidoc[]
include::string.asciidoc[]
include::type-conversion.asciidoc[]
include::geo.asciidoc[]
include::conditional.asciidoc[]
include::system.asciidoc[]
2 changes: 2 additions & 0 deletions docs/reference/sql/language/data-types.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ s|SQL precision
| interval_hour_to_minute | 23
| interval_hour_to_second | 23
| interval_minute_to_second | 23
| geo_point | 52
| geo_shape | 2,147,483,647

|===

Expand Down
11 changes: 11 additions & 0 deletions docs/reference/sql/limitations.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,14 @@ SELECT count(*) FROM test GROUP BY MINUTE((CAST(date_created AS TIME));
-------------------------------------------------------------
SELECT HISTOGRAM(CAST(birth_date AS TIME), INTERVAL '10' MINUTES) as h, COUNT(*) FROM t GROUP BY h
-------------------------------------------------------------

[float]
[[geo-sql-limitations]]
=== Geo-related functions

Since `geo_shape` fields don't have doc values these fields cannot be used for filtering, grouping or sorting.

By default,`geo_points` fields are indexed and have doc values. However only latitude and longitude are stored and
indexed with some loss of precision from the original values (4.190951585769653E-8 for the latitude and
8.381903171539307E-8 for longitude). The altitude component is accepted but not stored in doc values nor indexed.
Therefore calling `ST_Z` function in the filtering, grouping or sorting will return `null`.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@

import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.mapper.BaseGeoShapeFieldMapper;

import java.io.IOException;
import java.io.InputStream;

/**
* first point of entry for a shape parser
Expand Down Expand Up @@ -67,4 +73,20 @@ static ShapeBuilder parse(XContentParser parser, BaseGeoShapeFieldMapper shapeMa
static ShapeBuilder parse(XContentParser parser) throws IOException {
return parse(parser, null);
}

static ShapeBuilder parse(Object value) throws IOException {
XContentBuilder content = JsonXContent.contentBuilder();
content.startObject();
content.field("value", value);
content.endObject();

try (InputStream stream = BytesReference.bytes(content).streamInput();
XContentParser parser = JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, stream)) {
parser.nextToken(); // start object
parser.nextToken(); // field name
parser.nextToken(); // field value
return parse(parser);
}
}
}
1 change: 1 addition & 0 deletions x-pack/plugin/sql/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ext {
// SQL test dependency versions
csvjdbcVersion="1.0.34"
h2Version="1.4.197"
h2gisVersion="1.5.0"
}

configurations {
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugin/sql/jdbc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ dependencies {
compile (project(':libs:x-content')) {
transitive = false
}
compile (project(':libs:elasticsearch-geo')) {
transitive = false
}
compile project(':libs:core')
runtime "com.fasterxml.jackson.core:jackson-core:${versions.jackson}"
testCompile "org.elasticsearch.test:framework:${version}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public enum EsType implements SQLType {
INTERVAL_DAY_TO_SECOND( ExtraTypes.INTERVAL_DAY_SECOND),
INTERVAL_HOUR_TO_MINUTE( ExtraTypes.INTERVAL_HOUR_MINUTE),
INTERVAL_HOUR_TO_SECOND( ExtraTypes.INTERVAL_HOUR_SECOND),
INTERVAL_MINUTE_TO_SECOND(ExtraTypes.INTERVAL_MINUTE_SECOND);
INTERVAL_MINUTE_TO_SECOND(ExtraTypes.INTERVAL_MINUTE_SECOND),
GEO_POINT( ExtraTypes.GEOMETRY),
GEO_SHAPE( ExtraTypes.GEOMETRY);

private final Integer type;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ private ExtraTypes() {}
static final int INTERVAL_HOUR_MINUTE = 111;
static final int INTERVAL_HOUR_SECOND = 112;
static final int INTERVAL_MINUTE_SECOND = 113;
static final int GEOMETRY = 114;

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.sql.jdbc;

import java.util.Objects;
Expand Down Expand Up @@ -89,4 +90,4 @@ public boolean equals(Object obj) {
public int hashCode() {
return Objects.hash(name, type, table, catalog, schema, label, displaySize);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
/ Additional properties can be specified either through the Properties object or in the URL. In case of duplicates, the URL wins.
*/
//TODO: beef this up for Security/SSL
class JdbcConfiguration extends ConnectionConfiguration {
public class JdbcConfiguration extends ConnectionConfiguration {
static final String URL_PREFIX = "jdbc:es://";
public static URI DEFAULT_URI = URI.create("http://localhost:9200/");

Expand All @@ -47,7 +47,7 @@ class JdbcConfiguration extends ConnectionConfiguration {
// can be out/err/url
static final String DEBUG_OUTPUT_DEFAULT = "err";

static final String TIME_ZONE = "timezone";
public static final String TIME_ZONE = "timezone";
// follow the JDBC spec and use the JVM default...
// to avoid inconsistency, the default is picked up once at startup and reused across connections
// to cater to the principle of least surprise
Expand Down
Loading