From 8d092c0722fea2f7208b48362d0dcf9801059313 Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Wed, 23 Nov 2022 19:41:36 +0100 Subject: [PATCH 01/13] update to master maven version to 1.9.0-SNAPSHOT (#285) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- CHANGELOG.md | 3 +++ pom.xml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f8d7b820..74b52be7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,7 +12,7 @@ A clear and concise description of what the bug is. ### General Information Please include the following general information about the issue and list any additional steps needed to reproduce the bug. - - Version of the ohsome API [e.g. `1.5.0`] + - Version of the ohsome API [e.g. `1.8.0`] - Which API instance was requested [e.g. remote instance at `https://api.ohsome.org/v1`, local instance with an h2 file or connected to the cluster, etc.] - Affected endpoint(s) [e.g. /contributions/count] - URL of your request (and request body if applicable) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c38c175..3b519a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Changelog ========= +## 1.9.0-SNAPSHOT (current master) + + ## 1.8.0 ### Breaking Changes diff --git a/pom.xml b/pom.xml index 7015f581..9dae5a16 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ https://api.ohsome.org A public Web-RESTful-API for "ohsome" OpenStreetMap history data. jar - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT scm:git:git@github.com:GIScience/ohsome-api.git From 5f3feb0c6c1824c368e3a47632f6a1f3c5e5d6f5 Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Thu, 1 Dec 2022 09:35:08 +0100 Subject: [PATCH 02/13] fix typo in docs (#287) --- docs/endpoints.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/endpoints.rst b/docs/endpoints.rst index ff49cccc..8fb10f40 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -1244,7 +1244,7 @@ Number of the latest contributions to residential buildings with a geometry chan .. code-tab:: bash curl (POST) - curl -X POST 'https://api.ohsome.org/v1/contributions/latest/count' --data-urlencode 'bboxes=8.69282,49.40766,8.71673,49.4133' --data-urlenconde 'contributionType=geometryChange' --data-urlencode 'filter=building=residential' --data-urlencode 'time=2014-01-01,2015-01-01' + curl -X POST 'https://api.ohsome.org/v1/contributions/latest/count' --data-urlencode 'bboxes=8.69282,49.40766,8.71673,49.4133' --data-urlencode 'contributionType=geometryChange' --data-urlencode 'filter=building=residential' --data-urlencode 'time=2014-01-01,2015-01-01' .. code-tab:: python Python From 022a31b67f50134cea144ed63847907f7dfc8f6e Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Wed, 4 Jan 2023 15:00:34 +0100 Subject: [PATCH 03/13] Docs: change formatting of filter tables --- docs/filter.rst | 193 ++++++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 97 deletions(-) diff --git a/docs/filter.rst b/docs/filter.rst index d08f4afb..7cc754c1 100644 --- a/docs/filter.rst +++ b/docs/filter.rst @@ -19,65 +19,64 @@ Selectors +-------------------------+------------------------------------+------------------------+ | | **description** | **example** | +=========================+====================================+========================+ - | ``key=value`` | | matches all entities which | ``natural=tree`` | - | | | have this exact tag | | + | ``key=value`` | matches all entities which | ``natural=tree`` | + | | have this exact tag | | +-------------------------+------------------------------------+------------------------+ - | ``key=*`` | | matches all entities which have | ``addr:housenumber=*`` | - | | | any tag with the given key | | + | ``key=*`` | matches all entities which have | ``addr:housenumber=*`` | + | | any tag with the given key | | +-------------------------+------------------------------------+------------------------+ - | ``key!=value`` | | matches all entities | ``oneway!=yes`` | - | | | which do not have | | - | | | this exact tag | | + | ``key!=value`` | matches all entities | ``oneway!=yes`` | + | | which do not have | | + | | this exact tag | | +-------------------------+------------------------------------+------------------------+ - | ``key!=*`` | | matches all entities which do not| ``name!=*`` | - | | | have any tag with the given key | | - | | | | | + | ``key!=*`` | matches all entities which do not | ``name!=*`` | + | | have any tag with the given key | | +-------------------------+------------------------------------+------------------------+ - | ``key in (value list)`` | | matches all entities which do | ``highway in | - | | | have any tag with the given key | (residential, | - | | | and one of the given values | living_street)`` | + | ``key in (value list)`` | matches all entities which do | ``highway in`` | + | | have any tag with the given key | ``(residential, | + | | and one of the given values | living_street)`` | +-------------------------+------------------------------------+------------------------+ - | ``type:osm-type`` | | matches all entities of the | ``type:node`` | - | | | given osm type | | + | ``type:osm-type`` | matches all entities of the | ``type:node`` | + | | given osm type | | +-------------------------+------------------------------------+------------------------+ - | ``id:osm-id`` | | matches all entities with the | ``id:1234`` | - | | | given osm id [1]_ | | + | ``id:osm-id`` | matches all entities with the | ``id:1234`` | + | | given osm id [1]_ | | +-------------------------+------------------------------------+------------------------+ - | ``id:osm-type/osm-id`` | | matches the entity with the given| ``id:node/1234`` | - | | | osm type and id | | + | ``id:osm-type/osm-id`` | matches the entity with the given | ``id:node/1234`` | + | | osm type and id | | +-------------------------+------------------------------------+------------------------+ - | ``id:(id list)`` | | matches all entities with the | ``id:(1, 42, 1234)`` | - | | | given osm ids [1]_ | | + | ``id:(id list)`` | matches all entities with the | ``id:(1, 42, 1234)`` | + | | given osm ids [1]_ | | +-------------------------+------------------------------------+------------------------+ - | ``id:(id list)`` | | matches all entities with the | ``id:(node/1, way/3)`` | - | | | given osm types and ids | | + | ``id:(id list)`` | matches all entities with the | ``id:(node/1, way/3)`` | + | | given osm types and ids | | +-------------------------+------------------------------------+------------------------+ - | ``id:(id range)`` | | matches all entities with an id | ``id:(1 .. 9999)`` | - | | | matching the given id range [2]_ | | + | ``id:(id range)`` | matches all entities with an id | ``id:(1 .. 9999)`` | + | | matching the given id range [2]_ | | +-------------------------+------------------------------------+------------------------+ - | ``geometry:geom-type`` | | matches anything which has a | ``geometry:polygon`` | - | | | geometry of the given type | | - | | | (point, line, polygon, or other) | | + | ``geometry:geom-type`` | matches anything which has a | ``geometry:polygon`` | + | | geometry of the given type | | + | | (point, line, polygon, or other) | | +-------------------------+------------------------------------+------------------------+ - | ``area:(from..to)`` | | matches features with a geometry | ``area:(1.0 .. 1E6)`` | - | | | having an area (measured in m²) | | - | | | in the given range [2]_ | | + | ``area:(from..to)`` | matches features with a geometry | ``area:(1.0 .. 1E6)`` | + | | having an area (measured in m²) | | + | | in the given range [2]_ | | +-------------------------+------------------------------------+------------------------+ - | ``length:(from..to)`` | | matches features with a geometry | ``length:( .. 100)`` | - | | | having a length (measured in m) | | - | | | in the given range [2]_ | | + | ``length:(from..to)`` | matches features with a geometry | ``length:( .. 100)`` | + | | having a length (measured in m) | | + | | in the given range [2]_ | | +-------------------------+------------------------------------+------------------------+ - | ``changeset:id`` | | matches contributions [3]_ | ``changeset:42`` | - | | | performed in the specified | | - | | | changeset | | + | ``changeset:id`` | matches contributions [3]_ | ``changeset:42`` | + | | performed in the specified | | + | | changeset | | +-------------------------+------------------------------------+------------------------+ - | ``changeset:(id list)`` | | matches contributions [3]_ | ``changeset:(10, 42)`` | - | | | performed in one of the | | - | | | specified changesets | | + | ``changeset:(id list)`` | matches contributions [3]_ | ``changeset:(10, 42)`` | + | | performed in one of the | | + | | specified changesets | | +-------------------------+------------------------------------+------------------------+ - | ``changeset:(from..to)``| | matches contributions [3]_ | ``changeset:(10..42)`` | - | | | performed in a range of | | - | | | changesets | | + | ``changeset:(from..to)``| matches contributions [3]_ | ``changeset:(10..42)`` | + | | performed in a range of | | + | | changesets | | +-------------------------+------------------------------------+------------------------+ .. [1] Keep in mind that osm ids are not unique between osm types. In order to include only a specific object the id needs to be used together with an osm type filter. Alternatively, one can also use the combined type+id filter (e.g. `id:node/1234`). .. [2] The lower or upper bound of a range may be omitted to indicate that the values are only to be limited to be "up to" or "starting from" the given value, respectively. For example: `id:(10..)` will accept all entities with an id of 10 or higher. @@ -94,18 +93,18 @@ Operators +------------------------+------------------------------------+------------------------+ | | **description** | **example** | +========================+====================================+========================+ - | ``(…)`` | | can be used to change | ``highway=primary and | - | | | precedence of operators | (name=* or ref=*)`` | + | ``(…)`` | can be used to change | ``highway=primary and | + | | precedence of operators | (name=* or ref=*)`` | +------------------------+------------------------------------+------------------------+ - | ``not X`` | | negates the following filter | ``not type:node`` | - | | | expression | | + | ``not X`` | negates the following filter | ``not type:node`` | + | | expression | | +------------------------+------------------------------------+------------------------+ - | ``X and Y`` | | returns entities which match | ``highway=service and | - | | | both filter expressions X and Y | service=driveway`` | + | ``X and Y`` | returns entities which match | ``highway=service and | + | | both filter expressions X and Y | service=driveway`` | +------------------------+------------------------------------+------------------------+ - | ``X or Y`` | | returns entities which match at | ``natural=wood or | - | | | least one of the filter | landuse=forest`` | - | | | expressions X or Y | | + | ``X or Y`` | returns entities which match at | ``natural=wood or | + | | least one of the filter | landuse=forest`` | + | | expressions X or Y | | +------------------------+------------------------------------+------------------------+ Operators follow the following order of precedence: parentheses before ``not``, before ``and``, before ``or``. @@ -139,56 +138,56 @@ Here's some useful examples for querying some OSM features: +------------------+--------------------------------------------------------+------------------------------+ | **OSM Feature** | **filter** | **comment** | +==================+========================================================+==============================+ - | | forests/woods | | ``(landuse=forest or natural=wood) and`` | | Using | - | | | ``geometry:polygon`` | | ``geometry:polygon`` will | - | | | | select closed ways as | - | | | | well as multipolygons | - | | | | (e.g. a forest with | - | | | | clearings). | + | forests/woods | | ``(landuse=forest or natural=wood) and`` | Using | + | | | ``geometry:polygon`` | ``geometry:polygon`` will | + | | | select closed ways as | + | | | well as multipolygons | + | | | (e.g. a forest with | + | | | clearings). | +------------------+--------------------------------------------------------+------------------------------+ - | | parks and | | ``leisure=park and geometry:polygon or`` | | A filter can also fetch | - | | park benches | | ``amenity=bench and (geometry:point or`` | | features of different | - | | | ``geometry:line)`` | | geometry types: this | - | | | | returns parks | - | | | | (polygons) as well as | - | | | | park benches (points or | - | | | | lines). | + | parks and | | ``leisure=park and geometry:polygon or`` | A filter can also fetch | + | park benches | | ``amenity=bench and (geometry:point or`` | features of different | + | | | ``geometry:line)`` | geometry types: this | + | | | returns parks | + | | | (polygons) as well as | + | | | park benches (points or | + | | | lines). | +------------------+--------------------------------------------------------+------------------------------+ - | | buildings | | ``building=* and building!=no and`` | | This filter also | - | | | ``geometry:polygon`` | | excludes the (rare) | - | | | | objects marked with | - | | | | ``building=no``, which is | - | | | | a tag used to indicate | - | | | | that a feature might be | - | | | | expected to be a | - | | | | building (e.g. from an | - | | | | outdated aerial imagery | - | | | | source), but is in reality | - | | | | not one. | + | buildings | | ``building=* and building!=no and`` | This filter also | + | | | ``geometry:polygon`` | excludes the (rare) | + | | | objects marked with | + | | | ``building=no``, which is | + | | | a tag used to indicate | + | | | that a feature might be | + | | | expected to be a | + | | | building (e.g. from an | + | | | outdated aerial imagery | + | | | source), but is in reality | + | | | not one. | +------------------+--------------------------------------------------------+------------------------------+ - | | highways | | ``type:way and (highway in (motorway,`` | | The list of used tags | - | | | ``motorway_link, trunk, trunk_link, primary,`` | | depends on the exact | - | | | ``primary_link, secondary, secondary_link,`` | | definition of a | - | | | ``tertiary, tertiary_link, unclassified,`` | | "highway". In a | - | | | ``residential, living_street, pedestrian) or`` | | different context, it may | - | | | ``(highway=service and service=alley))`` | | also include less or even | - | | | | more tags | - | | | | (``footway``, ``cycleway``,| - | | | | ``track``, ``path``, all | - | | | | ``highway=service``, etc.) | + | highways | | ``type:way and (highway in (motorway,`` | The list of used tags | + | | | ``motorway_link, trunk, trunk_link, primary,`` | depends on the exact | + | | | ``primary_link, secondary, secondary_link,`` | definition of a | + | | | ``tertiary, tertiary_link, unclassified,`` | "highway". In a | + | | | ``residential, living_street, pedestrian) or`` | different context, it may | + | | | ``(highway=service and service=alley))`` | also include less or even | + | | | more tags | + | | | (``footway``, ``cycleway``, | + | | | ``track``, ``path``, all | + | | | ``highway=service``, etc.) | +------------------+--------------------------------------------------------+------------------------------+ - | | residential | | ``type:way and highway=residential and`` | | Note that some roads | - | | roads missing | | ``name!=* and noname!=yes`` | | might be actually | - | | a name (for | | | unnamed in reality. | - | | quality | | | Such features can be | - | | assurance) | | | marked as unnamed | - | | | | with the ``noname`` tag | - | | | | in OSM. | + | residential | | ``type:way and highway=residential and`` | Note that some roads | + | roads missing | | ``name!=* and noname!=yes`` | might be actually | + | a name (for | | unnamed in reality. | + | quality | | Such features can be | + | assurance) | | marked as unnamed | + | | | with the ``noname`` tag | + | | | in OSM. | +------------------+--------------------------------------------------------+------------------------------+ - | | implausibly | | ``geometry:polygon and building=* and building!=no`` | | The currently largest | - | | large | | ``and area:(1E6..)`` | | building by footprint area | - | | buildings | | | is a car factory building | - | | | | measuring about 887,800 m².| + | implausibly | | ``geometry:polygon and building=* and building!=no`` | The currently largest | + | large | | ``and area:(1E6..)`` | building by footprint area | + | buildings | | is a car factory building | + | | | measuring about 887,800 m². | +------------------+--------------------------------------------------------+------------------------------+ | From 7d3c356ab31be292a1399954c810a29d81af91b1 Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Wed, 4 Jan 2023 15:34:18 +0100 Subject: [PATCH 04/13] Docs: add perimeter, and multiple geometry filters --- docs/filter.rst | 153 ++++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 62 deletions(-) diff --git a/docs/filter.rst b/docs/filter.rst index 7cc754c1..162874fb 100644 --- a/docs/filter.rst +++ b/docs/filter.rst @@ -16,71 +16,100 @@ Selectors .. table:: :widths: 24 50 24 - +-------------------------+------------------------------------+------------------------+ - | | **description** | **example** | - +=========================+====================================+========================+ - | ``key=value`` | matches all entities which | ``natural=tree`` | - | | have this exact tag | | - +-------------------------+------------------------------------+------------------------+ - | ``key=*`` | matches all entities which have | ``addr:housenumber=*`` | - | | any tag with the given key | | - +-------------------------+------------------------------------+------------------------+ - | ``key!=value`` | matches all entities | ``oneway!=yes`` | - | | which do not have | | - | | this exact tag | | - +-------------------------+------------------------------------+------------------------+ - | ``key!=*`` | matches all entities which do not | ``name!=*`` | - | | have any tag with the given key | | - +-------------------------+------------------------------------+------------------------+ - | ``key in (value list)`` | matches all entities which do | ``highway in`` | - | | have any tag with the given key | ``(residential, | - | | and one of the given values | living_street)`` | - +-------------------------+------------------------------------+------------------------+ - | ``type:osm-type`` | matches all entities of the | ``type:node`` | - | | given osm type | | - +-------------------------+------------------------------------+------------------------+ - | ``id:osm-id`` | matches all entities with the | ``id:1234`` | - | | given osm id [1]_ | | - +-------------------------+------------------------------------+------------------------+ - | ``id:osm-type/osm-id`` | matches the entity with the given | ``id:node/1234`` | - | | osm type and id | | - +-------------------------+------------------------------------+------------------------+ - | ``id:(id list)`` | matches all entities with the | ``id:(1, 42, 1234)`` | - | | given osm ids [1]_ | | - +-------------------------+------------------------------------+------------------------+ - | ``id:(id list)`` | matches all entities with the | ``id:(node/1, way/3)`` | - | | given osm types and ids | | - +-------------------------+------------------------------------+------------------------+ - | ``id:(id range)`` | matches all entities with an id | ``id:(1 .. 9999)`` | - | | matching the given id range [2]_ | | - +-------------------------+------------------------------------+------------------------+ - | ``geometry:geom-type`` | matches anything which has a | ``geometry:polygon`` | - | | geometry of the given type | | - | | (point, line, polygon, or other) | | - +-------------------------+------------------------------------+------------------------+ - | ``area:(from..to)`` | matches features with a geometry | ``area:(1.0 .. 1E6)`` | - | | having an area (measured in m²) | | - | | in the given range [2]_ | | - +-------------------------+------------------------------------+------------------------+ - | ``length:(from..to)`` | matches features with a geometry | ``length:( .. 100)`` | - | | having a length (measured in m) | | - | | in the given range [2]_ | | - +-------------------------+------------------------------------+------------------------+ - | ``changeset:id`` | matches contributions [3]_ | ``changeset:42`` | - | | performed in the specified | | - | | changeset | | - +-------------------------+------------------------------------+------------------------+ - | ``changeset:(id list)`` | matches contributions [3]_ | ``changeset:(10, 42)`` | - | | performed in one of the | | - | | specified changesets | | - +-------------------------+------------------------------------+------------------------+ - | ``changeset:(from..to)``| matches contributions [3]_ | ``changeset:(10..42)`` | - | | performed in a range of | | - | | changesets | | - +-------------------------+------------------------------------+------------------------+ + +------------------------------------+------------------------------------+-----------------------------------+ + | | **description** | **example** | + +====================================+====================================+===================================+ + | ``key=value`` | matches all entities which | ``natural=tree`` | + | | have this exact tag | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``key=*`` | matches all entities which have | ``addr:housenumber=*`` | + | | any tag with the given key | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``key!=value`` | matches all entities | ``oneway!=yes`` | + | | which do not have | | + | | this exact tag | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``key!=*`` | matches all entities which do not | ``name!=*`` | + | | have any tag with the given key | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``key in (value list)`` | matches all entities which do | ``highway in`` | + | | have any tag with the given key | ``(residential, | + | | and one of the given values | living_street)`` | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``type:osm-type`` | matches all entities of the | ``type:node`` | + | | given osm type | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``id:osm-id`` | matches all entities with the | ``id:1234`` | + | | given osm id [1]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``id:osm-type/osm-id`` | matches the entity with the given | ``id:node/1234`` | + | | osm type and id | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``id:(id list)`` | matches all entities with the | ``id:(1, 42, 1234)`` | + | | given osm ids [1]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``id:(id list)`` | matches all entities with the | ``id:(node/1, way/3)`` | + | | given osm types and ids | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``id:(id range)`` | matches all entities with an id | ``id:(1 .. 9999)`` | + | | matching the given id range [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry:geom-type`` | matches anything which has a | ``geometry:polygon`` | + | | geometry of the given type | | + | | (point, line, polygon, or other) | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``area:(from..to)`` | matches features with a geometry | ``area:(1.0 .. 1E6)`` | + | | having an area (measured in m²) | | + | | in the given range [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``length:(from..to)`` | matches features with a geometry | ``length:( .. 100)`` | + | | having a length (measured in m) | | + | | in the given range [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``perimeter:(from..to)`` | matches features with a | ``perimeter:( .. 100)`` | + | | perimeter (measured in m) in the | | + | | given range [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry.vertices:(from..to)`` | matches features by the number | ``geometry.vertices:(1 .. 10)`` | + | | of points they consists of | | + | | in the given range [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry.outers:number`` | matches features by the number | ``geometry.outers:1`` | + | or | of outer rings they consists of | or | + | ``geometry.outers:(from..to)`` | in the given range [2]_ | ``geometry.outers:(2 .. )`` | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry.inners:number`` | matches features by the number | ``geometry.inners:0`` | + | or | of holes (inner rings) they | or | + | ``geometry.inners:(from..to)`` | consists of in the given range | ``geometry.inners:(1 .. )`` | + | | [2]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry.roundness:(from..to)`` | matches features which have a | ``geometry.roundness:(0.8 .. )`` | + | | *roundness* (or *compactness*) | | + | | in the given range [2]_ [4]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``geometry.squareness:(from..to)`` | matches features which have a | ``geometry.squareness:(0.8 .. )`` | + | | *squareness* | | + | | in the given range [2]_ [5]_ | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``changeset:id`` | matches contributions [3]_ | ``changeset:42`` | + | | performed in the specified | | + | | changeset | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``changeset:(id list)`` | matches contributions [3]_ | ``changeset:(10, 42)`` | + | | performed in one of the | | + | | specified changesets | | + +------------------------------------+------------------------------------+-----------------------------------+ + | ``changeset:(from..to)`` | matches contributions [3]_ | ``changeset:(10..42)`` | + | | performed in a range of | | + | | changesets | | + +------------------------------------+------------------------------------+-----------------------------------+ .. [1] Keep in mind that osm ids are not unique between osm types. In order to include only a specific object the id needs to be used together with an osm type filter. Alternatively, one can also use the combined type+id filter (e.g. `id:node/1234`). .. [2] The lower or upper bound of a range may be omitted to indicate that the values are only to be limited to be "up to" or "starting from" the given value, respectively. For example: `id:(10..)` will accept all entities with an id of 10 or higher. .. [3] The `changeset` filters can only be used in `contribution` based API endpoints. +.. [4] This is using the `"Polsby–Popper test" score`_ where all values fall in the interval 0 to 1 and 1 represents a perfect circle. +.. [5] This is using the `rectilinearity measurement by Žunić and Rosin`_ where all values fall in the interval 0 to 1 and 1 represents a perfectly rectilinear geometry. +.. _"Polsby–Popper test" score: https://en.wikipedia.org/wiki/Polsby%E2%80%93Popper_test +.. _rectilinearity measurement by Žunić and Rosin: https://www.researchgate.net/publication/221304067_A_Rectilinearity_Measurement_for_Polygons) | From 7ce7ecea4983de15094c383713bad64e09b5e82f Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Wed, 4 Jan 2023 15:34:34 +0100 Subject: [PATCH 05/13] Docs: bugfix wrong line-height in tables --- docs/_static/custom.css | 4 ++++ docs/conf.py | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 docs/_static/custom.css diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..748088cb --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,4 @@ +html.writer-html5 .rst-content table.docutils td > p, html.writer-html5 .rst-content table.docutils th > p { + /* this setting is changed in the theme for tables, but shouldn't change for us. */ + line-height: 24px; +} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 4eb3a818..3ef5610f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,6 +97,8 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +html_css_files = ['custom.css'] + # Custom sidebar templates, must be a dictionary that maps document names # to template names. # From 947d3747c3bcf47cdeb888e03bf59405e9d4b903 Mon Sep 17 00:00:00 2001 From: Johannes Visintini Date: Wed, 4 Jan 2023 15:43:43 +0100 Subject: [PATCH 06/13] Docs: improve filter examples formatting --- docs/filter.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/filter.rst b/docs/filter.rst index 162874fb..25be1f6c 100644 --- a/docs/filter.rst +++ b/docs/filter.rst @@ -162,7 +162,7 @@ Examples Here's some useful examples for querying some OSM features: .. table:: - :widths: 24 50 24 + :widths: 24 34 34 +------------------+--------------------------------------------------------+------------------------------+ | **OSM Feature** | **filter** | **comment** | @@ -195,12 +195,12 @@ Here's some useful examples for querying some OSM features: | | | not one. | +------------------+--------------------------------------------------------+------------------------------+ | highways | | ``type:way and (highway in (motorway,`` | The list of used tags | - | | | ``motorway_link, trunk, trunk_link, primary,`` | depends on the exact | - | | | ``primary_link, secondary, secondary_link,`` | definition of a | - | | | ``tertiary, tertiary_link, unclassified,`` | "highway". In a | - | | | ``residential, living_street, pedestrian) or`` | different context, it may | - | | | ``(highway=service and service=alley))`` | also include less or even | - | | | more tags | + | | | ``motorway_link, trunk, trunk_link,`` | depends on the exact | + | | | ``primary, primary_link, secondary,`` | definition of a | + | | | ``secondary_link, tertiary,`` | "highway". In a | + | | | ``tertiary_link, unclassified,`` | different context, it may | + | | | ``residential, living_street, pedestrian)`` | also include less or even | + | | | ``or (highway=service and service=alley))`` | more tags | | | | (``footway``, ``cycleway``, | | | | ``track``, ``path``, all | | | | ``highway=service``, etc.) | @@ -213,8 +213,8 @@ Here's some useful examples for querying some OSM features: | | | with the ``noname`` tag | | | | in OSM. | +------------------+--------------------------------------------------------+------------------------------+ - | implausibly | | ``geometry:polygon and building=* and building!=no`` | The currently largest | - | large | | ``and area:(1E6..)`` | building by footprint area | + | implausibly | | ``geometry:polygon and building=* and`` | The currently largest | + | large | | ``building!=no and area:(1E6..)`` | building by footprint area | | buildings | | is a car factory building | | | | measuring about 887,800 m². | +------------------+--------------------------------------------------------+------------------------------+ From 8cf10afa5d6f804f163bc74c2d1faf88148788bd Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 16:07:41 +0100 Subject: [PATCH 07/13] fix bug in groupByTag endpoints when key/values do not exist in keytables --- .../executor/ElementsRequestExecutor.java | 66 ++++++++++-------- ...itional-spring-configuration-metadata.json | 9 +++ .../controller/GetControllerTest.java | 69 +++++++++++++++++++ 3 files changed, 116 insertions(+), 28 deletions(-) create mode 100644 src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java index 95df128d..289f0c75 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/ElementsRequestExecutor.java @@ -181,11 +181,12 @@ public static

Response aggregateGroupByBoundary TagTranslator tt = DbConnData.tagTranslator; Integer[] valuesInt = new Integer[groupByValues.length]; ArrayList> zeroFill = new ArrayList<>(); - int keysInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-1); + int keyInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-2); if (groupByValues.length != 0) { for (int j = 0; j < groupByValues.length; j++) { - valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]).map(OSHDBTag::getValue).orElse(-j); - zeroFill.add(new ImmutablePair<>(keysInt, valuesInt[j])); + valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]) + .map(OSHDBTag::getValue).orElse(-j - 1); + zeroFill.add(new ImmutablePair<>(keyInt, valuesInt[j])); } } var arrGeoms = new ArrayList<>(processingData.getBoundaryList()); @@ -201,7 +202,7 @@ public static

