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

Add support for Geo-spatial queries #1403

Merged
merged 17 commits into from
Jul 21, 2023
Merged

Add support for Geo-spatial queries #1403

merged 17 commits into from
Jul 21, 2023

Conversation

cmelchior
Copy link
Contributor

@cmelchior cmelchior commented May 31, 2023

This PR is adding support for Geo-spatial queries. Core doesn't have a specific geo-type (yet), so this is just the first version which relies on duck-typing.

This means that geo queries can be used on any embedded objects that has a type and coordinates property.

This also has the implication that it is slightly awkward to to pass in geo-parameters. The current implementation overrides the toString() method which will format the data structures so they can be used from within a query.

TODO

  • Documentation
  • Figure out how many tests we need?
  • There is a chance that Core allow String arguments to be converted to geo-spatial arguments. Check with them about this.

Christian Melchior added 5 commits June 23, 2023 09:43
# Conflicts:
#	packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
@cmelchior cmelchior marked this pull request as ready for review June 27, 2023 13:48
* This class represents an equatorial distance that can be used in geospatial queries like those
* represented by a [GeoCircle].
*/
public data class Distance private constructor(
Copy link
Contributor

Choose a reason for hiding this comment

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

This distance is the distance on the surface of the earth, isn't it? Could we use a different name like EarthSurfaceDistance or GeoDistance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is the distance on the earth. I guess we could have also gone with GeoDistance, but Distance was the name used in the technical scope: https://docs.google.com/document/d/1Z7CK79CqebEtVllVHTNEq8neKhoMWeFCDjKBrn_pq1Y/ and I don't think that is particular confusing? And it is shorter than GeoDistance.

Copy link
Contributor

Choose a reason for hiding this comment

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

It confuses me because it mixed linear and angular distances.

We implicitly use the earth's radius to correlate between them, but we are not explicitly stating in the documentation that we are using it. Instead, we could be explicit:

val distance: Distance = 1.2.earthRadians
val distance: Distance = 1.2.earthDegrees
val distance: Distance = 10.4.km
val distance: Distance = 10.5.miles

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I'm missing something obvious here, but how could radians be interpreted in any other way than Earth radians? Like what can it potentially be confused with?

Copy link
Contributor

@rorbech rorbech Jun 28, 2023

Choose a reason for hiding this comment

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

I also had the same feeling like Clemente. It isn't at all obvious that radians are "earth radians" as a distance (if such a term even exists!). But once you start interpreting this as "equatorial distance in radians" it starts to be ok to work with. I think it is just something people will need to grasp and then it is ok. I tried to suggest updates to some docs by adding explicit "equatorial distance" here and there to speed up the "learning curve" to make it more clear. Anyway the km should make it possible to work with it without bothering with the internals.

Copy link
Contributor

Choose a reason for hiding this comment

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

The whole Geo-Spatial solution is generic, it can work on any sphere. It is this Distance implementation that tights it to the Earth.

The thing is that this solution works for other spheres too, planets or simulations. If these KM/Miles are used on a different sphere than the earth it would not be correct. Adding a comment about it would be fine.

Here I tried to convert values Distance as a linear distance, that's why I wrote "earthRadians" (radians*earth radius = linear distance ). But we actually require angular distance so forget about it.

Co-authored-by: Claus Rørbech <claus.rorbech@mongodb.com>
* This class represents an equatorial distance that can be used in geospatial queries like those
* represented by a [GeoCircle].
*/
public data class Distance private constructor(
Copy link
Contributor

Choose a reason for hiding this comment

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

It confuses me because it mixed linear and angular distances.

We implicitly use the earth's radius to correlate between them, but we are not explicitly stating in the documentation that we are using it. Instead, we could be explicit:

val distance: Distance = 1.2.earthRadians
val distance: Distance = 1.2.earthDegrees
val distance: Distance = 10.4.km
val distance: Distance = 10.5.miles

@cmelchior
Copy link
Contributor Author

I reworked the API based on our discussions. It should be ready for another round of review.

Copy link
Contributor

@rorbech rorbech left a comment

Choose a reason for hiding this comment

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

Cool. Only some minor comments here and there.

* @throws IllegalArgumentException if the input polygon break some of the rules outlined
* above.
*/
public fun create(outerRing: List<GeoPoint>, holes: List<List<GeoPoint>>): GeoPolygon {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to be able to GeoBox, GeoPolygon and GeoCircles as holes? ... But I guess we can always add a subtype to the regional types and an overload method, so nothing for this PR.

public companion object {

private const val DEGREE_TO_RADIAN: Double = PI / 180.0
private const val RADIAN_TO_DEGREE: Double = 180.0 / PI
Copy link
Contributor

Choose a reason for hiding this comment

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

Feels a bit funny to define both just to be able use multiplication in both conversion. Maybe only define one and then divide in one of the ways.

if (outerRing.size < MIN_RING_SIZE) {
throw IllegalArgumentException("The outer ring requires at least $MIN_RING_SIZE points: ${outerRing.size}")
}
if (outerRing.first() != outerRing.last()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm. Maybe I was not right in suggesting this check. I am a bit confused, though, so don't know what is up and down 🙃. Seems like the general GeoPolygon class documentation state that there must be four https://github.com/realm/realm-kotlin/pull/1403/files#diff-bb869c11647feb614648b9cdafb62fb3aa3b95c2b18f6d81f3cd714f90cce286R29-R31, but then it is also mentioned that the first and last point is implicitly connected in https://github.com/realm/realm-kotlin/pull/1403/files#diff-bb869c11647feb614648b9cdafb62fb3aa3b95c2b18f6d81f3cd714f90cce286R102-R103. The reason why I suggested the check was just to catch errors before performing the actual queries, but if there is an option to leave out the duplicate first/last point and consider it being implicit I would vote for allowing that.

Copy link
Contributor

Choose a reason for hiding this comment

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

This check is totally valid as it is required that the first and last points to be the same, otherwise core would throw an exception.

* The recommended approach is encapsulating this inside its own [EmbeddedRealmObject], like this
*
* ```
* public class Location: EmbeddedRealmObject {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not provide the implementation for this type? We have types for querying but not for persistence. Also, this type could implement GeoPoint for better integration with the Geo APIs.

It is some temporal code, but having to copy/paste this code makes it hard to discover, and leaves us with no control over it, we cannot deprecate it, or notify the users to move to another "final" type.

Copy link
Member

Choose a reason for hiding this comment

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

This is because we can't force the type name from the client. E.g. if the server json schema defines the location type as Person_Address_Location (i.e. automatically generated name for an unnamed embedded object), we will end up with schema mismatch if the user attempts to use the SDK-specified Location. This is covered in the "Design Alternnatives" section of the Design doc.

In phase 2 we will have a dedicated type both on the client and the server, but this work was deemed quite involved and we didn't want to delay phase 1 because of it.

@clementetb clementetb merged commit 1821ecc into main Jul 21, 2023
1 check passed
@clementetb clementetb deleted the cm/geo-support branch July 21, 2023 11:08
cbullinger added a commit to mongodb/docs-realm that referenced this pull request Sep 6, 2023
## Pull Request Info

- Document geospatial queries:
realm/realm-kotlin#1403

- Update to v1.11.0

> NOTE: API ref links won't work until v1.11.0 refs are published

### Jira

- https://jira.mongodb.org/browse/DOCSP-30997

### Staged Changes

- [Geospatial Data - Kotlin
SDK](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30997-geospatial/sdk/kotlin/realm-database/schemas/data-types/geospatials/)
- new page

### Reminder Checklist

If your PR modifies the docs, you might need to also update some
corresponding
pages. Check if completed or N/A.

- [x] Create Jira ticket for corresponding docs-app-services update(s),
if any
- [x] Checked/updated Admin API
- [x] Checked/updated CLI reference

### Review Guidelines


[REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md)
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants