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
[sensorthings] Support feature expansion #56960
Conversation
@nyalldawson A documentation ticket will be opened at https://github.com/qgis/QGIS-Documentation when this PR is merged. Please update the description (not the comments) with helpful description and screenshot to help the work from documentors. Thank you! |
This pull request has been tagged for the changelog.
You can edit the description. Format available for credits
Thank you! |
(not for merge at this stage -- after discussion with @rduivenvoorde we need a sort order option to accompany this) |
@nyalldawson, not so much viewing from my use-cases, but more with QGIS/GIS in mind: should the 'Expand to' rules not mostly (try to) expand to objects in which every object will get a 'geometry'? Instead of, for example: Observations only be available now with 'No Geometry'? I have to try to craft some of the 'queries' first, but I reckoned that the ideal situation would be some query/question like: Get me all (recent x) Observations (from a given Datastream) in this extent and show them on my MapCanvas (and I can use Temporal Controller to filter/view them)? This would mean that this (Datastream)-Observations should at least contain the expansion till the Location of their Thing? So the Geometry type would be Point then? I think(!) the responsibility to, for example, request all Datastreams ( to be able to show all Observations of a Quantity and Unit (ObservedProperty) of interest ), will probably be in a plugin (using core func)? So the plugin can then request all Observations from selected Datastreams (using core func). From https://github.com/FraunhoferIOSB/FROST-Server/wiki/Example-queries,
This probably should also be possible 'the other way around', so request Observations (of a certain Datastream (== type)) and expand Thing/Location so every Observation has a geometry? OR am I going over the top anyway? Because this makes the queries (and handling of the results) too complex? But then would be my question: do we have bindings (for plugin authors) to craft such queries (and retrieve/parse the data theirselves? |
Another example All Datastreams (in given bbox, though not sure if st_contains is still in v1.1...), then expand the Thing/Location to be able to show them on a map |
Ok I've reworked this to allow for more flexible configuration of expansion targets no. Instead of the previous combobox and limit widget, there's now button to open a dialog to configure expansions: Clicking this shows a dialog allowing users to control exactly how expansions should be made, including per-expansion limits and ordering settings: (potentially this could be expanded in future to also expose per expansion query filters!) This should address the "find me just the most recent observation for each location" type use case (ie that's what the configuration above would do) |
My thinking is that the user must always select the entity with the geometry as the base entity type. So eg if they want observations, the base entity type is Location and then they expand through Things, DataStreams, to Observations. |
@nyalldawson Question: can you maybe give some hints on how to use the provider to fetch data (as that is how Luca et al. will be going to use it in the plugin(s))? @ghtmtt I've build and did some test: -1- Observation, expanding to Datastream: Then there seems to be 'Observations'-table in the layer manager, but if you open the table (to fetch data), you see this query: While (trial and error) what works is (note the 'Datastream' instead of 'DatastreamS': -2- Another test, Thing expanding to Datastream just works (!): Probably because one Thing can have several datastreams, but one Observation has always one datastream (looking at the diagram, I also read datastream vs datastreams) -3-
Is fine, a difficulty here (@hylkevds mentioned this in the chat during the meeting), is that you will get All datastreams of all Things at that moment, and thus a mixed set of Observations (as in different units/quantities/params). Which could be fine! Or (and this was mentioned by Luca ( no githandle available :-) ), we probably want do some more filtering (adding the filter clause into the queries to filter on 'properties' or :
Example of all Things with SO2 sensor datastreams and the latest Observation: The crux is to create such (to me pretty complex) 'queries' in such a way that the result is a 'feature' with some geometry and value to chow in the maps Another crafted example (just to get the Locations to be the root item). All locations expanding the Datastreams (selecting only the SO2 streams) via Things, and then showing the most recent Observation: Trying to minimize output: -4- another observation: it is not so easy to clean the 'expand' path in the dialog? Changing Object does not clean the (then invalid) path. Sometimes it is cleaned (seemingly random?). |
Do you mean from a raw api point of view? If so, then I'd suggest either adding layers from data source manager and viewing the resultant layer source, OR checking out how we construct layer source URIs from the unit tests here: https://github.com/qgis/QGIS/blob/master/tests/src/python/test_provider_sensorthings.py#L3675
Wow, I do NOT like this part of the SensorThings specification! It turns out the the url query required for expansions depends on the actual relationship type between each expansion and its parent. This isn't nice at all for clients, and results in a lot more complex code 😭 . Anyway, I've addressed this in the latest commit.
While we create the correct query string for this one now, it kills the frost server 🙃 The query we now send is of the form: Which just endlessly hangs until the request times out. I doubt there's anything we can do from QGIS' side to handle this.
I'm going to have to defer to @ghtmtt here -- my understanding is that this is considered out of scope for the current project and needs to wait till a further round of funding.
Try the latest version, I've added some tweaks |
The name of the relation has no technical relation to the name of the entity type on the other side of that relation in OData, so that name is based on the semantics of the relation. An Observation has one (1) Datastream, so the name of the relation is Two EntityTypes can even have multiple relations, which will happen in the Sampling extension in STA v2 between Sampling and Feature. Better get it correct now, or there will be a serious issue when V2 comes along :)
Missing index :) |
@ghtmtt we really have to discus use-cases here, because in current setup it is (I think) too easy to fire "meaningless queries' as @hylkevds says. Some quick ideas/use-cases:
I'm aware these are all specific use-cases, but I think we should take this kind of use cases into mind when developing this provider. |
I think a good practical solution to that would be if we added "preset" configurations which prepopulate all the layer settings (including expansions). Users could pick from these, or use them as starting points for configuration, or just configure from scratch themselves if no presets match their needs. I'm shortly heading away for a week and a bit, so I'll catch up on this discussion when I'm back online! |
Two more use cases:
|
Dear all, here I am to join this very interesting discussion...which, in my opinion, is also quite pivotal to design a usable solution (both for data provider and for the data analysis plugin). I think we are facing 2 main issues:
I thought about and drafted (on paper!) some ideas (and mock-ups too :) ) on how to tackle those issues and I will post them here as soon as I manage to transcribe them. I have my two young kids home from school for Easter and I can't manage right now ...but I will manage at most by early next week. I trust and I hope you'll be on some king of Easter holiday too! :) |
Done! Sent by email! |
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
While we hate to see this happen, this PR has been automatically closed because it has not had any activity in the last 21 days. If this pull request should be reconsidered, please follow the guidelines in the previous comment and reopen this pull request. Or, if you have any further questions, just ask! We love to help, and if there's anything the QGIS project can do to help push this PR forward please let us know how we can assist. |
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
This change allows SensorThings entities to be expanded to contain their related child feature attributes, exposing the relational SensorThings model as a traditional "flat" GIS-friendly table structure. Eg when selecting Location entities, you can now opt to expand to "Things > Datastreams > Observations". This would result in multiple "stacked" point location features, one corresponding to each observation, with the attributes for each point feature containing the location, thing, datastream and observation attributes. (Best used combined with some extent, feature limit, or custom filter option, as this can otherwise result in very heavy requests to the backend service!) Fixes qgis#56805
This helps reduce the load on backend servers, as feature expansion can quickly balloon out to a huge number of features. Default to a very conservative expansion limit, requiring users to "opt in" to larger limits which may be inappropriate for a service.
This allows us to control the sort order and limit for each expansion, and gives us more flexibility in future to eg handle per expansion filter strings
Allows for users to configure per expansion limit and sort ordering
Merging after extensive user testing. Follow ups will come in separate prs |
@nyalldawson |
This change allows SensorThings entities to be expanded to contain their related child feature attributes, exposing the relational SensorThings model as a traditional "flat" GIS-friendly table structure.
Eg when selecting Location entities, you can now opt to expand to "Things > Datastreams > Observations". This would result in multiple "stacked" point location features, one corresponding to each observation, with the attributes for each point feature containing the location, thing, datastream and observation attributes.
Best used combined with some extent, feature limit, or custom filter option, as this can otherwise result in very heavy
requests to the backend service! There's also an option to limit then number of child features returned when expanding, and we default to a very conservative amount here in order to reduce load on services. (I.e. users need to explicitly "opt in" to fetch large amounts of features)
Here's an example of a feature returned when the expansion option out to "Location > Thing > Datastream" is used. Note how the "Thing" and "Thing_Datastream" attributes are appended on to the base "Location" attributes:
Fixes #56805