Response aggregateGroupByBoundary mapAgg = mapAgg.filter(filter.get()); } var result = ExecutionUtils.computeNestedResult(requestResource, - mapAgg.map(f -> ExecutionUtils.mapSnapshotToTags(keysInt, valuesInt, f)) + mapAgg.map(f -> ExecutionUtils.mapSnapshotToTags(keyInt, valuesInt, f)) .aggregateBy(Pair::getKey, zeroFill).map(Pair::getValue) .aggregateByTimestamp(OSMEntitySnapshot::getTimestamp)); var groupByResult = OSHDBCombinedIndex.nest(result); @@ -217,10 +218,12 @@ public static

Response aggregateGroupByBoundary int tagValue = entry.getKey().getSecondIndex().getValue(); String tagIdentifier; // check for non-remainder objects (which do have the defined key and value) - if (entry.getKey().getSecondIndex().getKey() != -1 && tagValue != -1) { - tagIdentifier = tt.lookupTag(keysInt, tagValue).toString(); - } else { + if (entry.getKey().getSecondIndex().getKey() == -1) { tagIdentifier = "remainder"; + } else if (tagValue < 0) { + tagIdentifier = groupByKey[0] + '=' + groupByValues[-tagValue - 1]; + } else { + tagIdentifier = tt.lookupTag(keyInt, tagValue).toString(); } resultSet[count] = new GroupByResult(new Object[] {boundaryIds[boundaryIdentifier], tagIdentifier}, results); @@ -288,14 +291,15 @@ public static Response aggregateGroupByTag(RequestResource requestResource, TagTranslator tt = DbConnData.tagTranslator; Integer[] valuesInt = new Integer[groupByValues.length]; ArrayList> zeroFill = new ArrayList<>(); - int keysInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-1); + int keyInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-2); if (groupByValues.length != 0) { for (int j = 0; j < groupByValues.length; j++) { - valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]).map(OSHDBTag::getValue).orElse(-j); - zeroFill.add(new ImmutablePair<>(keysInt, valuesInt[j])); + valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]) + .map(OSHDBTag::getValue).orElse(-j - 1); + zeroFill.add(new ImmutablePair<>(keyInt, valuesInt[j])); } } - var preResult = mapRed.map(f -> ExecutionUtils.mapSnapshotToTags(keysInt, valuesInt, f)) + var preResult = mapRed.map(f -> ExecutionUtils.mapSnapshotToTags(keyInt, valuesInt, f)) .aggregateByTimestamp().aggregateBy(Pair::getKey, zeroFill).map(Pair::getValue); var result = ExecutionUtils.computeResult(requestResource, preResult); var groupByResult = ExecutionUtils.nest(result); @@ -307,10 +311,12 @@ public static Response aggregateGroupByTag(RequestResource requestResource, ElementsResult[] results = ExecutionUtils.fillElementsResult( entry.getValue(), requestParameters.isDensity(), df, geom); // check for non-remainder objects (which do have the defined key and value) - if (entry.getKey().getKey() != -1 && entry.getKey().getValue() != -1) { - groupByName = tt.lookupTag(keysInt, entry.getKey().getValue()).toString(); - } else { + if (entry.getKey().getKey() == -1) { groupByName = "remainder"; + } else if (entry.getKey().getValue() < 0) { + groupByName = groupByKey[0] + '=' + groupByValues[-entry.getKey().getValue() - 1]; + } else { + groupByName = tt.lookupTag(keyInt, entry.getKey().getValue()).toString(); } resultSet[count] = new GroupByResult(groupByName, results); count++; @@ -431,7 +437,7 @@ public static Response aggregateGroupByKey(RequestResource requestResource, TagTranslator tt = DbConnData.tagTranslator; Integer[] keysInt = new Integer[groupByKeys.length]; for (int i = 0; i < groupByKeys.length; i++) { - keysInt[i] = tt.getOSHDBTagKeyOf(groupByKeys[i]).map(OSHDBTagKey::toInt).orElse(-i); + keysInt[i] = tt.getOSHDBTagKeyOf(groupByKeys[i]).map(OSHDBTagKey::toInt).orElse(-i - 2); } MapAggregator, OSMEntitySnapshot> preResult = mapRed.flatMap(f -> { @@ -460,10 +466,12 @@ public static Response aggregateGroupByKey(RequestResource requestResource, ElementsResult[] results = ExecutionUtils.fillElementsResult( entry.getValue(), requestParameters.isDensity(), df, null); // check for non-remainder objects (which do have the defined key) - if (entry.getKey() != -1) { - groupByName = tt.lookupTag(entry.getKey(), 0).getKey(); - } else { + if (entry.getKey() == -1) { groupByName = "remainder"; + } else if (entry.getKey() < -1) { + groupByName = groupByKeys[-entry.getKey() - 2]; + } else { + groupByName = tt.lookupTag(entry.getKey(), 0).getKey(); } resultSet[count] = new GroupByResult(groupByName, results); count++; @@ -531,18 +539,19 @@ public static Response aggregateBasicFiltersRatio(RequestResource requestResourc Integer[] keysInt2 = new Integer[keys2.length]; Integer[] valuesInt2 = new Integer[values2.length]; for (int i = 0; i < requestParameters.getKeys().length; i++) { - keysInt1[i] = tt.getOSHDBTagKeyOf(requestParameters.getKeys()[i]).map(OSHDBTagKey::toInt) - .orElse(-i); + keysInt1[i] = tt.getOSHDBTagKeyOf(requestParameters.getKeys()[i]) + .map(OSHDBTagKey::toInt).orElse(-i - 1); if (requestParameters.getValues() != null && i < requestParameters.getValues().length) { valuesInt1[i] = tt.getOSHDBTagOf(requestParameters.getKeys()[i], requestParameters.getValues()[i]) - .map(OSHDBTag::getValue).orElse(-i); + .map(OSHDBTag::getValue).orElse(-i - 1); } } for (int i = 0; i < keys2.length; i++) { - keysInt2[i] = tt.getOSHDBTagKeyOf(keys2[i]).map(OSHDBTagKey::toInt).orElse(-i); + keysInt2[i] = tt.getOSHDBTagKeyOf(keys2[i]).map(OSHDBTagKey::toInt).orElse(-i - 1); if (i < values2.length) { - valuesInt2[i] = tt.getOSHDBTagOf(keys2[i], values2[i]).map(OSHDBTag::getValue).orElse(-i); + valuesInt2[i] = tt.getOSHDBTagOf(keys2[i], values2[i]) + .map(OSHDBTag::getValue).orElse(-i - 1); } } EnumSet osmTypes1 = @@ -782,18 +791,19 @@ public static

Response aggregateBasicFiltersRat Integer[] valuesInt2 = new Integer[values2.length]; TagTranslator tt = DbConnData.tagTranslator; for (int i = 0; i < requestParameters.getKeys().length; i++) { - keysInt1[i] = tt.getOSHDBTagKeyOf(requestParameters.getKeys()[i]).map(OSHDBTagKey::toInt) - .orElse(-i); + keysInt1[i] = tt.getOSHDBTagKeyOf(requestParameters.getKeys()[i]) + .map(OSHDBTagKey::toInt).orElse(-i - 1); if (requestParameters.getValues() != null && i < requestParameters.getValues().length) { valuesInt1[i] = tt.getOSHDBTagOf(requestParameters.getKeys()[i], requestParameters.getValues()[i]) - .map(OSHDBTag::getValue).orElse(-i); + .map(OSHDBTag::getValue).orElse(-i - 1); } } for (int i = 0; i < keys2.length; i++) { - keysInt2[i] = tt.getOSHDBTagKeyOf(keys2[i]).map(OSHDBTagKey::toInt).orElse(-i); + keysInt2[i] = tt.getOSHDBTagKeyOf(keys2[i]).map(OSHDBTagKey::toInt).orElse(-i - 1); if (i < values2.length) { - valuesInt2[i] = tt.getOSHDBTagOf(keys2[i], values2[i]).map(OSHDBTag::getValue).orElse(-i); + valuesInt2[i] = tt.getOSHDBTagOf(keys2[i], values2[i]) + .map(OSHDBTag::getValue).orElse(-i - 1); } } EnumSet osmTypes1 = (EnumSet) processingData.getOsmTypes(); diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000..f35bed01 --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,9 @@ +{ + "properties": [ + { + "name": "project.version", + "type": "java.lang.String", + "description": "Description for project.version." + } + ] +} \ No newline at end of file diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java index d7623e99..fa58e8ee 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java @@ -11,8 +11,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; +import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.apache.commons.csv.CSVRecord; import org.heigit.ohsome.ohsomeapi.Application; @@ -177,6 +179,41 @@ public void getElementsCountGroupByBoundaryGroupByTagTest() { .findFirst().get().get("result").get(0).get("value").asInt()); } + @Test + public void getElementsCountGroupByBoundaryGroupByTagUnknownValuesTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/elements/count/groupBy/boundary/groupBy/tag?bboxes=8.68086,49.39948,8.69401,49.40609&" + + "time=2016-11-09&groupByKey=building&groupByValues=xxx,yyy,zzz&filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("building=xxx", "building=yyy", "building=zzz", "remainder"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .filter(jsonNode -> + "boundary1".equalsIgnoreCase(jsonNode.get("groupByObject").get(0).asText())) + .map(jsonNode -> jsonNode.get("groupByObject").get(1).asText()) + .collect(Collectors.toSet())); + } + + @Test + public void getElementsCountGroupByBoundaryGroupByTagUnknownKeyTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity(server + port + + "/elements/count/groupBy/boundary/groupBy/tag?bboxes=8.68086,49.39948,8.69401,49.40609&" + + "time=2016-11-09&groupByKey=DoesNotExist&groupByValues=xxx&" + + "filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("DoesNotExist=xxx", "remainder"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .filter(jsonNode -> + "boundary1".equalsIgnoreCase(jsonNode.get("groupByObject").get(0).asText())) + .map(jsonNode -> jsonNode.get("groupByObject").get(1).asText()) + .collect(Collectors.toSet())); + } + @Test public void getElementsCountGroupByTypeTest() { TestRestTemplate restTemplate = new TestRestTemplate(); @@ -206,6 +243,38 @@ public void getElementsCountGroupByTagTest() { .findFirst().get().get("result").get(0).get("value").asInt()); } + @Test + public void getElementsCountGroupByTagUnknownValuesTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity( + server + port + "/elements/count/groupBy/tag?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2017-01-01&groupByKey=building&groupByValues=xxx,yyy,zzz&" + + "filter=building=* and type:way", + JsonNode.class); + assertEquals( + Set.of("building=xxx", "building=yyy", "building=zzz", "remainder"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + + @Test + public void getElementsCountGroupByTagUnknownKeyTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = restTemplate.getForEntity( + server + port + "/elements/count/groupBy/tag?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2017-01-01&groupByKey=DoesNotExist&groupByValues=xxx&" + + "filter=building=* and type:way", + JsonNode.class); + assertEquals( + Set.of("DoesNotExist=xxx", "remainder"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + @Test public void getElementsCountGroupByKeyTest() { TestRestTemplate restTemplate = new TestRestTemplate(); From 5a7480e0b06f6b0230679739a16deca0215c45d1 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 18:22:08 +0100 Subject: [PATCH 08/13] f --- .../additional-spring-configuration-metadata.json | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json deleted file mode 100644 index f35bed01..00000000 --- a/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "properties": [ - { - "name": "project.version", - "type": "java.lang.String", - "description": "Description for project.version." - } - ] -} \ No newline at end of file From 20e09cd774fb5c4940c2bb34bf1cccbb76313525 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 17:20:32 +0100 Subject: [PATCH 09/13] add further test cases for the `groupBy/tag` bug --- .../controller/GetControllerTest.java | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java index fa58e8ee..9510f3a8 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/GetControllerTest.java @@ -184,7 +184,8 @@ public void getElementsCountGroupByBoundaryGroupByTagUnknownValuesTest() { TestRestTemplate restTemplate = new TestRestTemplate(); ResponseEntity response = restTemplate.getForEntity(server + port + "/elements/count/groupBy/boundary/groupBy/tag?bboxes=8.68086,49.39948,8.69401,49.40609&" - + "time=2016-11-09&groupByKey=building&groupByValues=xxx,yyy,zzz&filter=type:way and building=*", + + "time=2016-11-09&groupByKey=building&groupByValues=xxx,yyy,zzz&" + + "filter=type:way and building=*", JsonNode.class); assertEquals( Set.of("building=xxx", "building=yyy", "building=zzz", "remainder"), @@ -291,6 +292,23 @@ public void getElementsCountGroupByKeyTest() { .findFirst().get().get("result").get(0).get("value").asInt()); } + @Test + public void getElementsCountGroupByKeyUnknownKeysTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = + restTemplate.getForEntity( + server + port + "/elements/count/groupBy/key?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2012-01-01&groupByKeys=DoesNotExist1,DoesNotExist2,DoesNotExist3&" + + "filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("DoesNotExist1", "DoesNotExist2", "DoesNotExist3", "remainder"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + @Test public void getElementsCountRatioTest() { final double expectedValue = 0.153933; @@ -654,6 +672,24 @@ public void getUsersCountGroupByKeyTest() { .findFirst().get().get("result").get(0).get("value").asInt()); } + @Test + public void getUsersCountGroupByKeyUnknownKeysTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = + restTemplate.getForEntity( + server + port + "/users/count/groupBy/key?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2014-01-01,2015-01-01&" + + "groupByKeys=DoesNotExist1,DoesNotExist2,DoesNotExist3&" + + "filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("DoesNotExist1", "DoesNotExist2", "DoesNotExist3", "remainder", "total"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + @Test public void getUsersCountGroupByTagTest() { TestRestTemplate restTemplate = new TestRestTemplate(); @@ -668,6 +704,41 @@ public void getUsersCountGroupByTagTest() { .findFirst().get().get("result").get(0).get("value").asInt()); } + @Test + public void getUsersCountGroupByTagUnknownValuesTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = + restTemplate.getForEntity( + server + port + "/users/count/groupBy/tag?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2014-01-01,2015-01-01&groupByKey=building&" + + "groupByValues=DoesNotExist1,DoesNotExist2&" + + "filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("building=DoesNotExist1", "building=DoesNotExist2", "remainder", "total"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + + @Test + public void getUsersCountGroupByTagUnknownKeyTest() { + TestRestTemplate restTemplate = new TestRestTemplate(); + ResponseEntity response = + restTemplate.getForEntity( + server + port + "/users/count/groupBy/tag?bboxes=8.67859,49.41189,8.67964,49.41263&" + + "time=2014-01-01,2015-01-01&groupByKey=DoesNotExist&groupByValues=xxx&" + + "filter=type:way and building=*", + JsonNode.class); + assertEquals( + Set.of("DoesNotExist=xxx", "remainder", "total"), + StreamSupport.stream(Spliterators.spliteratorUnknownSize( + response.getBody().get("groupByResult").iterator(), Spliterator.ORDERED), false) + .map(jsonNode -> jsonNode.get("groupByObject").asText()) + .collect(Collectors.toSet())); + } + @Test public void getUsersCountDensityTest() { final double expectedValue = 14.33; From af608bb0c29f3c8352a1226082929d7dddcccaa9 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 17:47:22 +0100 Subject: [PATCH 10/13] also fix groupBy/tag + groupBy/key bug in /users/count requests --- .../executor/UsersRequestExecutor.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/UsersRequestExecutor.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/UsersRequestExecutor.java index 6e995c8c..50d1bab2 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/UsersRequestExecutor.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/executor/UsersRequestExecutor.java @@ -120,12 +120,12 @@ public static Response countGroupByTag(HttpServletRequest servletRequest, TagTranslator tt = DbConnData.tagTranslator; Integer[] valuesInt = new Integer[groupByValues.length]; ArrayList> zeroFill = new ArrayList<>(); - int keysInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-1); + int keyInt = tt.getOSHDBTagKeyOf(groupByKey[0]).map(OSHDBTagKey::toInt).orElse(-3); if (groupByValues.length != 0) { for (int j = 0; j < groupByValues.length; j++) { - valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]).map(OSHDBTag::getValue) - .orElse(-j); - zeroFill.add(new ImmutablePair<>(keysInt, valuesInt[j])); + valuesInt[j] = tt.getOSHDBTagOf(groupByKey[0], groupByValues[j]) + .map(OSHDBTag::getValue).orElse(-j - 1); + zeroFill.add(new ImmutablePair<>(keyInt, valuesInt[j])); } } SortedMap>, Integer> result = null; @@ -138,7 +138,7 @@ public static Response countGroupByTag(HttpServletRequest servletRequest, for (OSHDBTag tag : tags) { int tagKeyId = tag.getKey(); int tagValueId = tag.getValue(); - if (tagKeyId == keysInt) { + if (tagKeyId == keyInt) { if (valuesInt.length == 0) { res.add(new ImmutablePair<>(new ImmutablePair<>(tagKeyId, tagValueId), f)); } @@ -169,12 +169,14 @@ public static Response countGroupByTag(HttpServletRequest servletRequest, groupByResult.entrySet()) { ContributionsResult[] results = ExecutionUtils.fillContributionsResult(entry.getValue(), requestParameters.isDensity(), inputProcessor, df, geom); - if (entry.getKey().getKey() == -2 && entry.getKey().getValue() == -2) { + if (entry.getKey().getKey() == -2) { groupByName = "total"; - } else if (entry.getKey().getKey() == -1 && entry.getKey().getValue() == -1) { + } else if (entry.getKey().getKey() == -1) { groupByName = "remainder"; + } else if (entry.getKey().getValue() < 0) { + groupByName = groupByKey[0] + '=' + groupByValues[-entry.getKey().getValue() - 1]; } else { - groupByName = tt.lookupTag(keysInt, entry.getKey().getValue()).toString(); + groupByName = tt.lookupTag(keyInt, entry.getKey().getValue()).toString(); } resultSet[count] = new GroupByResult(groupByName, results); count++; @@ -216,7 +218,7 @@ public static Response countGroupByKey(HttpServletRequest servletRequest, TagTranslator tt = DbConnData.tagTranslator; Integer[] keysInt = new Integer[groupByKeys.length]; for (int i = 0; i < groupByKeys.length; i++) { - keysInt[i] = tt.getOSHDBTagKeyOf(groupByKeys[i]).map(OSHDBTagKey::toInt).orElse(-i); + keysInt[i] = tt.getOSHDBTagKeyOf(groupByKeys[i]).map(OSHDBTagKey::toInt).orElse(-i - 3); } SortedMap, Integer> result = null; result = mapRed @@ -257,6 +259,8 @@ public static Response countGroupByKey(HttpServletRequest servletRequest, groupByName = "total"; } else if (entry.getKey() == -1) { groupByName = "remainder"; + } else if (entry.getKey() < -2) { + groupByName = groupByKeys[-entry.getKey() - 3]; } else { groupByName = tt.lookupTag(entry.getKey(), 0).getKey(); } From 2ed312cdc8b3bbcc224de75a031afc78b1184242 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 17:38:04 +0100 Subject: [PATCH 11/13] add to changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b519a03..b3facbde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ Changelog ## 1.9.0-SNAPSHOT (current master) +### Bug Fixes + +* Fix crash and incorrect output of `…/groupBy/tag` and `…/groupBy/key` endpoints when non-existing tag keys or values are used in a query ([#291]) + +[#291]: https://github.com/GIScience/ohsome-api/pull/291 + ## 1.8.0 From 4b2b28e8f0e4b93b572ae24df5c6d8d2d8a7e2aa Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Wed, 11 Jan 2023 18:32:30 +0100 Subject: [PATCH 12/13] various checkstyle fixes --- .../ohsomeapi/inputprocessing/StringSimilarity.java | 1 - .../heigit/ohsome/ohsomeapi/oshdb/DbConnData.java | 1 - .../ohsome/ohsomeapi/utils/ConfigureApplication.java | 3 ++- .../heigit/ohsome/ohsomeapi/utils/FilterUtil.java | 11 ++++++++++- .../heigit/ohsome/ohsomeapi/utils/RequestUtils.java | 2 -- .../ohsomeapi/controller/DataExtractionTest.java | 2 +- .../executor/ContributionsExecutorTest.java | 4 +++- .../inputprocessing/GeometryBuilderTest.java | 12 ++++++++---- 8 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/inputprocessing/StringSimilarity.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/inputprocessing/StringSimilarity.java index 5bb91f13..9c523c0a 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/inputprocessing/StringSimilarity.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/inputprocessing/StringSimilarity.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; import org.apache.commons.text.similarity.FuzzyScore; diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/oshdb/DbConnData.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/oshdb/DbConnData.java index fe80b983..c6f16055 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/oshdb/DbConnData.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/oshdb/DbConnData.java @@ -2,7 +2,6 @@ import javax.sql.DataSource; import org.heigit.ohsome.oshdb.api.db.OSHDBDatabase; -import org.heigit.ohsome.oshdb.api.db.OSHDBJdbc; import org.heigit.ohsome.oshdb.util.tagtranslator.TagTranslator; /** Holds the database connection objects. */ diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/ConfigureApplication.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/ConfigureApplication.java index 62cd0015..4ad991ae 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/ConfigureApplication.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/ConfigureApplication.java @@ -99,7 +99,8 @@ private ConfigureApplication(ApplicationArguments args) { } /** - * Method run by the Application class to parse incoming command line arguments + * Method run by the Application class to parse incoming command line arguments. + * * @param args ApplicationArguments from spring to be parsed. */ public static void parseArguments(ApplicationArguments args) diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/FilterUtil.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/FilterUtil.java index 767722a9..573e0b72 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/FilterUtil.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/FilterUtil.java @@ -4,12 +4,21 @@ import java.util.stream.Collectors; import org.heigit.ohsome.oshdb.osm.OSMType; +/** + * Utility functions for OSHDB filters. + */ public class FilterUtil { private FilterUtil() {} + /** + * Creates an OSHDB filter which selects OSM objects by their type. + * + * @param types the set of allowed OSM types + * @return a string representing an OSHDB filter matching the given set of OSM types + */ public static String filter(Set types) { return types.stream() .map(type -> "type:" + type.toString().toLowerCase()) - .collect(Collectors.joining(" or ", "( "," )")); + .collect(Collectors.joining(" or ", "( ", " )")); } } diff --git a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/RequestUtils.java b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/RequestUtils.java index 005a2a0a..229ef033 100644 --- a/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/RequestUtils.java +++ b/src/main/lombok/org/heigit/ohsome/ohsomeapi/utils/RequestUtils.java @@ -4,13 +4,11 @@ import java.io.IOException; import javax.servlet.http.HttpServletRequest; import org.heigit.ohsome.ohsomeapi.exception.DatabaseAccessException; -import org.heigit.ohsome.ohsomeapi.exception.ExceptionMessages; import org.heigit.ohsome.ohsomeapi.inputprocessing.GeometryBuilder; import org.heigit.ohsome.ohsomeapi.inputprocessing.ProcessingData; import org.heigit.ohsome.ohsomeapi.oshdb.DbConnData; import org.heigit.ohsome.ohsomeapi.oshdb.ExtractMetadata; import org.heigit.ohsome.oshdb.api.db.OSHDBDatabase; -import org.heigit.ohsome.oshdb.api.db.OSHDBJdbc; /** Utils class containing request-specific static utility methods. */ public class RequestUtils { diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java index 84bfa912..15a05369 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/controller/DataExtractionTest.java @@ -92,7 +92,7 @@ public void elementsGeomSimpleFeaturesOtherLineTest() { assertTrue("GeometryCollection" .equals(response.getBody().get("features").get(0).get("geometry").get("type").asText())); } - + @Test public void elementsGeomUsingNoTagsTest() { TestRestTemplate restTemplate = new TestRestTemplate(); diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsExecutorTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsExecutorTest.java index 7cbf4d59..a3441d95 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsExecutorTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/executor/ContributionsExecutorTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.util.EnumSet; import java.util.Set; import java.util.function.Predicate; @@ -45,7 +46,8 @@ public void contributionsFilter() { @Test public void contributionsFilterInvalid() { - assertThrows(BadRequestException.class, () -> ExecutionUtils.contributionsFilter("doesnotexist")); + assertThrows(BadRequestException.class, () -> + ExecutionUtils.contributionsFilter("doesnotexist")); } diff --git a/src/test/java/org/heigit/ohsome/ohsomeapi/inputprocessing/GeometryBuilderTest.java b/src/test/java/org/heigit/ohsome/ohsomeapi/inputprocessing/GeometryBuilderTest.java index 602dd21e..2f12ea59 100644 --- a/src/test/java/org/heigit/ohsome/ohsomeapi/inputprocessing/GeometryBuilderTest.java +++ b/src/test/java/org/heigit/ohsome/ohsomeapi/inputprocessing/GeometryBuilderTest.java @@ -124,7 +124,8 @@ public void createPolygonFromGeoJsonWithWrongGeomType() { + "{\"id\":\"Neuenheim\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[[[8.68465," + "49.41769]]]}}]}"; InputProcessor inputProcessor = new InputProcessor(processingData); - assertThrows(BadRequestException.class, () -> geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); + assertThrows(BadRequestException.class, () -> + geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); } @Test @@ -136,14 +137,16 @@ public void createPolygonFromGeoJsonWithWrongFormat() { + "[8.2933214,49.4329125],[8.2936734,49.4330121],[8.2940745,49.4331354]," + "[8.2950478,49.4317345],[8.2944706,49.4313443]]]]}]}"; InputProcessor inputProcessor = new InputProcessor(processingData); - assertThrows(BadRequestException.class, () -> geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); + assertThrows(BadRequestException.class, () -> + geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); } @Test public void createGeometryFromInvalidInputGeoJson() { String geoJson = "{\"type\": \"FeatureCollection\"}"; InputProcessor inputProcessor = new InputProcessor(processingData); - assertThrows(BadRequestException.class, () -> geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); + assertThrows(BadRequestException.class, () -> + geomBuilder.createGeometryFromGeoJson(geoJson, inputProcessor)); } @Test @@ -194,6 +197,7 @@ public void createGeometryFromMetadataGeoJson() { @Test public void createGeometryFromWrongMetadataGeoJson() { String geoJson = "{\"type\":\"Polygon\",\"coordinates\":[Invalid-Input]}"; - assertThrows(RuntimeException.class, () ->geomBuilder.createGeometryFromMetadataGeoJson(geoJson)); + assertThrows(RuntimeException.class, () -> + geomBuilder.createGeometryFromMetadataGeoJson(geoJson)); } } From dcd96534bbf3dac1bc53d93efe916ea59e94641e Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 9 Feb 2023 18:04:11 +0100 Subject: [PATCH 13/13] add release notes for v1.8.1 (#292) --- CHANGELOG.md | 8 ++- README.md | 8 +-- docs/endpoints.rst | 126 ++++++++++++++++++++++----------------------- 3 files changed, 74 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3facbde..f8608bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,16 @@ Changelog ## 1.9.0-SNAPSHOT (current master) -### Bug Fixes +## 1.8.1 + +### Bug Fixes * Fix crash and incorrect output of `…/groupBy/tag` and `…/groupBy/key` endpoints when non-existing tag keys or values are used in a query ([#291]) +### Documentation +* Complete documentation of ohsome filters ([#290]) + +[#290]: https://github.com/GIScience/ohsome-api/pull/290 [#291]: https://github.com/GIScience/ohsome-api/pull/291 diff --git a/README.md b/README.md index 2fa37ef6..5e2b0f87 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The ohsome API is a generic web API for in-depth analysis of OpenStreetMap (OSM) data with a focus on its history. It allows to get aggregated statistics about the evolution of OSM data itself and about the contributors behind the data. Furthermore, data extraction methods are provided to access the historic development of individual OSM features. -The functionalities of the ohsome API can be accessed via HTTP requests. As a basis underneath serves the [OSHDB API](https://github.com/GIScience/oshdb). The current stable version is [v1.8.0](https://github.com/GIScience/ohsome-api/releases/tag/1.8.0). Developed and maintained by [HeiGIT](https://heigit.org/). +The functionalities of the ohsome API can be accessed via HTTP requests. As a basis underneath serves the [OSHDB API](https://github.com/GIScience/oshdb). The current stable version is [v1.8.1](https://github.com/GIScience/ohsome-api/releases/tag/1.8.1). Developed and maintained by [HeiGIT](https://heigit.org/). ## Using the ohsome API @@ -39,7 +39,7 @@ Here you see an example response giving the length of residential roads for a bo "url": "https://ohsome.org/copyrights", "text": "© OpenStreetMap contributors" }, - "apiVersion": "1.8.0", + "apiVersion": "1.8.1", "metadata": { "executionTime": 858, "description": "Total length of items in meters.", @@ -122,8 +122,8 @@ These instructions will get you a copy of the project up and running on your loc 2. move to your Maven project directory in a shell (e.g. Windows PowerShell) 3. enter the command `mvn -DskipTests=true package` to build the project (if you want to build it running the integrated tests too, look at the section [Testing](#testing)) 4. to run the jar file enter the following (if no additional keytables file is given, you can assume that it is included): - * keytables included: `java -jar target/ohsome-api-1.8.0.jar --database.db=C:/path-to-your-data/ba-wue.oshdb` - * keytables not included: `java -jar target/ohsome-api-1.8.0.jar --database.db=C:/path-to-your-data/ba-wue.oshdb --database.keytables=C:/path-to-your-keytablesFile/keytables` + * keytables included: `java -jar target/ohsome-api-1.8.1.jar --database.db=C:/path-to-your-data/ba-wue.oshdb` + * keytables not included: `java -jar target/ohsome-api-1.8.1.jar --database.db=C:/path-to-your-data/ba-wue.oshdb --database.keytables=C:/path-to-your-keytablesFile/keytables` Now you should have a running local API, which is ready for receiving requests under *http://localhost:8080/*.
To check if it is running properly, you should be able to visit the swagger documentation under *http://localhost:8080/swagger-ui.html*. diff --git a/docs/endpoints.rst b/docs/endpoints.rst index 8fb10f40..a512780c 100644 --- a/docs/endpoints.rst +++ b/docs/endpoints.rst @@ -65,7 +65,7 @@ How big is the area of farmland in the region Rhein-Neckar? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2014-01-01T00:00:00Z", "value" : 1.020940258E7 @@ -79,7 +79,7 @@ How big is the area of farmland in the region Rhein-Neckar? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2014-01-01T00:00:00Z", "value" : 1.020940258E7 @@ -93,7 +93,7 @@ How big is the area of farmland in the region Rhein-Neckar? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2014-01-01T00:00:00Z", "value" : 10209402.58 @@ -107,7 +107,7 @@ How big is the area of farmland in the region Rhein-Neckar? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2014-01-01T00:00:00Z", "value" : 1.020940258E7 @@ -160,7 +160,7 @@ What is the density of restaurants with wheelchair access in Heidelberg? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2019-05-07T00:00:00Z", "value" : 0.79 @@ -174,7 +174,7 @@ What is the density of restaurants with wheelchair access in Heidelberg? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2019-05-07T00:00:00Z", "value" : 0.79 @@ -188,7 +188,7 @@ What is the density of restaurants with wheelchair access in Heidelberg? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2019-05-07T00:00:00Z", "value" : 0.79 @@ -202,7 +202,7 @@ What is the density of restaurants with wheelchair access in Heidelberg? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "timestamp" : "2019-05-07T00:00:00Z", "value" : 0.79 @@ -262,7 +262,7 @@ How many oneway streets exist within living_street streets in Heidelberg over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "ratioResult" : [ { "timestamp" : "2016-01-01T00:00:00Z", "value" : 28660.519999999997, @@ -288,7 +288,7 @@ How many oneway streets exist within living_street streets in Heidelberg over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "ratioResult" : [ { "timestamp" : "2016-01-01T00:00:00Z", "value" : 28660.519999999997, @@ -314,7 +314,7 @@ How many oneway streets exist within living_street streets in Heidelberg over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "ratioResult" : [ { "timestamp" : "2016-01-01T00:00:00Z", "value" : 28660.519999999997, @@ -340,7 +340,7 @@ How many oneway streets exist within living_street streets in Heidelberg over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "ratioResult" : [ { "timestamp" : "2016-01-01T00:00:00Z", "value" : 28660.519999999997, @@ -412,7 +412,7 @@ How often information about the roof of buildings is present? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -441,7 +441,7 @@ How often information about the roof of buildings is present? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -470,7 +470,7 @@ How often information about the roof of buildings is present? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -499,7 +499,7 @@ How often information about the roof of buildings is present? "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -582,7 +582,7 @@ Compare length of different types of streets for two or more regions. "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -641,7 +641,7 @@ Compare length of different types of streets for two or more regions. "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -700,7 +700,7 @@ Compare length of different types of streets for two or more regions. "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -759,7 +759,7 @@ Compare length of different types of streets for two or more regions. "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "result" : [ { "timestamp" : "2018-01-01T00:00:00Z", @@ -884,7 +884,7 @@ Show number of users editing buildings before, during and after Nepal earthquake "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2015-03-01T00:00:00Z", "toTimestamp" : "2015-04-01T00:00:00Z", @@ -915,7 +915,7 @@ Show number of users editing buildings before, during and after Nepal earthquake "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2015-03-01T00:00:00Z", "toTimestamp" : "2015-04-01T00:00:00Z", @@ -946,7 +946,7 @@ Show number of users editing buildings before, during and after Nepal earthquake "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2015-03-01T00:00:00Z", "toTimestamp" : "2015-04-01T00:00:00Z", @@ -977,7 +977,7 @@ Show number of users editing buildings before, during and after Nepal earthquake "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2015-03-01T00:00:00Z", "toTimestamp" : "2015-04-01T00:00:00Z", @@ -1063,7 +1063,7 @@ Number of contributions to the building 'Stadthalle Heidelberg' between 2010 and "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2010-01-01T00:00:00Z", @@ -1080,7 +1080,7 @@ Number of contributions to the building 'Stadthalle Heidelberg' between 2010 and "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2010-01-01T00:00:00Z", @@ -1097,7 +1097,7 @@ Number of contributions to the building 'Stadthalle Heidelberg' between 2010 and "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2010-01-01T00:00:00Z", @@ -1114,7 +1114,7 @@ Number of contributions to the building 'Stadthalle Heidelberg' between 2010 and "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2010-01-01T00:00:00Z", @@ -1167,7 +1167,7 @@ Density of contributions to shops within the oldtown area of Heidelberg between "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1184,7 +1184,7 @@ Density of contributions to shops within the oldtown area of Heidelberg between "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1201,7 +1201,7 @@ Density of contributions to shops within the oldtown area of Heidelberg between "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1218,7 +1218,7 @@ Density of contributions to shops within the oldtown area of Heidelberg between "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1271,7 +1271,7 @@ Number of the latest contributions to residential buildings with a geometry chan "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2014-01-01T00:00:00Z", @@ -1288,7 +1288,7 @@ Number of the latest contributions to residential buildings with a geometry chan "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2014-01-01T00:00:00Z", @@ -1305,7 +1305,7 @@ Number of the latest contributions to residential buildings with a geometry chan "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2014-01-01T00:00:00Z", @@ -1322,7 +1322,7 @@ Number of the latest contributions to residential buildings with a geometry chan "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2014-01-01T00:00:00Z", @@ -1375,7 +1375,7 @@ Density of the latest contributions with a geometry change to shops within the o "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1392,7 +1392,7 @@ Density of the latest contributions with a geometry change to shops within the o "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1409,7 +1409,7 @@ Density of the latest contributions with a geometry change to shops within the o "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1426,7 +1426,7 @@ Density of the latest contributions with a geometry change to shops within the o "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "result" : [ { "fromTimestamp" : "2012-01-01T00:00:00Z", @@ -1479,7 +1479,7 @@ Number of contributions to shops in different suburbs of Heidelberg (Altstadt an "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1504,7 +1504,7 @@ Number of contributions to shops in different suburbs of Heidelberg (Altstadt an "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1529,7 +1529,7 @@ Number of contributions to shops in different suburbs of Heidelberg (Altstadt an "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1554,7 +1554,7 @@ Number of contributions to shops in different suburbs of Heidelberg (Altstadt an "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1615,7 +1615,7 @@ Density of contributions to shops within different suburbs of Heidelberg (Altsta "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1640,7 +1640,7 @@ Density of contributions to shops within different suburbs of Heidelberg (Altsta "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1665,7 +1665,7 @@ Density of contributions to shops within different suburbs of Heidelberg (Altsta "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1690,7 +1690,7 @@ Density of contributions to shops within different suburbs of Heidelberg (Altsta "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "groupByResult" : [ { "groupByObject" : "Heidelberg-Altstadt", "result" : [ { @@ -1825,7 +1825,7 @@ Extract the modifications of the blown up tower of the heidelberg castle over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "type" : "FeatureCollection", "features" : [{ "type" : "Feature", @@ -1863,7 +1863,7 @@ Extract the modifications of the blown up tower of the heidelberg castle over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "type" : "FeatureCollection", "features" : [{ "type" : "Feature", @@ -1901,7 +1901,7 @@ Extract the modifications of the blown up tower of the heidelberg castle over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "type" : "FeatureCollection", "features" : [{ "type" : "Feature", @@ -1939,7 +1939,7 @@ Extract the modifications of the blown up tower of the heidelberg castle over ti "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "type" : "FeatureCollection", "features" : [{ "type" : "Feature", @@ -2024,7 +2024,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2101,7 +2101,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2178,7 +2178,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2255,7 +2255,7 @@ Get the changes of pharmacies with opening hours in a certain area of Heidelberg "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6720,49.3988,8.7026,49.4274&filter=amenity=pharmacy%20and%20opening_hours=*%20and%20type:node&time=2020-02-01,2020-06-29&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2376,7 +2376,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2425,7 +2425,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2474,7 +2474,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2523,7 +2523,7 @@ Get the latest change of constructions in a certain area of the Bahnstadt in Hei "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "metadata" : { "description" : "Latest contributions as GeoJSON features.", "requestUrl" : "https://api.ohsome.org/v1/contributions/latest/geometry?bboxes=8.6644159,49.401099,8.6663353,49.4027195&filter=landuse=construction%20and%20type:way&time=2020-06-29,2014-07-01&showMetadata=yes&properties=metadata,tags&clipGeometry=false" @@ -2606,7 +2606,7 @@ Get metadata of the underlying OSHDB data "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "timeout": 600.0, "extractRegion" : { "spatialExtent" : { @@ -2628,7 +2628,7 @@ Get metadata of the underlying OSHDB data "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "extractRegion" : { "spatialExtent" : { "type" : "Polygon", @@ -2649,7 +2649,7 @@ Get metadata of the underlying OSHDB data "url" : "https://ohsome.org/copyrights", "text" : "© OpenStreetMap contributors" }, - "apiVersion" : "1.8.0", + "apiVersion" : "1.8.1", "extractRegion" : { "spatialExtent" : { "type" : "Polygon",