Publication Date: 2020-07-08

Approval Date: 2020-06-26

Submission Date: 2020-05-05

Reference number of this document: OGC 19-084

Reference URL for this document: http://www.opengis.net/doc/PER/vtp2-D002

Category: OGC Public Engineering Report

Editor: Andrea Aime

Title: OGC Vector Tiles Pilot 2: Vector Tiles Filtering Language Engineering Report


OGC Public Engineering Report

COPYRIGHT

Copyright © 2020 Open Geospatial Consortium. To obtain additional rights of use, visit http://www.opengeospatial.org/

WARNING

This document is not an OGC Standard. This document is an OGC Public Engineering Report created as a deliverable in an OGC Interoperability Initiative and is not an official position of the OGC membership. It is distributed for review and comment. It is subject to change without notice and may not be referred to as an OGC Standard. Further, any OGC Public Engineering Report should not be referenced as required or mandatory technology in procurements. However, the discussions in this document could very well lead to the definition of an OGC Standard.

LICENSE AGREEMENT

Permission is hereby granted by the Open Geospatial Consortium, ("Licensor"), free of charge and subject to the terms set forth below, to any person obtaining a copy of this Intellectual Property and any associated documentation, to deal in the Intellectual Property without restriction (except as set forth below), including without limitation the rights to implement, use, copy, modify, merge, publish, distribute, and/or sublicense copies of the Intellectual Property, and to permit persons to whom the Intellectual Property is furnished to do so, provided that all copyright notices on the intellectual property are retained intact and that each person to whom the Intellectual Property is furnished agrees to the terms of this Agreement.

If you modify the Intellectual Property, all copies of the modified Intellectual Property must include, in addition to the above copyright notice, a notice that the Intellectual Property includes modifications that have not been approved or adopted by LICENSOR.

THIS LICENSE IS A COPYRIGHT LICENSE ONLY, AND DOES NOT CONVEY ANY RIGHTS UNDER ANY PATENTS THAT MAY BE IN FORCE ANYWHERE IN THE WORLD. THE INTELLECTUAL PROPERTY IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE DO NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE INTELLECTUAL PROPERTY WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION OF THE INTELLECTUAL PROPERTY WILL BE UNINTERRUPTED OR ERROR FREE. ANY USE OF THE INTELLECTUAL PROPERTY SHALL BE MADE ENTIRELY AT THE USER’S OWN RISK. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY CONTRIBUTOR OF INTELLECTUAL PROPERTY RIGHTS TO THE INTELLECTUAL PROPERTY BE LIABLE FOR ANY CLAIM, OR ANY DIRECT, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM ANY ALLEGED INFRINGEMENT OR ANY LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR UNDER ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION WITH THE IMPLEMENTATION, USE, COMMERCIALIZATION OR PERFORMANCE OF THIS INTELLECTUAL PROPERTY.

This license is effective until terminated. You may terminate it at any time by destroying the Intellectual Property together with all copies in any form. The license will also terminate if you fail to comply with any term or condition of this Agreement. Except as provided in the following sentence, no such termination of this license shall require the termination of any third party end-user sublicense to the Intellectual Property which is in force as of the date of notice of such termination. In addition, should the Intellectual Property, or the operation of the Intellectual Property, infringe, or in LICENSOR’s sole opinion be likely to infringe, any patent, copyright, trademark or other right of a third party, you agree that LICENSOR, in its sole discretion, may terminate this license without any compensation or liability to you, your licensees or any other party. You agree upon termination of any kind to destroy or cause to be destroyed the Intellectual Property together with all copies in any form, whether held by you or by any third party.

Except as contained in this notice, the name of LICENSOR or of any other holder of a copyright in all or part of the Intellectual Property shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Intellectual Property without prior written authorization of LICENSOR or such copyright holder. LICENSOR is and shall at all times be the sole entity that may authorize you or any third party to use certification marks, trademarks or other special designations to indicate compliance with any LICENSOR standards or specifications.

This Agreement is governed by the laws of the Commonwealth of Massachusetts. The application to this Agreement of the United Nations Convention on Contracts for the International Sale of Goods is hereby expressly excluded. In the event any provision of this Agreement shall be deemed unenforceable, void or invalid, such provision shall be modified so as to make it valid and enforceable, and as so modified the entire Agreement shall remain in full force and effect. No decision, action or inaction by LICENSOR shall be construed to be a waiver of any rights or remedies available to it.

None of the Intellectual Property or underlying information or technology may be downloaded or otherwise exported or reexported in violation of U.S. export laws and regulations. In addition, you are responsible for complying with any local laws in your jurisdiction which may impact your right to import, export or use the Intellectual Property, and you represent that you have complied with any regulations or registration procedures required by applicable law to make this license enforceable.

Table of Contents

1. Subject

The OGC Vector Tiles Pilot 2: Vector Tiles Filtering Language Engineering Report (ER) defines a filter language for vector data delivered as tiles (also known as vector tiles). The language applies to vector tiles served through implementations of the OGC API – Features standard and the draft OGC API - Tiles specification, but can be generally applied on all services supporting filtering by attributes.

The ER further includes an assessment of filter languages, styles and online/offline symbol sharing for GeoPackages, OGC API - Features and OGC API - Tiles implementations for accuracy and completeness in applications that render vector tiles at local to regional scales.

1.1. Target Scenario

The main benefits for transitioning from raster tiles to vector tiles has been the possibility of flexible map styling and the reduction of storage space required for maps, the latter allowing for maps being stored on devices with lower storage capacity as well as requiring lower bandwidth communications for transmission. In some cases, maps represented with vector tiles can be 20 to 30 times smaller than the same maps represented by raster tiles. This reduction enables the possibility of storing large sets of maps (i.e.,tile sets) into secure and lightweight removable media devices.

As described in Figure 1, a tile set repository (such as GeoPackage, Static Cache, or Compact Cache V2) is being used by a humanitarian relief convoy in the middle of the desert and with limited to no connectivity, supported by a group of interconnected systems working and communicating with each other. The repositories are generated at Command Post Computing Environments (CPCE) and comprise tile sets, styles, maps and routes served by National-level Services and Enterprise-level Services, which communicate with each other throughout OGC API Styles, API Tiles, API Images and API Routes.

executiveSummary
Figure 1. Sponsor Modular Scenario

The intention of working with vector tile sets is to transition from classic raster maps into using up-to-date and small-sized vector maps which allow for different styles to be applied as needed. An end user would easily transition from a Day Tpographic styling during daytime operations, to Night Topographic during night time, or even a hybrid satellite imagery/vector overlay styling.

Tile content filtering, as described in this ER, allows preparing a tile set specifically targeted to the mission, focusing on pertinent information, further reducing the final size of the package being downloaded on the mobile units, as well as limiting potential confusion.

2. Executive Summary

Consistent application of filters on data is important, whether an application is connected to a network or not. This is more so in environments with Denied, Degraded, Intermittent or Limited (DDIL) connectivity. This engineering report presents work conducted by the OGC Vector Tiles Pilot Phase 2 (VTP2) project with respect to filter languages.

VTP2 sought to deliver a consistent, interoperable online/offline architecture consisting of feature and tile servers, and GeoPackage-producing components that could publish, display and query vector tiles. One of the objectives of the VTP2 pilot was to develop a filtering language for vector tiles, and implement and exercise the filtering language on clients and servers.

The purpose of this Engineering Report and associated component implementations is to study the filtering and production of tiled feature data (also known as vector tiles) and GeoPackages, with particular attention to the following filtering features based on spatial and temporal aspects, as well as alphanumeric

The APIs applied in the pilot are from the emerging suite of OGC API standards. The first of the OGC API standards to be approved by the Technical Committee is the OGC API - Features standard. The pilot also explored the draft OGC API - Tiles and OGC API - Styles specifications.

The report also focuses on the opportunity for client-side versus server-side filtering, coupled with the possibility of caching, overall performance and user experience.

Feature and tile servers deployed in VTP2 implemented the OGC API - Features standard, and the draft OGC API - Tiles and OGC API - Styles specifications. Whereas the feature and tile servers allowed the pilot to explore online support for vector tiles, GeoPackage allowed the pilot to explore offline support.

The key findings of the pilot, with regard to a vector tiles filter language, are:

  • Both server-side and client-side filtering are important. Server-side filtering reduces payload size and can simplify the client-side development. The client-side helps to keep tiles static, and thus cacheable, while adding interactivity.

  • In the context of vector tiles some pre-defined server-side filters are important, to include pertinent information depending on the zoom level, and to keep the vector tile size in control.

  • The filtering language can contain operators that are not needed for specific applications, and difficulties of implementing a text-based parsers may limit its implementations.

The pilot made the following recommendations, with regard to a vector tiles filter language:

  • A way to advertise support for a subset of filtering operators and expressions should be developed and included in filtering extensions.

  • JSON based filtering languages should be explored to lower the implementation cost and provide a suitable option for clients offering Graphical User Interfaces (GUIs) to build filters.

  • Complex filtering and multi-layer filtering should be investigated, and methods to support them implemented.

  • While filtering can reduce the number of returned items, it’s also necessary to develop support for limiting the returned attributes. A querying extension should both advertise which attributes can be removed, and provide ways to limit them in requests.

  • Support for complex, eventually multi-layer filtering should be explored, allowing to perform queries that are too large to fit the limits of a URL, as well as to avoid providing the same query into all tile requests.

2.1. Document contributor contact points

All questions regarding this document should be directed to the editor or the contributors:

Contacts

Name Organization Role

Andrea Aime

GeoSolutions

Editor

Stefano Bovio

GeoSolutions

Contributor

Clemens Portele

interactive instruments

Contributor

Jeff Yutzler

Image Matters

Contributor

Jerome Jacovella-St-Louis

Ecere

Contributor

Jeffrey Johnson

Terranodo

Contributor

Sergio Taleisnik

Skymantics

Contributor

Jeff Harrison

AGC

Contributor

2.2. Foreword

Attention is drawn to the possibility that some of the elements of this document may be the subject of patent rights. The Open Geospatial Consortium shall not be held responsible for identifying any or all such patent rights.

Recipients of this document are requested to submit, with their comments, notification of any relevant patent claims or other intellectual property rights of which they may be aware that might be infringed by any implementation of the standard set forth in this document, and to provide supporting documentation.

3. References

4. Terms and definitions

For the purposes of this report, the definitions specified in Clause 4 of the OWS Common Implementation Standard OGC 06-121r9 shall apply. In addition, the following terms and definitions apply.

● tile

geometric shape with known properties that may or may not be the result of a tiling (tessellation) process. A tile consists of a single connected "piece" without "holes" or "lines" (topological disc). (from OGC 19-014r1).

Note
In the ER, the definition for “tile is further constrained as a tessellated representation of geographicdata, often part of a set of such elements, covering a spatially contiguous extent which can be uniquely defined by a pair of indices for the column and row along with an identifier for the tile matrix (adapted from OGC 07-057r7)
● GeoPackage

an open, standards-based, platform-independent, portable, self-describing, compact format for transferring geospatial information [geopackage]

● dataset

collection of data, published or curated by a single agent, and available for access or download in one or more formats [OGC 17-069r3]

● collection

a set of features from a dataset [OGC 17-069r3]

4.1. Abbreviated terms

  • CQL Common Query Language

  • FE Filter Encoding

  • GPKG GeoPackage

  • MVT Mapbox Vector Tiles

  • OGC Open Geospatial Consortium

  • VT Vector Tiles

  • WFS Web Feature Service

  • WKT Well Known Text

  • WMS Web Map Service

5. Overview

The introduction provides a quick introduction to the VTP2 objectives.

The previous work section provides a summary of previous work related to tiling and filtering.

The Filter Conceptual Model and VTP2 testing considerations provides an overview of the filtering expressions and operators, a more in depth analysis of CQL.

The Tiles filtering section provides a list of filters used in the VTP2 tests and implementations, and the protocol extensions required to advertise queryables and submit filters.

The GeoPackaage filtering section details application of filters against GeoPackages, and support structures that can be used to speed up tile contents filtering.

The implementations section covers each VTP2 server and client deliverable involved in filtering tiles. Each component is described in detail, along with implementation difficulties and unique features.

The results and findings section summarizes the issues found in the development of VTP2 components, findings, as well as future work items.

Annex A contains the full Baukus Naur Form (BNF) of the CQL text encoding.

Annex B contains a copy of they Queryables specification from the Testbed 15 Styles Engineering report..

Annex C provides a sample filter capabilities document developed during the STAC and OGC API - Features and Catalogues Sprint.

6. Introduction

The goal of the Vector Tiles Pilot Phase 2 filtering activity, as described in this Engineering Report (ER) and associated component implementations, was to study the filtering and production of tiled feature data (also known as vector tiles) and GeoPackages, with particular attention to the following:

  • Filtering tiles based on the tile matrix set, range of zoom levels, bounding box and tile matrix set limits per level.

  • Removing layers and attributes that are not desired to be on the client-side.

  • Filtering features based on spatial, temporal, as well as alphanumeric aspects.

The ER also focuses on the opportunity for client-side versus server-side filtering, coupled with the possibility of caching, thereby enhancing overall performance and user experience.

7. Previous work

This section discusses previous work related to filtering, among existing OGC specifications, Testbeds and other activities, evaluating its usefulness in the context of filtering vector tiles.

7.1. Filter Encoding

The OpenGIS Filter Encoding 2.0 Encoding Standard (FE) describes an Extensible Markup Language (XML) and Key-Value Pair (KVP) encoding of a system neutral syntax for expressing projections, selection and sorting clauses collectively called a query expression.

The FE Standard includes both a conceptual filtering model as well as one encoding in Extensible Markup Language (XML). The FE language supports:

  • Literals and value references (attributes)

  • Expressions, as basic math, and functions

  • Comparison operators for alphanumeric expressions

  • Spatial operators for location-based expressions

  • Temporal operators for time-based expressions

  • Logical operators allowing the combination of all the above

  • Value references. In particular, value references can use a a subset of XPath, allowing sophisticated access to objects in a nested structure. This makes FE a natural fit for application schemas based on complex features.

The FE detailed conceptual model is distributed across the entire specification document. This ER contains a simple overview diagram of FE in the conceptual model chapter in this ER.

The FE XML encoding is best suited for use in XML documents sent in HTTP POST requests. Usage in GET requests, as a query parameter, is also possible, but limited in application by the verboseness of the language, the URL encoding obfuscating most of its structure, and the practical length limits of a URL.

7.2. Catalog Services

The HTTP binding of the Catalog Services standard (OGC 12-168r6), also referred to as the Catalogue Services for the Web (CSW) standard (OGC 12-176r7), supports multiple query languages by means of a CONSTRAINTLANGUAGE parameter in GetRecords requests.

The Catalog Services Standard supports the usage of OGC Filter Encoding, but also defines the Common Query Language (CQL). CQL is a text based query language with "a syntax similar to the SQL Where Clause", extended to support both temporal and spatial filters.

CSW advertises CQL as the primary means to filter records. Below is an example used against the AnyText property, which in CSW allows for full text searches:

http://host/catalogServer/csw?
service=CSW&
version=2.0.2&
request=GetRecords&
resultType=results&
outputSchema=http%3A%2F%2Fwww.isotc211.org%2F2005%2Fgmd&
NAMESPACE=xmlns(gmd=http%3A%2F%2Fwww.isotc211.org%2F2005%2Fgmd)&
typeNames=gmd:MD_Metadata&
CONSTRAINTLANGUAGE=CQL_TEXT
CONSTRAINT=AnyText%20=%20'air%20temperature'&
CONSTRAINT_LANGUAGE_VERSION=1.1.0&
elementSetName=full

However, the use of CQL as specified in CSW has several limitations:

  • The Baukus Naur Form (BNF) is not structurally valid

  • The CQL imposes limitations on comparisons that are not present in OGC Filter, e.g., while attribute = literal is valid, attribute1 > attribute2 is not.

  • The standard lacks CQL examples. The same is true of most CSW implementations. On the other hand, OGC Filter examples can be found in abundance, suggesting a less than widespread implementation of CQL.

  • While geometries can be expressed in Well-Known Text (WKT), there is no support for defining their Coordinate Reference System CRS.

The implementation of OGC Catalog Services has also pioneered two concepts that are now relevant to OGC API - Features, queryables and returnables.

Queryable properties are "field-like objects" that can be used to build filters, and "may differ from the response data elements". In other words, queryables are property names, but do not necessarily match the names of the returned properties, and may not appear in the data schema at all (if any schema is present). One example of a queryable without a direct match with returned data is AnyText, which is defined as a "target for full-text search of character data types in a catalogue". Another interesting example is "Abstract". This is a property that can be found among the results, but whose name may vary depending on the record format. For example, in Dublin Core records "Abstract" is named description, while in ISO records "Abstract" matches the nested property /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataI dentification/gmd:abstract.

On the other hand Returnable properties are property names found in the response. Some of them have a match with a corresponding queryable (e.g., title), while others do not. If this is the case, those properties cannot be used in filters (e.g, publisher, contributor).

7.3. CQL adoption and extension in open source software

The GeoServer open source project was the first reference implementation of the OGC Web Feature Service (WFS) standard.

Users of the WFS standard reported difficulties in using the OGC Filter Encoding standard for filtering. This was partly due to the complexity of the language, and partly due to limits in its usage within HTTP GET requests, in particular:

  • The verboseness of the format limited the ability to fit filters in the practical maximum length of a URL.

  • URL encoding of the XML elements both reduced URL legibility and aggravated the verboseness issues, with many characters represented as a 3 chars escape code.

This limited the ability to share data references as simple links.

The GeoServer project adopted, in 2007, a CQL_FILTER query parameter for both WFS GetFeature and Web Map Service (WMS) GetMap:

  • In WFS GetFeature, the parameter serves as an alternative to FILTER (which uses a different OGC FE XML encoding according to the WFS version in use).

  • In WMS GetMap, the parameter filters the map contents, allowing dynamic selection and filtering, from the client, without requiring to setup again the whole map style (see also the SLD and SLD_BODY parameters in OGC 05-078r4).

The following examples show a WFS 1.1 GetFeature request, returning features where the LAND_KM property value is between 100000 and 150000. The first uses FE XML, while the second encodes the filter in CQL instead:

Listing 1. WFS GetFeature with FE XML
http://host/wfs?request=GetFeature&version=1.1.0&typeName=topp:states&FILTER=%3CFilter%20xmlns=%22http://www.opengis.net/ogc%22%3E%3CPropertyIsBetween%3E%3CPropertyName%3Etopp:LAND_KM%3C/PropertyName%3E%3CLowerBoundary%3E%3CLiteral%3E100000%3C/Literal%3E%3C/LowerBoundary%3E%3CUpperBoundary%3E%3CLiteral%3E150000%3C/Literal%3E%3C/UpperBoundary%3E%3C/PropertyIsBetween%3E%3C/Filter%3E
Listing 2. WFS GetFeature with CQL
http://wfs?request=GetFeature&version=1.1.0&typeName=topp:states&CQL_FILTER=LAND_KM%20BETWEEN%20100000%20AND%20150000

Eventually some limitations of the first CQL version became apparent, so in 2010 Extended CQL (ECQL) was created by the GeoTools and GeoServer communities, to bring the language closer to the OGC Filter capabilities. In particular, ECQL supports, in addition to CQL:

  • Free-form comparison expressions in terms of expression OP expression.

  • FeatureId filters.

The CQL_FILTER parameter has supported both CQL and ECQL syntaxes since then.

A remaining significant limitation of (E)CQL, in GeoServer, is that it can only be used in a GET request, and has no support in XML POST requests.

7.4. OGC Testbed 14

Participants in the Testbed 14 Complex Features Handling thread performed an extensive analysis of filtering languages [1]. Of particular interest is the ER chapter on API building blocks for queries.

That chapter contains an analysis of filtering languages following different approaches:

  • Languages already available OGC standards, namely, OGC Filter Encoding and CQL.

  • Emerging languages used by the Web Community, in particular, GraphQL and Falcor.

  • Creating a new language that is simple to implement (more about this in the STAC and OGC API sprint report below).

Notable observations from that work include:

  • Due to being encoded in XML, OGC Filter Encoding is not considered a natural fit for JSON-first services (though it remains a good option for implementations returning GML based application schemas).

  • Falcor is best suited for JSON only services, and needs to be extended to support spatial support capabilities.

  • GraphQL needs extensions to its spatial capabilities. GraphQL also depends on the presence of a schema, which is not mandatory in OGC API - Features. Like CQL, GraphQL does not support multi-valued properties.

CQL has been considered suitable for usage in future extensions of the OGC API - Features but, due to its numerous limitations, but not without further work.

For CQL, the notion of a queryable was first used in combination with a data retrieving service. As with CSW, a queryable is a property that can be queried, but it is not necessarily tied to the schema of the dataset. A queryable could indeed be a visible property of the data. A queryable could also be referring to a nested element via a simple name, or referring to a summary property, such as AnyText, without the property actually being present in the result. The concept was further explored in OGC Testbed 15, where a dedicated OGC API - Features extension was proposed.

7.5. OGC Testbed 15

Participants in the OGC Testbed 15 Open Portrayal thread investigated and prototyped a new Application Programming Interface (API) for styles publishing, discovery and editing. Results of this activity are documented in the OGC Testbed-15: Styles API Engineering Report.

When a client edits styles, knowing which attributes can be used for collection filtering is important. This was handled by the queryables OGC API - Features extension draft. Queryables are normally a subset of all possible attributes, and in general, may not even show up among the results of a items query. The returned attributes are referred to as "presentables" or "returnables", instead.

Quoting the Testbed 15 ER, each collection exposes a list of Queryable objects, each characterized by:

  • id (required) - the property name for use in expressions.

  • type (required) - the data type of the property, one of string, uri, enum, number, integer, date, dateTime, boolean.

  • description (optional) - a description of the property.

  • required (optional) - indicator whether the property is always present in features.

  • mediaTypes (optional) - in general, the representation of the queryables is meant to be independent of the feature encoding. However, this is not always the case. For example, length restrictions or namespace prefixes may result in different property identifiers for the same property. To support this, the definition of a queryable may be restricted to one or more feature encodings (media types).

  • pattern (optional, only for "string" and "uri") - a regular expression to validate the values of the property.

  • values (required, only for "enum") - an array of valid values of the property.

  • range (optional, only for "number", "integer", "date" and "dateTime") - the range of valid values expressed as an array with two items. Open ranges can be expressed using null for the minimum or maximum value.

As they provide a list of property names the filter can use, queryables are a natural fit for a filtering extension.

7.6. STAC and OGC API Sprint, OGC API Filtering extension

In November 2019 OGC organized the STAC and OGC API - Features and Catalogues Sprint. The sprint hosted numerous groups, one of them focused on experimenting a possible "OGC API - Features - Part 3: Common Query Language" extension.

The CQL language was considered first in conceptual terms, with a definition of the operators and expressions that could be used in an encoding. Then, three possible encodings were prototyped:

  • A text-based language, derived from the original CQL. The language is similar to the GeoServer Extended CQL, in particular, it removes some of the original CQL limitations, allowing comparisons between expressions.

  • A JSON-based hierarchical objects language, meant to be a port to JSON of the OGC Filter Encoding XML encoding.

  • A JSON-based nested array language, that would read like a prefix notation, reminiscent of Mapbox Styles Expressions.

The following table compares the various approaches:

Table 1. Comparison of CQL encodings friendliness
Text Hierarchical JSON Array based JSON

User

Trivial to write by hand and understand

Easier to handle for those familiar with OGC filter

Reads "backwards", easier to handle for those familiar with Mapbox Styles Expressions

Developer

Requires writing a text based parser based on the BNF

JSON reads directly into a parse-tree like structure (based on nested objects)

JSON reads directly into a parse-tree like structure (based on nested arrays)

The following shows an example of filtering based on properties of a satellite image, and spatial location, in the three encodings:

Table 2. Encoding examples
Language Example

Text

beamMode='ScanSAR Narrow' AND
swathDirection='ascending' AND
polarization='HH+VV+HV+VH' AND
intersects(geometry,POLYGON((-77.117938 38.936860,-77.040604 39.995648,-76.910536 38.892912,-77.039359 38.791753,-77.047906 38.841462,-77.034183 38.840655,-77.033142 38.857490)))

Hierarchical json

{
  "and": [
    {
      "eq": {
        "property": "beamMode",
        "value": "ScanSAR Narrow"
      }
    },
    {
      "eq": {
        "property": "swathDirection",
        "value": "ascending"
      }
    },
    {
      "eq": {
        "property": "polarization",
        "value": "HH+VV+HV+VH"
      }
    },
    {
      "intersects": {
        "property": "footprint",
        "value": {
          "type": "Polygon",
          "coordinates": [
            [
              [ -77.117938, 38.93686 ],
              [ -77.040604, 39.995648 ],
              [ -76.910536, 38.892912 ],
              [ -77.039359, 38.791753 ],
              [ -77.047906, 38.841462 ],
              [ -77.034183, 38.840655 ],
              [ -77.033142, 38.85749 ],
              [ -77.117938, 38.93686 ]
            ]
          ]
        }
      }
    }
  ]
}

Array based JSON

[
  "all",
  [
    "==",
    [ "get", "beamMode" ],
    "ScanSAR Narrow"
  ],
  [
    "==",
    [ "get", "swathDirection" ],
    "ascending"
  ],
  [
    "==",
    [ "get", "polarization" ],
    "HH+VV+HV+VH"
  ],
  [
    "intersects",
    [ "geometry" ],
    {
      "type": "Polygon",
      "coordinates": [
        [
          [ -77.117938, 38.93686 ],
          [ -77.040604, 39.995648 ],
          [ -76.910536, 38.892912 ],
          [ -77.039359, 38.791753 ],
          [ -77.047906, 38.841462 ],
          [ -77.034183, 38.840655 ],
          [ -77.033142, 38.85749 ],
          [ -77.117938, 38.93686 ]
        ]
      ]
    }
  ]
]

In addition to working with the filtering language, the sprint considered the cost of filter language implementation, from the filtering operators point of view. The CQL model contains a rich set of comparison, spatial, temporal and logic operators. Implementing the full set can be both expensive, and depending on the application, perhaps un-necessary.

Based on the OGC Filter Encoding 2.0 specification, and the OGC APIs, two options were considered:

  • Conformance classes for filters, identifying them in groups.

  • Fine grained filter capabilities documents, listing the specific subset chosen by a server

The conformance classes approach allows a compact representation of the supported filters. This is at the expense of fine grain tuning the supported operator set. Classes can be naturally derived from the existing operator subdivision, that is, logical, comparison, spatial, and temporal. However, in practical applications, subsets of operators tend to go across classes. For example, a minimal subset covering basic filtering needs could include all comparisons and logical operators, along with bbox and during basic spatial and temporal filtering. The uncommon and advanced operators can be found within the spatial and temporal categories, but the common ones are found in all categories.

On the other hand, the capabilities document allows for a tailored operator selection but at the expense of listing all supported operators. Annex C contains an example of a full queryables document, as prototyped in GeoServer during the code sprint.

Combining the best aspects of the two approaches above is also possible: declaring a conformance class when all operators in it are supported, and explicitly enumerating the ones for incomplete classes.

8. Filter Conceptual Model and VTP2 testing considerations

8.1. Conceptual model

The following diagram provides a draft of the filter conceptual model, the elements and their relationship to the other significant elements, available when using a filter in a service or GeoPackage implementation.

conceptual model
Figure 2. Filter conceptual models

In particular, an implementation of the model refers to:

  • A hierarchy of filter types and expression concepts, that can be used to compose a filter.

  • A filter language, an encoding, typically textual, that expresses the filter.

  • A collection or tile set, which is the target of the filtering.

The collection in turn exposes a set of queryables, property names and types that can be used to build a filter, and to verify its formal correctness.

The filter refers to the common building blocks. In summary:

  • Expressions, be they property references, literals, functions and arithmetic combinations thereof.

  • Filters, in particular, spatial ones, temporal, simple comparisons and logic combinations thereof.

Refer to 09-026r2, OGC® Filter Encoding 2.0 Encoding Standard – With Corrigendum for a detailed definition of each expression and filter.

8.2. The CQL language

The OGC API - Features Standards Working Group (SWG) is currently exploring a filtering extension and are evaluating a number of possible encodings. Two encodings are currently being considered for use in the filtering extension:

The JSON encoding is recognized to be most useful to express filters in a larger JSON document, while the CQL based syntax is considered more useful for direct human entry and usage in URLs.

Within the limits of VTP2, the CQL language was chosen for prototyping purposes, as CQL is currently better defined, and better supports the target usage within tile resource URLS.

The CQL language is a text-based language that reads like a SQL 'Where' clause expression, as it is regarded as easy to read and to enter directly, without support by a user interface. On the other hand, due to the text nature, CQL is more complex to handle software-wise, as a full parser needs to be written to handle it. By comparison, the two JSON structures mentioned above, can be parsed using a JSON parser, and would construct an object structure that is similar to a parse tree, ready for use and evaluation.

Usage of CQL outside of the confines of Catalog Services has been pioneered by GeoServer community. GeoServer is an open source project which began using an extended version of the CQL language in both the WFS and WMS protocols:

  • In WFS, CQL can be used as an alternative to the XML filter encoding in GetFeature requests.

  • In WMS, CQL can be used as a way to further filter map contents, in addition to the filtering already performed by the Styled Layer Descriptor (SLD) styles.

In both cases the user can add a &CQL_FILTER=<filter expression> query parameter in the request, and get back filtered results.

Compared to the Catalog CQL, the proposed filtering extension of OGC API - Features provided some improvements:

  • Some of the original restrictions have been lifted, making this approach as expressive as OGC FE, and similar to the version adopted by GeoServer. For example, the original CQL did not allow comparing two properties, but only a property with a literal.

  • The BNF was updated to correctly validate, and can now be parsed by a machine.

A copy of the current BNF version can be found in Annex A.

The following table shows a few examples of text CQL filters:

Filter meaning CQL encoding

Floors greater than 5

floors>5

Owner name contains 'Jones'

owner LIKE '% Jones %'

More than 5 floors and a swimming pool

floors>5 AND swimming_pool=true

A swimming pool and (more than five floors or material is brick)

swimming_pool=true AND (floors > 5 OR material LIKE 'brick%' OR material LIKE '%brick')`

Updated between 7:30am June 10, 2017 and 10:30am June 11, 2017

updated DURING 2017-06-10T07:30:00 2017-06-11T10:30:00

Geometry that intersects with geometry POLYGON((-10.0 -10.0,10.0 -10.0,10.0 10.0,-10.0 -10.0)) (as expressed in WKT)

INTERSECTS(geometry,POLYGON\((-10.0 -10.0,10.0 -10.0,10.0 10.0,-10.0 -10.0)))

Some considerations:

  • The filter is normally human readable and quite similar to SQL.

  • Geometries are expressed in the Well Known Text (WKT) syntax.

  • Time literals are expressed in ISO format.

9. Filtering Tiles

This ER Section focuses on filtering tile contents and explains the final decisions and recommended API changes needed to generate outputs that match the VTP2 objectives.

9.1. Vector Tiles Pilot 2 testing operator subset

The VTP2 implementations exercised the following subset of operators:

Table 3. VTP2 filter operator subset
Class Operators

Spatial

BBOX, Contains, Within, Intersects, Disjoint

Temporal

During, Before, After, TEquals

Comparison

All

Logical

All

Expression

Property, Literal

The selection of the operators has been driven by the following principles:

  • The set is simple enough to be implemented within the time frame of VTP2.

  • The set is representative of the overall model filtering abilities.

9.2. Queryables

The list of valid properties, and their type, must be available for clients to build filters.

As indicated in Chapter 6, the Testbed 15 Styles’s Engineering Report extended the OGC API - Features with a concept of Queryables, a resource enumerating all attributes available for filtering.

The VTP2 participants used the same extension to advertise collection queryables, both in the OGC API - Features, and in the OGC API - Tiles (for those implementing a stand-alone Tile API, as opposed to a tiles building block in the Features API).

9.3. Single and multi-layer tile filtering

The VTP2 participants considered two filtering cases:

  • Filtering a tile from a single collection

  • Filtering a multi-layer collection

The first use case, filtering a single layer tile, is well-supported by the existing work, in particular, the OGC API - Features CQL extension, as well as the Queryables extension, with the following workflow:

  • The client inspects the queryables

  • The client helps the user to build a filter reducing the features returned in tiles

  • A request for tiles with the filter and filter-lang parameters is sent to the OGC API - Features tiles extension, or to the stand-alone OGC API - Tiles, retrieving tiles with reduced content.

The second use case presents some extra complexities, in particular:

  • Discovery of queryables for all the layers included in the tile must be possible.

  • Providing multiple filters, one per collection, to the server must be possible.

Regarding queryables discovery, the issue is easily solved in an OGC API - Features providing multi-layer tiles at the root level /tiles resource. In this case, the client can list the collections to be retrieved, and thus, lookup the queryables on a collection by collection basis. A stand-alone Tiles API poses a challenge, as collections are opaque and can contain anything, including having a single collection delivering directly multi-layer tiles (see the GeoSolutions implementation in this regard). The queryables document, as a flat list of attributes, is insufficient for this case, and should be turned into a list of named layers, each having their own queryables.

The second issue, providing multiple filters, does not have a solution in the existing CQL language. GeoServer Extended CQL supports a notion of "filter list", used to provide multiple filters in WMS GetMap requests. The grammar uses the semicolon to separate filters, as the comma is already used in the IN operator.

SequenceOfSearchConditions> ::=
          <search condition>
        | <SequenceOfSearchConditions> ; <search condition>

Another possibility would be to repeat the "filter" and "filter-lang" parameters, one instance per filtered collection, in the URL.

Regardless of the solution adopted, most base maps use a large number of layers, for example, an openstreemap.org like map typically uses over 20 layers. Trying to filter on this would require placing over 20 filters in the request, quickly exhausting the practical length of a URL.

For these reasons, with the exception of the Ecere Tiles API, the VTP2 participants limited filtering to single layer collections, while filtering multi-layer collections with CQL is left as future exercise.

Ecere implemented support for compact multi-layer filtering expressions based on the selectors and expressions syntax from the Cascading Map Style Sheets (CMSS) styling language (see Section 11.5).

10. Filtering GeoPackages with Vector Tiles

GeoPackage is built on the SQLite relational database. As a relational database, filtering of feature data is easily done through conventional SQL querying. However, when the feature data is stored in vector tiles, filtering is more complicated. Both formats used in VTP2 tiles (MVT and GeoJSON) embed attribute information in the vector tiles. Keeping the attributes embedded in the vector tiles undermines the capabilities of a GeoPackage-based architecture for the following reasons:

  1. Since features may span multiple tiles, having the attribute information duplicated across each tile containing a particular feature is redundant.

  2. Queries against the embedded attributes are not possible without opening a number of candidate tiles individually, an inefficient process.

  3. There is no obvious way to identify the candidate tiles to open, beyond knowledge of the area of interest of a particular query.

In response to these concerns, the participants proposed some alternatives for managing attributes. Due to resource constraints, these approaches were only tested in a limited fashion.

10.1. Attributes in Attributes Tables

Through the Vector Tiles Attributes Extension (see the Summary ER), a GeoPackage may contain an attributes table for each vector tiles layer. Using this approach provides two benefits:

  • Features can be filtered via their attributes using conventional SQL queries.

  • The attributes for a feature can be removed from the vector tiles, so that they are only stored in the GeoPackage once.

Depending on the underlying architecture of the vector tiles server, this approach may impose significant additional processing during GeoPackage creation. In some architectures, the vector tiles are created in advance. In naive GeoPackage creation (ignoring filtering considerations), those vector tiles can simply be copied directly into the GeoPackage. However, in this scenario the vector tiles would have to be modified to remove the attributes. This would significantly increase the processing time required to produce the GeoPackage. An architecture where vector tiles are produced on-the-fly would not be subject to this performance impact.

10.2. Spatial Filtering

The approach described in the previous section provides significant benefits for scenarios where features need to be filtered by their attributes and spatial extents. However, it is not possible or practical to isolate which tiles to open to find the geometries for the features that satisfy a particular query.

An R-tree spatial index, storing the overall extent of whole (untiled) features, can be used in conjunction with the attributes table to handle arbitrarily large geospatial extents. Such an index can speed up queries by focusing on the features present in a specific area, only performing more costly attributes comparison for those features within the bounding box of a query. That same stored extent can also be used to easily identify where specific features are located, e.g. to center the view on a particular feature, potentially after having identified that feature by an attributes-based query.

The GeoPackage Related Tables Extension can be used to establish a many-to-many mapping between features and the tiles containing those features. Once this is done, the query can be performed to identify a result set (based on feature IDs) and the mapping table can be queried to identify the tile or tiles that contain the geometries for those features. In some scenarios, this will improve the performance of filtering operations.

The following examples are practical queries performed on a GeoPackage produced by Ecere of the Daraa / OpenStreetMap Topographic DataStore for the pilot, with vector data tiled according to the World Mercator WGS84 Tile Matrix Set, and using the Attributes Table extension, the Tiles/Features Mapping Table extension, as well as a 32-bit integer R-tree spatial index (storing the extent of features as decimal degrees multiplied by a factor of 107, maintaining the same precision as OpenStreetMap).

Querying features and attributes

In this first example query, the client does not care about either the detailed geometry or the tiles of the features but does care about features within a specific geographic region. The client wishes to list the GeoPackage feature IDs, as well as the values for four of the attribute fields (UFI, F_CODE, FCSUBTYPE and ZI005_FNA) matching the following conditions:

  • Features from the Daraa transportation lines (roads) layer

  • Whose name ZI005_FNA is not No Information

  • Which are at least partially located within a geographic bounding box whose lower-left and upper-right corners are respectively (32.6083233°N, 32.6083233°E) and (32.6097047°N, 36.0987994°E).

An inner join is used between the attributes table and the R-tree spatial index, whose id fields correspond.

select attributes_TransportationGroundCrv.id, UFI, F_CODE, FCSUBTYPE, ZI005_FNA
   from attributes_TransportationGroundCrv
   inner join rtree_attributes_TransportationGroundCrv_vector_tiles
   on attributes_TransportationGroundCrv.id = rtree_attributes_TransportationGroundCrv_vector_tiles.id
   where ZI005_FNA != 'No Information' and
   maxLat > 326083233 and maxLon > 360899582 and
   minLat < 326097047 and minLon < 360987994;

Output (list of features):

id

UFI

F_CODE

FCSUBTYPE

ZI005_FNA

1442

36d6beb3-0a35-4ec3-a2f6-6b526ea1f659

AP030

100152

شارع الأردن

3178

204af963-3d18-402d-8cfe-ff4195e992c7

AP030

100152

شارع الزيدي

Identifying tiles containing certain features

In this second example query, the client wishes to preserve the above conditions (only roads with name information, within that same bounding box), but rather than retrieving the attributes values, all the tiles (specifically of zoom level 16, in this case) containing those features should be listed. Because this GeoPackage includes a Tiles / Features Mapping table, that table can be joined with both the Attributes table (through its related_id) as well as with the Tiles table (through its base_id). Note that the tiles returned by this query cover the entirety of the unclipped features which happen to intersect the bounding box of interest — not only the tiles which themselves intersect the bounding box.

select distinct tiles_Daraa2.id, zoom_level, tile_row, tile_column
   from mapping_table_TransportationGroundCrv
   inner join tiles_Daraa2
   on mapping_table_TransportationGroundCrv.base_id = tiles_Daraa2.id
   inner join attributes_TransportationGroundCrv
   on mapping_table_TransportationGroundCrv.related_id = attributes_TransportationGroundCrv.id
   inner join rtree_attributes_TransportationGroundCrv_vector_tiles
   on attributes_TransportationGroundCrv.id = rtree_attributes_TransportationGroundCrv_vector_tiles.id
   where ZI005_FNA != 'No Information'
   and maxLat > 326083233 and maxLon > 360899582
   and minLat < 326097047 and minLon < 360987994
   and zoom_level = 16;

Output (list of tiles):

id

zoom_level

tile_row

tile_column

7962

16

26518

39339

8059

16

26519

39338

8060

16

26519

39339

8161

16

26520

39337

8162

16

26520

39338

8163

16

26520

39339

Identifying tiles without a mapping table

Even without a Tiles / Features Mapping table, a client could still easily determine a list of tiles from the extent of the feature(s) as stored in the R-tree spatial index. For a large feature, often only the tiles in view are of interest, in which case the client could also calculate the intersection of the feature’s extent with the view’s extent to identify those tiles. It could then proceed to enumerate the full list (complete box) of tiles within that extent, in a similar way to how the limits of a tile matrix are calculated for a dataset’s extent. The advantage of the Mapping table is to altogether skip tiles in which the features of interest may not be present at all, therefore avoiding to decode tiles not containing these. This would most likely only benefit large features spread non-uniformly across a vast geospatial extent, and come at the cost of additional storage, which should be taken into consideration. The benefit would also not apply to scenarios where all tiles within a geographic area of interest should be decoded anyways (e.g. the simple visualization use case).

In this third example query, it is assumed that a Tiles / Features Mapping table is not available, and therefore the output of the query is an extent which will be programmatically converted to tile coordinates.

select min(minLat), min(minLon), max(maxLat), max(maxLon)
   from attributes_TransportationGroundCrv
   inner join rtree_attributes_TransportationGroundCrv_vector_tiles
   on attributes_TransportationGroundCrv.id = rtree_attributes_TransportationGroundCrv_vector_tiles.id
   where ZI005_FNA != 'No Information'
   and maxLat > 326083233 and maxLon > 360899582
   and minLat < 326097047 and minLon < 360987994;

Output (extent of the unclipped features):

min(minLat)

min(minLon)

max(maxLat)

max(maxLon)

326079262

360884617

326191309

361000583

The extent returned in this case is larger and fully contains the extent of interest in the request. Converting the geographic extent to WorldMercatorWGS84Quad level 16 tile coordinates gives (26518, 39337)-(26520, 39339).

Here is the full list of tiles using those bounding tile coordinates, assuming the whole unclipped features are desired:

select id, zoom_level, tile_row, tile_column
   from tiles_Daraa2
   where zoom_level = 16
   and tile_row >= 26518 and tile_row <= 26520
   and tile_column >= 39337 and tile_row <= 39339;

Output (list of tiles):

id

zoom_level

tile_row

tile_column

7960

16

26518

39337

7961

16

26518

39338

7962

16

26518

39339

8058

16

26519

39337

8059

16

26519

39338

8060

16

26519

39339

8161

16

26520

39337

8162

16

26520

39338

8163

16

26520

39339

It can be seen that the Mapping table request in this scenario would save the client from decoding 3 out of 9 tiles (33%), which might be significant.

If the client is instead interested in the clipped portion rather than the unclipped features (i.e. only the tiles which themselves intersect the bounding box of interest), then the intersection of the returned extent with the requested extent should be used. This might have justified avoiding the query altogether and directly converting the area of interest to a list of tiles, depending on the circumstances. Converting this intersected extent (which here is the same as the original requested bounding box) to WorldMercatorWGS84Quad level 16 tile coordinates gives (26520, 39337)-(26520, 39339).

The full list of tiles for the portion of the features of interest intersecting the area of interest is:

select id, zoom_level, tile_row, tile_column
   from tiles_Daraa2
   where zoom_level = 16
   and tile_row >= 26520 and tile_row <= 26520
   and tile_column >= 39337 and tile_row <= 39339;

Output (list of tiles):

id

zoom_level

tile_row

tile_column

8161

16

26520

39337

8162

16

26520

39338

8163

16

26520

39339

In this case, only 3 tiles are needed, and a query using the Mapping table does not eliminate any tile from the full box of tiles covered by the extent, since all tiles of the bounding box contain those features (no saving).

11. Implementations

Each component provides filtering abilities, available both on the client and server side. This chapter includes salient implementation notes, descriptions and demonstrations, as well as relevant feedback from each deliverable.

11.1. GeoSolutions D100 OGC API - Features

GeoSolutions worked on extending their implementation of the OGC API - Features standard to match the requirements of the VTP2 initiative. Specifically, the following changes were implemented to support filtering and tiles:

  • Exposed GeoServer (E)CQL filtering capabilities as an implementation of the current OGC API Features CQL extension draft, along with queryables support.

  • Implemented the draft OGC API - Tiles building blocks as part of the OGC API - Features, and added filtering support in the same way as the OGC API - Features extensions.

The CQL filtering support has been added directly into the "gs-ogcapi-features" GeoServer plugin, while the tiles building block has been implemented as new plugin, "gs-ogciapi-tiled-features", which can be added on top of the base "gs-ogcapi-features" one.

When the Tiled Features plugin is added, the landing page of the service reports the tile matrix set endpoint, as well as advertising tiling resources in the API definition. The following figures show the GeoServer OGC API - Features landing page and API, both extended with new elements from the OGC API - Tile building blocks.

geosolutions D101 features landing
Figure 3. The landing page of the OGC API - Features allows access to the tile matrix sets.
geosolutions D101 features api
Figure 4. The OGC API - Features advertises tile matrix set and data tile access.

Tiles are provided in any vector format supported by the internal machinery. During VTP2 that meant MVT, GeoJSON and TopoJSON, new formats can be added as desired through a plug-in programming interface.

Queryables support has been added in all collections. The following is an excerpt from the queryables of the syria_vtp:building_s collection (only a few attributes are shown to keep the example short):

{
  "queryables": [
    {
      "id": "AOO",
      "type": "number"
    },
    {
      "id": "ARA",
      "type": "number"
    },
    {
      "id": "BEN",
      "type": "string"
    },
    {
      "id": "CAA",
      "type": "integer"
    },
    {
      "id": "CCN",
      "type": "string"
    },
    {
      "id": "geom",
      "type": "geometry"
    }
  ],
  "links": [
    {
      "href": "http://vtp2.geo-solutions.it/geoserver/ogc/features/collections/vtp%3ATransportationGroundCrv?f=application%2Fx-yaml",
      "rel": "alternate",
      "type": "application/x-yaml",
      "title": "This document as application/x-yaml"
    },
    {
      "href": "http://vtp2.geo-solutions.it/geoserver/ogc/features/collections/vtp%3ATransportationGroundCrv?f=application%2Fjson",
      "rel": "self",
      "type": "application/json",
      "title": "This document"
    },
    {
      "href": "http://vtp2.geo-solutions.it/geoserver/ogc/features/collections/vtp%3ATransportationGroundCrv?f=text%2Fhtml",
      "rel": "alternate",
      "type": "text/html",
      "title": "This document as text/html"
    }
  ]
}

Support for the filter and filter-lang query parameters has been added both to the items and the tiles resources.

An example of a filtered items request follows:

The same example above, reformatted and URL decoded for readability, can be split into:

  • https://vtp2.geo-solutions.it/geoserver/ogc/features (service base)

  • collections/vtp:TransportationGroundCrv/items? (items access)

  • f=application/vnd.mapbox-vector-tile (requests to return Mapbox Vector Tile format)

  • filter=("RIN_ROI" = '3') AND (BBOX(geom,36.140,32.595,36.142,32.658)) (the filter)

  • filter-lang=cql-text (filter language is CQL)

An example of a single collection filtered tiles request follows:

The same example above, reformatted and URL decoded for readability, can be split into:

  • https://vtp2.geo-solutions.it/geoserver/ogc/features (service base)

  • collections/vtp:TransportationGroundCrv/tiles/WebMercatorQuad/14/6618/9833? (tile access)

  • f=application/vnd.mapbox-vector-tile (requests to return mapbox vector tiles)

  • filter=("RIN_ROI" = '3') (the filter)

  • filter-lang=cql-text (filter language is CQL)

Regarding caching, it is worth noting that a layer needs to have a caching configuration in order to expose tiled access, as tiling is internally managed by GeoWebCache. It is however not required to make filtered tiles cacheable, if not enabled, then the filtered tiles are computed on-the-fly. If enabled, internal GeoWebCache is going to treat the filter as a "CQL_FITLER" query parameter, to make caches reusable across services. Mapbox vector tiles are indeed already provided as part of the WMTS and WMS services.

In particular, MVT tiles construction is driven by styles, using filters and scale dependencies to decide which features to include at a given zoom level. As a general rule, anything that needs styles to be generated is treated as a WMS output format, and is then exposed into WMTS via GeoWebCache tiling and caching engine.

Various filtering visual examples are available in the GeoSolutions D104 client section.

11.2. Terranodo D100 OGC API - Tiles

The open source tegola software implemented the OGC API - Features CQL extension draft, along with collection level queryables support.

11.2.1. CQL

CQL was implemented in tegola with the following functionality:

  • CQL filters supported via the filter= parameter.

  • CQL text support was added. CQL JSON was planned for a future implementation.

11.2.2. Sample Requests

Spatial Predicates example requests, CQL filter first, followed by a full URL-encoded API request:

INTERSECTS(geometry,POLYGON((36.0710334777832 32.59845703812064, 36.13574981689453 32.59845703812064, 36.13574981689453 32.633592568907005, 36.0710334777832 32.633592568907005, 36.0710334777832 32.59845703812064)))`

WITHIN(geometry,POLYGON((36.0710334777832 32.59845703812064, 36.13574981689453 32.59845703812064, 36.13574981689453 32.633592568907005, 36.0710334777832 32.633592568907005, 36.0710334777832 32.59845703812064)))

DISJOINT(geometry,POLYGON((34.73876953125 34.53823752729575, 37.825927734375 31.835565983656224, 38.72680664062501 34.06631196472105, 34.73876953125 34.53823752729575)))

Non spatial predicates examples, CQL filter first, followed by a full URL-encoded API request:

class=’landuse’

class like '%land%T'

Temporal predicates examples:

BEFORE 2020-03-03`

AFTER 2016-03-03

Logical Operators examples:

INTERSECTS(geometry,POLYGON((35.9 32.7,36 32.7,36 32.8,35.9 32.8,35.9 32.7))) AND class='swamp'

11.2.3. Queryables

The following resource encodes queryables as a JSON document:

{
  "queryables": [
    {
      "id": "wkb_geometry",
      "type": "geometry"
    },
    {
      "id": "event_id_no_cnty",
      "type": "string"
    },
    {
      "id": "event_date",
      "type": "date"
    },
    {
      "id": "sub_event_type",
      "type": "string"
    },
    {
      "id": "actor2",
      "type": "string"
    },
    {
      "id": "ogc_fid",
      "type": ""
    },
    {
      "id": "data_id",
      "type": "string"
    },
    {
      "id": "event_type",
      "type": "string"
    },
    {
      "id": "region",
      "type": "string"
    },
    {
      "id": "notes",
      "type": "string"
    },
    {
      "id": "interaction",
      "type": "string"
    },
    {
      "id": "source",
      "type": "string"
    },
    {
      "id": "admin3",
      "type": "string"
    },
    {
      "id": "location",
      "type": "string"
    },
    {
      "id": "event_id_cnty",
      "type": "string"
    },
    {
      "id": "actor1",
      "type": "string"
    },
    {
      "id": "country",
      "type": "string"
    },
    {
      "id": "admin1",
      "type": "string"
    },
    {
      "id": "admin2",
      "type": "string"
    }
  ]
}

11.3. interactive instruments D101 Features, Tiles and Styles API

11.3.1. The starting point

At the beginning of the OGC Vector Tiles Pilot Phase 2 initiative, the open-source tool ldproxy implemented the following capabilities that were the basis for the work in the pilot:

  • OGC API - Features - Part 1: Core: The following conformance classes were used in the pilot: Core, HTML, GeoJSON, OpenAPI 3.0. ldproxy was the first OGC Reference Implementation for the standard.

  • OGC API - Features - Part 2: Coordinate Reference Systems by Reference: The latest draft (the public review started during the pilot).

  • OGC API - Tiles: The following conformance classes of the latest draft were used in the pilot: Core, Tile Matrix Set, Tiles from more than one collection. Mapbox Vector Tiles and GeoJSON tiles were supported.

  • OGC API - Styles: The following conformance classes of the latest draft were used in the pilot: Core, Resources, HTML, Mapbox Styles, Style Info, Queryables.

  • A query parameter "properties" on all tile and feature resources to return only the selected properties in the response.

For the demonstration server, a test dataset with data from OpenStreetMap from the region of Daraa, Syria, converted to the Topographic Data Store (TDS) schema of NGA was used.

The following screenshots of the HTML view of the API resources illustrate the starting point for the work in the pilot. The HTML view is a rendering of the JSON content that was also available for each resource.

ii 00 landing page
Figure 5. interactive instruments - the landing page of the API
ii 01 collections
Figure 6. interactive instruments - the collections (feature types) in the dataset

For filtering, knowledge about the available properties for use in filter predicates is important. These were published as a separate resource for each collection, in the following screenshot for the Transportation (Ground) features with a line string geometry.

ii 01 queryables
Figure 7. interactive instruments - queryable properties for the Transportation (Ground) features with line string geometry

To illustrate the data, here is a screenshot of a road feature:

ii 01 road feature
Figure 8. interactive instruments - a road feature

The following code snippet is the same feature in GeoJSON (coordinates have been truncated):

Listing 3. interactive instruments - a road feature in GeoJSON
{
   "type":"Feature",
   "links":[
      {
         "href":"https://services.interactive-instruments.de/t15/daraa/collections/TransportationGroundCrv/items/34?f=json",
         "rel":"self",
         "type":"application/geo+json",
         "title":"This document"
      },
      {
         "href":"https://services.interactive-instruments.de/t15/daraa/collections/TransportationGroundCrv/items/34?f=html",
         "rel":"alternate",
         "type":"text/html",
         "title":"This document as HTML"
      },
      {
         "href":"https://services.interactive-instruments.de/t15/daraa/collections/TransportationGroundCrv?f=json",
         "rel":"collection",
         "type":"application/json",
         "title":"The collection the feature belongs to"
      }
   ],
   "id":"34",
   "geometry":{
      "type":"MultiLineString",
      "coordinates":[ ... ]
   },
   "properties":{
      "F_CODE":"AP030",
      "ZI001_SDV":"2014-09-13T18:57:11Z",
      "ZI005_FNA":"No Information",
      "RTY":2,
      "RIN_ROI":3,
      "UFI":"86c0f5fe-4abd-4e0e-970a-feaf7e0ab314",
      "FCSUBTYPE":100152,
      "ZI006_MEM":"No Information",
      "ZI001_SDP":"No Information",
      "ZI016_WTC":1,
      "RIN_RTN":"No Information",
      "RLE":-999999,
      "LOC":-999999
   }
}

All features were also available as vector tiles, both for each individual collection and a single multi-layer tile set. The screenshot below shows the vector tiles of the Transportation (Ground) features in an OpenLayers map.

ii 07 single collection tiles
Figure 9. interactive instruments - Mapbox Vector Tiles for the Transportation (Ground) features in OpenLayers

11.3.2. Support for filters

Support for CQL filters was implemented in ldproxy and support for the query parameters filter and filter-lang was added to the following resources:

  • /collections/{collectionId}/items - to filter the features resources

  • /collections/{collectionId}/tiles - to filter the features in the vector tiles of a collection

  • /tiles - to filter the features in the multi-collection vector tiles

Both representations of CQL expressions were supported (cql-text for text, cql-json for hierarchical JSON).

Most of the CQL grammar was implemented, with a few limitations:

  • only the temporal operators specified in Filtering Tiles;

  • no existence operators, since their semantics is not well-defined (see Chapter 12);

  • no arithmetic expressions (add, subtract, multiply, divide).

Some examples for filters:

Fetch the agricultural area that contains a point

CQL:

CONTAINS(geometry,POINT(36.3544 32.4675))`

Features:

Fetch all other agricultural areas (not containing the point)

CQL:

DISJOINT(geometry,POINT(36.3544 32.4675))`

Features:

Fetch the agricultural areas in a polygon/bbox

CQL:

INTERSECTS(geometry,POLYGON( (35.9 32.7,36 32.7,36 32.8,35.9 32.8,35.9 32.7) ))`

Features:

Tile:

Fetch all the other agricultural areas

CQL:

DISJOINT(geometry,POLYGON( (35.9 32.7,36 32.7,36 32.8,35.9 32.8,35.9 32.7) ))`

Tile:

Fetch the major roads in the eastern part of the city that were updated since 2013; only return selected attributes

CQL:

INTERSECTS(geometry,POLYGON( (36.1 32.6,36.15 32.6,36.15 32.65,36.1 32.65,36.1 32.6) )) AND F_CODE='AP030' AND RIN_ROI<4 AND ZI001_SDV AFTER 2013-01-01

Features:

Tile:

Fetch the local roads in the eastern part of the city that were updated during 2011 or 2012; only return selected attributes

CQL:

INTERSECTS(geometry,POLYGON( (36.1 32.6,36.15 32.6,36.15 32.65,36.1 32.65,36.1 32.6) )) AND F_CODE='AP030' AND RIN_ROI<4 AND ZI001_SDV AFTER 2013-01-01

Features:

Tile:

Fetch the ground transportation features last updated on 12/31/2011 at 11:45:18 UTC

CQL:

ZI001_SDV TEQUALS 2011-12-31T11:45:18Z

Features:

In a filter on a multi-layer vector tile ldproxy applied the filter on each collection. This implied that the list of collections in the tile has to be restricted to a small set with shared queryables. Otherwise an error was returned since the predicate could not be evaluated for all layers/collections. This is discussed in more detail in Chapter 12.

Fetch a multi-layer tile with Transportation (Ground) curves and Agricultural surfaces updated since 06/05/2012

CQL:

ZI001_SDV AFTER 2012-06-05

Tile:

All the examples above used CQL in the Text variant. The following is a JSON example:

Fetch all Transportation (Ground) curves and Agricultural surfaces updated since 06/05/2012

CQL:

{"after":{"property":"ZI001_SDV","value":"2015-09-01"}}`

Features:

The API was also tested with the GeoSolutions client, where various filters were applied on the vector tiles of the Transportation (Ground) curves. The following are two screenshots of sample filters:

ii 08 TIE within
Figure 10. Filtering Transportation (Ground) curves using the GeoSolutions client (example 1)
ii 08 TIE disjoint
Figure 11. Filtering Transportation (Ground) curves using the GeoSolutions client (example 2)

11.4. GeoSolutions D102 OGC API - Tiles

GeoSolutions worked on a filtering extension for the existing GeoServer OGC API - Tiles. During the VTP2 activity, the implementations of OGC API - Tiles have been extended to advertise queryables for vector collections, as shown in the following screenshot.

geosolutions D102 queryables api
Figure 12. API has been extended with Queryables concept. The collectionId parameter lists only the names of collections actually exposing queryables.
geosolutions D102 queryableLayer
Figure 13. HTML representation for single layer vector collection, with links to the queryables, as well as map and data tiles.
geosolutions D102 queryables
Figure 14. HTML representation for the above layer queryeables (excerpt, the layer in question has 73 queryables).

Then, the "data tiles" endpoint has been extended to allow filtering by means of the filter and filter-lang parameters (the map tiles resource has been extended as well, but it’s out of scope for VTP2).

At the time of writing, the only allowed value for filter-lang is cql-text.

geosolutions D102 tiles api
Figure 15. HTML representation for the above layer queryeables (excerpt, the layer in question has 73 queryables).

The implementation of cql-text is based on GeoServer Extended CQL, providing a full set of filtering operators, as well as a comprehensive list of filter functions covering basic math, string and date handling, as well as geometry manipulation.

A sample filtered tile request follows, reformatted and URL decoded for readability:

  • https://vtp2.geo-solutions.it/geoserver/ogc/tiles/ (service base)

  • collections/vtp:TransportationGroundCrv/tiles/WebMercatorQuad/14/6618/9833? (single tile access)

  • filter=(RIN_ROI = '3') (the filter)

  • filter-lang=cql-text (filter language is CQL)

Various tile filtering visual examples are available in the GeoSolutions D104 client section.

11.5. Ecere D103 Features & OGC API - Tiles

Ecere developed capabilities for server-side filtering in its GNOSIS Map Server, and exposed it in both the OGC API - Features and OGC API - Tiles implementations. The implementation included support for comparison of attribute values, geometry intersection with a bounding box, as well as logical and arithmetic operations. The current implementation supports expressions as defined in CMSS, the native styling language of GNOSIS tools. Support is planned for the CQL filtering language, but a parser for it could not be implemented during the pilot. Filtering CMSS was made available instead.

The CMSS styling language was first proposed as an encoding for a styling conceptual model in OGC Testbed 14, and documented in the Portrayal, and CityGML and Augmented Reality (http://docs.opengeospatial.org/per/18-025.html#_expressions) Engineering Reports. CMSS expressions serve both for selectors, deciding whether to apply symbology rules, and for styling property values within symbolizers. Just like with selectors, the expressions used for filtering resolve to a single boolean value, if the value is true then the feature is included in the results.

The syntax for CMSS expressions is mostly compatible with the eC programming language, a superset of the C language adding support for object orientation, as well as with ECON (eC Object Notation). Like the bitwise C operator, the symbol | represents an OR logical operation, while & represents AND. However, textual 'or' and 'and' are also supported. Negation is represented by the ! operator, and inequality by !=.

11.5.1. Examples of filtering expressions used with the OGC API - Features

From Natural Earth countries, return only features whose name property is either Canada or United States:

CMSS Expression: name = 'Canada' | name = 'United States'

Encoded filtered request URL:

ecere items1
Figure 16. Filtering country features by name

From Daraa OpenStreetMap / Topographic Data Store’s ground transportation linear features, return only those whose name property (ZI005_FNA) is not No Information:

CMSS Expression: ZI005_FNA != 'No Information'

Encoded filtered request URL:

ecere items2
Figure 17. Filtering out road features with name set to 'No Information'

CMSS currently does not feature full regular expressions, but supports the text comparison operators: Contains (~), Begins with (^) and Ends with ($).

From Natural Earth countries, return only features whose name property contains ain:

CMSS Expression: name ~ 'ain'

Encoded filtered request URL:

ecere items3
Figure 18. Filtering country features whose names contain a sub-string

From Natural Earth countries, return only features whose estimated population (pop_est) property is greater than 50 million:

CMSS Expression: pop_est > 50M

Encoded filtered request URL:

ecere items4
Figure 19. Filtering out country features below a population threshold

The 'intersects' function was implemented to check intersection with geometry.

Currently, only support for checking intersection between a record’s geometry and a bounding box (specified as { { south latitude, west longitude }, { north latitude, east longitude } }) has been implemented.

From Natural Earth countries, return only features whose continent property is Anctarctica, or whose geometry intersects with a bounding box around 45°N, 75°W:

CMSS Expression: continent = 'Antarctica' | intersects(rec.geom, { { 45, -75 }, { 45.01, -74.99 } })

Encoded filtered request URL:

ecere items5
Figure 20. Filtering out features whose geometry lies outside of a bounding box

 
Support for lyr.geom to test whether any of the layers geometries intersect with each other, is also planned, as this might be useful for complex styling scenarios with special rules for overlapping geometry.

11.5.2. Use of filtering for vector tiles

Allowing clients requesting vector tiles to specify custom filters can reduce bandwidth and processing requirements, providing a flexible mechanism to make the same data suitable for different purposes and styles. Spatial operations may be less useful in conjunction with tiles, which already limit the response to a specific spatial extent, but are still available in the OGC API - Tiles for consistency.

Examples of filtering expressions used with the OGC API - Tiles

From Natural Earth countries, return a MapBox vector tile containing only features whose name property is either Canada or United States. Use the WebMercatorQuad tile matrix set, zoom level 0, row 0, column 0.

CMSS Expression: name = 'Canada' | name = 'United States'

Encoded filtered request URL:

ecere tile1
Figure 21. Filtering country features by name from a tile request

From Daraa OpenStreetMap / Topographic Data Store’s ground transportation linear features, return only those whose name property ZI005_FNA is not No Information. Use the WebMercatorQuad tile matrix set, zoom level 9, row 206, column 307.

CMSS Expression: ZI005_FNA != 'No Information'

Encoded filtered request URL:

ecere tile2
Figure 22. Filtering out road features with name set to 'No Information' from a tile request

11.5.3. Multi-layer and scale-based filtering (OGC API - Tiles)

The ability to select which layers to include inside multi-layer tiles also helps to reduce the size of produced tiles. CMSS already supported simple expressions as enclosed in a single selector within square brackets or being assigned to a property In addition, the syntax has been extended to include one or more selectors enclosed within square brackets, as well as a layer identifier selector prefixed by the # symbol. This syntax mirrors the full CMSS syntax as used for styling, but excludes the symbolizer and nested rules enclosed in curly braces which normally follow these selectors. Alternatively, the pre-defined lyr.id expression can be compared with a string literal, and used in conjunction with an or operation to match multiple layers. Additional selectors can be combined with and operations, with operands contained within parentheses.

Multi-layer filtering is particularly useful in conjunction with a scale-based selector, making it possible to re-use the same tiles template for all zoom levels.

CMSS pre-defines the viz.sd expression to refer to the scale denominator. In the context of the OGC API - Tiles filtering, it represents the scale denominator associated with a specific zoom level (tile matrix) being requested. The scale denominators associated with each zoom level of a tile matrix set are well-defined by the OGC Tile Matrix Standard, and tile matrix sets defined following this specification, according to a standard 0.28 mm/pixel equivalence. Referencing a scale denominator rather than a zoom level ensures that a filter or style is re-usable between different tile matrix sets where zoom levels correspond to different scales.

Examples of multi-layer and scale-based filtering

This section contains a number of examples, each one composed of:

  • A statement explaining the desired filtering

  • The equivalent URL retrieving the vector tiles matching the filter

  • A figure showing the result, visually.


From Daraa OpenStreetMap / Topographic Data Store, retrieve all features of the agriculture polygons layer (AgricultureSrf) and of the settlement polygons layer (SettlementSrf). Use the WebMercatorQuad tile matrix set, zoom level 8, row 103, column 153.

CMSS Expression (using selectors syntax): #AgricultureSrf#SettlementSrf

Encoded filtered request URL:

ecere tile3
Figure 23. Multi-layer filter to only include specific layers

From Daraa OpenStreetMap / Topographic Data Store, retrieve:

  • All features of the agriculture polygons layer (AgricultureSrf).

  • All features of the settlement polygons layer (SettlementSrf).

  • All features of the ground transportation linear features whose name property ZI005_FNA is not No Information.

  • All features of the culture points layer (CulturePnt), but only for zoom levels more detailed than 1:2,000,000 scale.

Use the WebMercatorQuad tile matrix set, zoom level '0', row 206, column 307.

CMSS Expression (using selectors syntax):

#AgricultureSrf #SettlementSrf #TransportationGroundCrv[ZI005_FNA != 'No Information'] #CulturePnt[viz.sd < 2M]`

Encoded filtered request URL:

ecere tile4
Figure 24. Complex multi-layer filter combining layer selection, name attribute condition and scale-based filtering

 
If the same filter is used for WebMercatorQuad zoom level 8 (scale is 1:2,183,915), the culture points, which were included at level 9, will be omitted:

ecere tile5
Figure 25. Identical multi-layer filter used at a different zoom level, showing the culture point features omitted

 
An equivalent expression not using the selectors syntax could be written as:

CMSS Expression (not using selectors):

( lyr.id = 'AgricultureSrf' or lyr.id = 'SettlementSrf' or (lyr.id = 'TransportationGroundCrv' and ZI005_FNA != 'No Information') or (lyr.id = 'CulturePnt' and viz.sd < 2M) )`

Encoded filtered request URL:


From the OpenStreetMap dataset of Washington, D.C., return all features from natural, waterways, railways, landuse, other areas, other lines, boundaries, roads, buildings and amenities layers. Use the WorldMercatorWGS84Quad tile matrix set, zoom level 10, row 392, column 293.

CMSS Expression:

#natural #waterways #railways #landuse #otherAreas #otherLines #boundaries #roads #buildings #amenities

Encoded filtered request URL:

ecere tile6
Figure 26. An OpenStreetMap tile requested with a filter to omit layers with large number of points

 
As a comparison, the same tile without a filter would include an extra 7000 points for the house numbers layer and 3000 for other points, each point containing attribute information, resulting in a particularly big tile for that scale:

ecere tile7
Figure 27. The same OpenStreetMap tile requested without the filter, showing the large number of points

11.5.4. POST requests to the OGC API - Tiles

A client would often make numerous requests for tiles using the same filter, especially when using multi-layer tiles and scale-based filtering. These filters may also be complex, which might pose problems to encode them entirely as a URL query parameter. As an alternative, Ecere considered using a POST request to an OGC API - Tiles end-point, whose content would be the filter expression. The response to this request would be a templated URL corresponding to the filter, which would not be a public resource, but potentially only available to a client having made that request. This would allow the server to only parse and process the filtering expression once, and may facilitate the configuration and/or caching of the tiles. A URL template returned this way might expire after a certain time of no tile request coming in, at which point the client would need to re-submit the template again to obtain a new valid template. Such a POST request could also be used with the OGC API - Tiles to specify complex multi-layer input data layers, styles, and even daisy-chained processing workflows. This approach was discussed and presented at the January 2020 OGC Coverage & Analytics Code Sprint.

As an example, a client could potentially submit a POST request to this URL (or an alternative version including a more complex filter in the payload):

and the server would return a templated link which may look like:

When a client accesses a tile using that template, the requested filter would be included in the tile result calculation.

11.5.5. Filtering driven by styles

For visualization use cases, filters may be tightly coupled with the styles displaying the data. Thus, the server could automatically determine the proper filter from the referenced style (from an associated Styles API), or by the client posting a complete style (e.g. encoded as CMSS, SLD/SE or Mapbox GL). In order to turn an encoded style into a filter, the service would filter out any geometry not being drawn. For example, in the case of CMSS (where everything is drawn by default, even without a style), the decision would be based on properties such as visibility, opacity, and label/marker. The server could also, optionally, omit any attribute information not useful for that style.

11.5.6. Retrieving attributes separately from geometry

In the GNOSIS Map Tiles encoding of vector tiles, attributes are not included in the result (in the GNOSIS Data Store, they are stored separately in a SQLite file, along with a spatial index). Currently, when the GNOSIS Client requests tiles as GNOSIS Map Tiles from the GNOSIS Map Server, the attributes are requested on demand separately, for the specific properties and features required. The request uses the query parameters featureid to specify which features to include, and properties to specify which properties to include.

In addition to being useful for vector tiles encodings formats not defining attribute, requesting the attributes separately can greatly reduce the size of the data to transmit, especially for large detailed features, spread across multiple tiles, having numerous associated attributes.

11.5.7. CMSS Expressions Syntax

A summary of the CMSS expression syntax is presented here. See the CityGML and Augmented Reality Engineering Report for a more detailed overview of CMSS as a styling language.

Types of expressions

type

example

identifier

FEATCODE

text

'Parking'

integer

10

real

3.14159

object

{ hour = 16, minutes = 30 }
Circle { radius = 5 }

member

viz.sd

list

[1, 2, 3]

operation

viz.sd > 10M

variable

@colorScheme

Types of identifiers
id or example description

F_CODE

Example of a data attribute

null

Unset value

true

Example of an enumeration value

lyr

The data layer (collection)

lyr.id

Identifier for the layer

lyr.fc

Feature class (e.g. vector, coverage, imagery)

lyr.vt

Vector type (e.g. points, lines, polygons)

lyr.geom

Layer geometry

viz

Visualization attributes

viz.sd

Scale denominator

viz.time

Visualization time

viz.date

Visualization date

viz.timeOfDay

Visualization time of day

rec

The record

rec.id

Record id

rec.geom

Record geometry

records

List of all records in the layer

Operators

Logical

AND (&), OR (|), NOT (!)

Comparison

Equal (=), Not equal (!=), Greater (>), Lesser than (<), Greater or Equal (>=), Lesser or Equal (\<\=)

Text Comparison

Contains (~), Starts with (^), Ends with ($), does not contain (!~), does not start with (!^), does not end with (!$)

Arithmetic

Addition (+), Subtraction (-), Multiplication (*), Division (/), Integer division (div), Remainder (%)

Priority

parentheses () for prioritizing

Conditional

if ? then : else

in

'in' to check if left-side expression is within a list

Function call

()

Functions

Text manipulation

strlwr, strupr, format, subst

implemented

Geometry operation

area, length, centroid

not yet implemented

Spatial operations

intersects, contains, within, withinRadius…​

only intersects(rec.geom, bbox) implemented

Iteration

to iterate within a list as part of an expression —  
thought of as an exercise for rules based on overlapping features
e.g. [featcode = 'bay' & iterate(or, records, it.featcode = 'ocean' & intersects(it, rec.geom))]

not yet implemented

For temporal support, time attributes can be compared against either visualization attributes (e.g. viz.time) or fixed time values.

11.6. Ecere D105 Client

Ecere provided a client able to visualize tiled vector features served by OGC API - Tiles, based on its GNOSIS Cartographer application. The client can apply styles, whether loaded locally, created using the visual style editing interface, or accessed via the Styles API. Features were automatically filtered based on the style in use, however filtering was still applied on the client side. As discussed in the server section, a filter can automatically be determined from a style, by considering its selectors and visualization properties such as opacity and visibility. The client could either reference a style, or POST a style to the service to specifically ask for pre-filtered geometry and attributes based on that style. Alternatively, the client could itself have determined a filter suitable for the style in use, and submit such filter in its service requests. That capability was planned but was not yet implemented during the pilot. A disadvantage of requesting pre-filtered tiles, rather than doing the filtering on the client side, is that the client would need to discard tiles and retrieve a different version when changing between styles.

ecere client
Figure 28. A screenshot of GNOSIS Cartographer showcasing the styling rules which could be used to automatically determine a filter

11.7. Ecere D107 GeoPackage producer & client

Ecere produced a number of GeoPackages for the pilot, as well as a client capable of visualizing GeoPackages produced by other participants. These GeoPackages produced using Ecere’s GNOSIS Cartographer tool made use of the "Attributes Tables" extension, which is also supported by the visualization client. This extension is useful for performing filtering when the client accesses the tile data (e.g. accessing fewer encoded tile blobs based on SQL queries). This optimization was not yet implemented in the client during the pilot. The attributes table extension also greatly reduced the size of GeoPackages compared to embedding attributes within the tiles themselves, and provided fast access to querying or updating the attribute information for a given feature. A filter could also be applied when generating a GeoPackage to minimize its size, but this capability has not yet been implemented either. See the GeoPackage section for more details, and an explanation of the SQL queries pictured below.

ecere geopackage
Figure 29. SQL queries performed at an SQLite prompt inside a multi-layer WorldMercator GeoPackage produced by Ecere, which could be used for filtering

11.8. Skymantics D104 Client

Skymantics selected Unity to develop a map client with augmented reality capabilities. This software was combined with Mapbox SDK and Mapbox Studio to provide a framework for map utilization.

11.8.1. Challenges Encountered

The implementation of filters within these software applications presented the following challenges:

  • Unity allows the creation of C# scripts that could be used to command filtering and styling over maps generated on Unity. When generating maps with Mapbox SDK and Mapbox Studio, the actual rendering of the map is encapsulated by Mapbox SDK and therefore the Unity C# scripts have no power over the maps.

  • Mapbox SDK does not allow Unity to interact with the filtering and styling tools found on Mapbox Studio. All those tools must be used manually in the Mapbox Studio application.

  • Vector tile data can only be uploaded to Mapbox Studio as a dataset or a tile set, therefore discarding any possibility of CQL filtering in Mapbox Studio.

  • Since the tile sets were fetched from the tile servers before being stored in files and afterwards loaded into Mapbox Studio, a CQL filter could have indeed been added to the GET requests. This approach would have been impractical for end users because it was impossible to command from Unity the automatic fetch of tile sets, the upload of those tile sets into Mapbox Studio and the render in Unity of the updated filtered map.

11.8.2. Filtering Within Unity and Mapbox Studio

In order to provide filtering support, Skymantics loaded, styled and filtered tilesets in Mapbox Studio, and finally made those styled and filtered tilesets available in Unity.

Mapbox provides their own filtering tools within the Mapbox Studio environment. In the Mapbox Style Specification, a filter is a property at the layer level that determines which features should be rendered in a style layer. Filters are written as expressions, which give you fine-grained control over which features to include: the style layer only displays the features that match the filter condition that you define.

Mapbox Studio allows users to create styles by adding multiple features to them. Entire tile sets, comprising one or several layers, can be added to a style, therefore creating a Mapbox style made up of a single or multiple layers. As shown on Figure 30, an Agriculture tile set and a Hydrography tile set were loaded into a single style as two separate layers; Agriculture was defined by the color green and Hydrography as dark blue.

Mapbpox Studio features a variety of filtering and styling tools. Once the layers have been added to a style, these tools can be applied to the style. In Figure 30, a filter based on values is being applied to a style in Mapbox Studio.

The final step of the process is to load the style into Unity. Mapbox Studio makes the styles created by the user available through a URL that is called by the Mapbox SDK in Unity. As seen in Figure 32, the URL is loaded into Unity and the style is automatically rendered, as previously visualized in Mapbox Studio. When compiled and executed as a mobile application, the map is rendered exactly as visualized in Unity.

skymantics client D104 layer selection
Figure 30. Style created in Mapbox Studio comprising two layers.
skymantics client D104 filtering
Figure 31. Filter being applied to a style in Mapbox Studio.
skymantics client D104 unity
Figure 32. Style URL loaded and map rendered in Unity.

11.8.3. Future Work

The filtering approach implemented in this Pilot had the disadvantage of providing a static solution to filtering because, since the tilesets had to be pre-styled and pre-filtered in Mapbox Studio before making them available in Unity, an end user would not be able to dynamically apply filters or styles while using the mobile application.

This approach could be further expanded by anticipating in advance a large number of combinations of layers, styles, and filters that an end user would be requiring, and making them easily available in the augmented reality mobile application. One Mapbox style per each combination would be created in Mapbox Studio, and made available in Unity by means of individual scenes the end user would select in the mobile app. Each Unity scene would access a specific Mapbox style URL previously created.

In order to provide end users with full filtering capabilities while using the augmented-reality mobile application, maps should be entirely generated in Unity without utilizing Mapbox SDK nor Mapbox Studio. A custom slippy map would need to be created in Unity, and control buttons would command C# scripts that effectively filter and style the map being rendered. This approach was indeed considered, but the workload involved would not fit the time limits of the Pilot.

11.9. GeoSolutions D104 Client

The deliverable implemented for the vector tile client was a web application built with MapStore, an open source web-based Geographic Information System (GIS) framework.

The following components show a complete filtering workflow:

  • Layers panel to list all the layers added to the map and also to provide layer related tools

  • filter builder panel to apply attribute, temporal or spatial filters to a selected layer (it was available only after selecting a layer in the list).

  • Map to render and support OGC vector tiles layers.

  • Catalog panel to display all layers available on an OGC API service where each card represents a collection that could be displayed on map.

geosolutions client D104 client steps
Figure 33. MapStore client with steps to activate the filter builder: add collection from an OGC API - Tiles server (right box), select collection and enable filter panel (top left box) and interact with the filter builder (bottom left box)

The filter created by the Filter Builder component was a CQL filter directly included in the tiles request, as query parameter. The client thus expected to get server-side filtered tiles.

The Transportation Ground Curve layer was used to test TIEs.

geosolutions client D104 filter polygon
Figure 34. Transportation Ground Curve layer without filters and highlighted the polygon used in the spatial filter

Below are some screenshots of filters applied to different services using the same layers.

11.9.1. Attribute filter

CQL Filter:

(RIN_ROI = '3')

Result:

geosolutions client D104 attribute filter
Figure 35. MapStore client with attribute filter applied to Transportation Ground Curve layer from different services: GeoSolutions (left), Interactive Instruments (top right) and Terranodo (bottom right)

11.9.2. Spatial filter

CQL Filter:

(WITHIN(geometry,POLYGON((36.08639717102051 32.605362330628395, 36.116266250610344 32.605362330628395, 36.116266250610344 32.625532858348336, 36.08639717102051 32.625532858348336, 36.08639717102051 32.605362330628395))))

Result:

geosolutions client D104 within filter
Figure 36. MapStore client with WITHIN spatial filter applied to Transportation Ground Curve layer from different services: GeoSolutions (left), Interactive Instruments (top right) and Terranodo (bottom right)

CQL Filter:

(DISJOINT(geometry,POLYGON((36.08639717102051 32.605362330628395, 36.116266250610344 32.605362330628395, 36.116266250610344 32.625532858348336, 36.08639717102051 32.625532858348336, 36.08639717102051 32.605362330628395))))

Result:

geosolutions client D104 disjoint filter
Figure 37. MapStore client with DISJOINT spatial filter applied to Transportation Ground Curve layer from different services: GeoSolutions (left), Interactive Instruments (top right) and Terranodo (bottom right)

11.9.3. Temporal filter

CQL Filter:

(ZI001_SDV AFTER 2014-01-01T00:00:00.000Z)

Result:

geosolutions client D104 after filter
Figure 38. MapStore client with AFTER temporal filter applied to Transportation Ground Curve layer from different services: GeoSolutions (top) and Interactive Instruments (bottom)

11.9.4. Mixed filters

CQL Filter:

(RIN_ROI = '3') AND (WITHIN(geom,POLYGON((36.06425285339356 32.59450435638428, 36.122875213623054 32.59450435638428, 36.122875213623054 32.65407085418701, 36.06425285339356 32.65407085418701, 36.06425285339356 32.59450435638428))))

Result:

geosolutions client D104 mix filters
Figure 39. MapStore client with attribute and spatial filters applied to Transportation Ground Curve layer from different services: GeoSolutions (left), Interactive Instruments (top right) and Terranodo (bottom right)
Note
Terranodo server used a different dataset so the attribute filter applied was (type='trunk' OR type='primary') instead of (RIN_ROI = '3')

12. Results and findings

12.1. Issues Encountered

12.1.1. CQL language issues

During the development and tests of CQL parsers the following issues were raised.

12.1.2. Quoted identifiers

In the original CQL it’s possible to double quote an identifier to avoid conflicts with reserved words and issues with special characters being part of the names.

The current draft OGC API - Features CQL extension BNF does not contain such support, it was suggested to add it back.

12.1.3. ENVELOPE constructor

An issue was found with the ENVELOPE construct, used to express rectangular geometries and used in spatial filters. In particular, the axis order in the BNF uses a west, east, north, south convention, not used in other OGC protocols.

Discussion is ongoing about possibly replacing the ENVELOPE construct with a simpler BBOX spatial filter operator.

12.1.4. EXISTS operator

The catalog specification is not clear about the meaning of the EXISTS operator, in particular, on whether the property being checked has a value, or not, or whether it is present in the schema of the data itself. For schemaless datasets, it may not even be possible to tell apart the two situations.

12.2. Findings

This section collects the findings of the Pilot activity.

12.2.1. Client-side versus Server-side filtering

A recurring topic in the Pilot was the component executing the filters. Two sides are considered:

  • Server-side, during the production of the tiles or the GeoPackage.

  • Client-side, while using the tiles.

It is to be noted that it makes sense to speak of a "filtering language" in the context of an API request, while working client-side the filtering will depend on the data delivered and the tools used to read it. A few examples follow:

  • In the case of a Mapbox Vector Tiles or GeoJSON file, the client-side library will often provide programmatic filtering abilities in the language of choice (e.g., JavaScript)

  • In the case of a GeoPackage, the client will perform filtering either directly in SQL, if attributes are available, or programmatically, after parsing the vector tiles, if the attributes are still encoded as part of the tile body.

The side where filtering is applied has significant consequences, with dual benefits/drawbacks:

  • When filtering server-side, tiles size can be reduced significantly, an important factor when delivering large, multi-scale datasets like, for example, OpenStreetMap (global coverage is currently over 50GB when delivered as a PBF, and for reference, over 300GB when imported in PostgreSQL). Conversely, providing filters from the client reduces the server ability to cache tiles, and disallows implementation of static tile servers.

  • When filtering client-side, server-side tiles are built once and cached.

A possible compromise could be to have server-side filtering as a base, intended to serve the majority of clients and offering tiles that are small enough for general use, while allowing client specified filters on top of it, to further reduce the size of the tiles. Among the implementations in this pilot at least one, GeoSolutions’s GeoServer, works using this approach.

12.2.2. Client-side control of contents and default filtering

The typical vector tiles delivery mechanisms available today assume that all filtering has to be done on the server-side in advance, taking into account multiple factors:

  • Data density, avoiding layers that would have too dense data for the current zoom level.

  • Common styling needs, removing attributes that are typically not used in client-side styles, and that are not often needed for "info" displays.

  • Data generalization based on the zoom level, considering multiple approaches, such as geometry simplification, union, selection based on importance.

This helps keep the vector tiles small compared to a server-side rendered equivalent, while still allowing the client to have some latitude in rendering and eventual client-side filtering.

Allowing the client to provide filters and projections to the server-side allows for other avenues.

For multi-layer base maps, a complex configuration is needed server-side, reporting for each layer:

  • The range of visibility, removing the layer at certain zoom levels, be it because it is spatially too dense, or not enough.

  • The desired filtering on a zoom level by zoom level basis (e.g., including only highways at low zoom levels, while providing the entire data set at higher ones).

  • Switching between different data sources depending on the zoom level (to leverage previous generalization work that might have simplified geometries, collapsed them, or simple pre-filtered them for performance reasons)

  • The desired set of attributes, which will vary depending on the intended application.

This kind of configuration is better performed server-side and would be the driver for an eventual advance seeding of the tiles. Trying to apply it on the client-side would require either:

  • A large configuration document to be sent along each request.

  • The creation of a stateful configuration, similar in principle to Stored Queries, that the client would then refer to by id, in subsequent tile requests.

Overlay layers can instead use a more dynamic filtering, provided the client as a query parameter in tile requests, depending on the current needs.

12.2.3. Filter capabilities and desired minimum filtering operator set

Regardless of the specific filter language encoding, filtering languages include a rich set of operators. This rich set helps expressiveness, but can hinder the implementation of the parser and filter engine.

It is thus desirable to advertise the capabilities of the filtering engine, allowing the implementation of a sub-set of filters.

Within the confines of VTP2 no capabilities mechanism has been mandated, instead, a minimum set of filters has been agreed upon among implementors, thereby providing a suitable balance between filter expressiveness and ease of implementation.

12.3. Recommendations

12.3.1. CQL CRS geometry support

CQL currently supports geometry literals without any specification of their coordinate reference system. The VTP2 participants recommend adding explicit support for it, either in the CQL own syntax, or as a separate request parameter.

The syntax embedding would allow for a freer form expression of filters, with a potential to have multiple spatial filters using different coordinate reference system literals.

The separate request parameter would instead imply that all literals in the filter are expressed in the same CRS. It would be however simpler to implement, and more in line with the bbox-crs request parameter already suggested in the OGC API - Features CRS extension.

12.3.2. Filter capabilities support

A mechanism to advertise the set of supported filtering operators is needed, in order to avoid un-necessary implementation efforts of servers-side, while allowing clients to determine which subset of filters is supported.

Ideally, this should be part of the OGC API - Features filtering extension.

12.3.3. Support for complex filtering

The current support for filters as query parameters in GET requests is simple, well suited for link sharing, and generally well understood.

However, there are evident situations where it would stop working due to practical URL length limits:

  • Spatial filters with long, elaborate geometries

  • Complex filters combining many conditions

  • Filters including manually chosen/removed features, by identifier

  • Multi-layer filters scenarios, where more than one filter needs to be specified.

A mechanism to support these use cases should be developed, e.g., stateless POST requests in form-urlencoded format using the same parameters, or stateful POST requests creating of stored queries that may be referred to using a filter identifier.

12.4. Future work

12.4.1. Selection of returned attributes

While the filtering allows to reduce the number of returned items, it does not support reducing the number of attributes returned along with each item.

Developing such support would require:

  • Advertising a list of "returnable" properties, structurally similar to the queryables, but with a different purpose.

  • Adding request parameters to support the property selection.

Similarly to filters, the selection of properties could lead to excessively long URLs, requiring usage of the POST method to carry the request.

In this context, a full-fledged JSON based filtering and property selection (querying) support could be developed too.

12.4.2. JSON based filtering languages

While VTP2 experimented with CQL-text, there is an evident desire for a JSON based filtering language. The language can be functionally equivalent, while the JSON structure would remove the need for a full-fledged text parser.

The encoding would find its natural position in larger JSON documents, while also being useful in allowing quicker implementation of servers, and on the client-side as well, when filters are built programmatically through graphical user interfaces, rather than directly entered into a text box.

12.4.3. Explore multi-layer tile filtering and querying support

As noted in the Single and multi-layer filtering section, and with the exception of the Ecere Tiles API implementation (see Section 11.5), this pilot focused on filtering single-layer tiles.

Multi-layer tiles filtering has been marked as a future-work item. In particular, in order to support multi-layer tiles filtering the following topics need to be researched in greater depth:

  • Expressing a short list of filters in GET requests, eventually as a cql-text grammar extension.

  • Expressing list of filters not fitting the practical length of a URL as a POST request (possibly in combination with multi-collection download extension for the OGC Features API)

  • Advertising queryables of a multi-layer vector tiles dataset outside of the OGC API - Features tile building blocks applications, for example, in a standalone OGC API - Tile implementation.

Appendix A: CQL BNF

The BNF describes the syntax of the CQL text language, in its full form (not limited to the subset of operators showcased in the Vector Tiles Pilot 2).

#
# MODULE:  cql.bnf
# PURPOSE: A BNF grammar for the Common Query Language (CQL).
# HISTORY:
# DATE         EMAIL                     DESCRIPTION
# 13-SEP-2019  pvretano[at]cubewerx.com  Initial creation
# 28-OCT-2019  pvretano[at]cubewerx.com  Initial checkin into github.
#

#=============================================================================#
# A CQL filter is a logically connected expression of one or more predicates.
#=============================================================================#
cqlFilter = booleanValueExpression;

booleanValueExpression = booleanTerm | booleanValueExpression "OR" booleanTerm;

booleanTerm = booleanFactor | booleanTerm "AND" booleanFactor;

booleanFactor = ["NOT"] booleanPrimary;

booleanPrimary = predicate
| leftParen cqlFilter rightParen;

#=============================================================================#
#  CQL supports scalar, spatial, temporal and existence predicates.
#=============================================================================#
predicate = comparisonPredicate
          | spatialPredicate
          | temporalPredicate
          | existencePredicate
          | inPredicate;

#=============================================================================#
# A comparison predicate evaluates if two scalar expression statisfy the
# specified comparison operator.  The comparion operators include an operator
# to evaluate regular expressions (LIKE), a range evaluation operator and
# an operator to test if a scalar expression is NULL or not.
#=============================================================================#
comparisonPredicate = binaryComparisonPredicate
                    | propertyIsLikePredicate
                    | propertyIsBetweenPredicate
                    | propertyIsNullPredicate;

binaryComparisonPredicate = scalarExpression comparisonOperator scalarExpression;

propertyIsLikePredicate =  scalarExpression "LIKE" regularExpression;

propertyIsBetweenPredicate = scalarExpression "BETWEEN"
scalarExpression "AND" scalarExpression;

propertyIsNullPredicate = scalarExpression "IS" ["NOT"] "NULL";

#
# A scalar expression is the property name, a chracter literal, a numeric
# literal or a function/method invocation that returns a scalar value.
#
scalarExpression = propertyName
| characterLiteral
| numericLiteral
| function
| arithmeticExpression;

# NOTE: This is just a place holder for a regular expression
#       We want to be able to say stuff like "<prop> LIKE 'Toronto%'" where
#       the '%' character means "match zero or more characters".
regularExpression = characterLiteral;

comparisonOperator = eq | neq | lt | gt | lteq | gteq;

neq = lt gt;

gteq = gt eq;

lteq = lt eq;

#=============================================================================#
# A spatial predicate evaluates if two spatial expressions satisfy the
# specified spatial operator.
#=============================================================================#
spatialPredicate =  spatialOperator leftParen geomExpression comma geomExpression rightParen;

# NOTE: The buffer operators (DWITHIN and BEYOND) are not included because
#       these are outside the scope of a "simple" core for CQL.  These
#       can be added as extensions.
#
spatialOperator = "EQUALS" | "DISJOINT" | "TOUCHES" | "WITHIN" | "OVERLAPS"
| "CROSSES" | "INTERSECTS" | "CONTAINS";

# A geometric expression is a property name of a geometry-valued property,
# a geometric literal (expressed as WKT) or a function that returns a
# geometric value.
#
geomExpression = propertyName
| geomLiteral
| function;

#=============================================================================#
# A temporal predicate evaluates if two temporal expressions satisfy the
# specified temporal operator.
#=============================================================================#
temporalPredicate = temporalExpression temporalOperator
temporalExpression [temporalExpression];

temporalExpression = propertyName
| temporalLiteral
| function;

temporalOperator = "AFTER" | "BEFORE" | "BEGINS" | "BEGUNBY" | "TCONTAINS"
| "DURING" | "ENDEDBY" | "ENDS" | "TEQUALS" | "MEETS"
| "METBY" | "TOVERLAPS" | "OVERLAPPEDBY" | "ANYINTERACTS"
| "INTERSECTS";

#=============================================================================#
# The existence predicate evalues whether the specified property exists
# in the current context. This predicate was added to accomodate the fact
# that OAPIF feature collections (and likely other specification) are
# heterogeneous with respect to schema.
#=============================================================================#
existencePredicate = propertyName "EXISTS"
                   | propertyName "DOES" "NOT" "EXIST";

#=============================================================================#
# The IN predicate
#=============================================================================#
inPredicate = propertyName "IN" leftParen { characterLiteral |
                                            numericLiteral |
                                            geomLiteral |
                                            temporalLiteral |
                                            function } rightParen;

#=============================================================================#
# Definition of a FUNCTION
# NOTE: How do we advertise which functions an implementation offer?
#       In the OpenAPI document I suppose!
#=============================================================================#
function = identifier {argumentList};

argumentList = leftParen [positionalArgument]  rightParen;

positionalArgument = argument [ { comma argument } ];

argument = characterLiteral
| numericLiteral
| geomLiteral
| propertyName
| arithmeticExpression;

#=============================================================================#
# An arithemtic expression is an expression composed of an arithmetic
# operand (a property name, a number or a function that returns a number),
# an arithmetic operators (+,-,*,/) and another arithmetic operand.
#=============================================================================#
arithmeticExpression = arithmeticOperand arithmeticOperator arithmeticOperand;

arithmeticOperator = plusSign | minusSign | asterisk | solidus;

arithmeticOperand = propertyName
| numericLiteral
| function;

#=============================================================================#
# Definition of NUMERIC literals
#=============================================================================#
numericLiteral = unsignedNumericLiteral | signedNumericLiteral;

unsignedNumericLiteral = exactNumericLiteral | approximateNumericLiteral;

signedNumericLiteral = [sign] exactNumericLiteral | approximateNumericLiteral;

exactNumericLiteral = unsignedInteger [ period [ unsignedInteger ] ]
| period unsignedInteger;

approximateNumericLiteral = mantissa "E" exponent;

mantissa = exactNumericLiteral;

exponent = signedInteger;

signedInteger = [ sign ] unsignedInteger;

unsignedInteger = {digit};

sign = plusSign | minusSign;

#=============================================================================#
# Definition of CHARACTER literals
#=============================================================================#
characterLiteral = characterStringLiteral
                 | bitStringLiteral
                 | hexStringLiteral;

characterStringLiteral = quote [ {character} ] quote;

bitStringLiteral = "B" quote [ {bit} ] quote;

hexStringLiteral = "X" quote [ {hexit} ] quote;

propertyName = identifier;

identifier = identifierStart [ {identifierPart} ];

identifierStart = alpha [{octothorp|dollar|underscore|alpha|digit}];

identifierPart = alpha | digit;

character = alpha | digit | specialCharacter | quoteQuote;

quoteQuote = quote quote;

# NOTE: This production is supposed to be any alphabetic character from
#       the character set.
#
#       I use the A-Z, a-z range here as placeholders because:
#       (a) I have no idea how to indicate that alpha can be
#           any alphabetic UTF-8 character
#       (b) the validators I am using can only handle ASCII chars
#
alpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" |
        "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" |
        "W" | "X" | "Y" | "Z" |
        "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" |
        "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" |
        "w" | "x" | "y" | "z";

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";

specialCharacter = percent | ampersand | leftParen | rightParen | asterisk
| plusSign | comma | minusSign | period | solidus | colon
| semicolon | lt | gt | eq | questionMark | underscore
| verticalBar | doubleQuote ;

octothorp = "#";

dollar = "$";

underscore = "_";

doubleQuote = "\"";

percent = "%";

ampersand = "&";

quote = "'";

leftParen = "(";

rightParen = ")";

asterisk = "*";

plusSign = "+";

comma = ",";

minusSign = "-";

period = ".";

solidus = "/";

colon = ":";

semicolon = ";";

lt = "<";

eq = "=";

gt = ">";

questionMark = "?";

verticalBar = "|";

bit = "0" | "1";

hexit = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f";

#=============================================================================#
# Definition of TEMPORAL literals
#
# NOTE: Is the fact the time zones are supported too complicated for a
#       simple CQL?  Perhaps the "core" of CQL should just support UTC.
#=============================================================================#
temporalLiteral = fullDate | fullDate "T" utcTime;

fullDate   = dateYear "-" dateMonth "-" dateDay;

dateYear   = digit digit digit digit;

dateMonth  = digit digit;

dateDay    = digit digit;

utcTime  = timeHour ":" timeMinute ":" timeSecond [timeZoneOffset];

timeZoneOffset = "Z" | sign timeHour;

timeHour   = digit digit;

timeMinute = digit digit;

timeSecond = digit digit [period digit {digit}];

#=============================================================================#
# Definition of GEOMETRIC literals
#
# NOTE: This is basically BNF that define WKT encoding; it would be nice
#       to instead reference some normative BNF for WKT.
#=============================================================================#
geomLiteral = pointTaggedText
            | linestringTaggedText
            | polygonTaggedText
            | multipointTaggedText
            | multilinestringTaggedText
            | multipolygonTaggedText
            | geometryCollectionTaggedText
            | envelopeTaggedText;

pointTaggedText = "POINT" pointText;

linestringTaggedText = "LINESTRING" lineStringText;

polygonTaggedText = "POLYGON" polygonText;

multipointTaggedText = "MULTIPOINT" multiPointText;

multilinestringTaggedText = "MULTILINESTRING" multiLineStringText;

multipolygonTaggedText = "MULTIPOLYGON" multiPolygonText;

geometryCollectionTaggedText = "GEOMETRYCOLLECTION" geometryCollectionText;

pointText = leftParen point rightParen;

point = xCoord yCoord [zCoord];

xCoord = signedNumericLiteral;

yCoord = signedNumericLiteral;

zCoord = signedNumericLiteral;

lineStringText = leftParen point {comma point} rightParen;

polygonText =  leftParen lineStringText {comma lineStringText} rightParen;

multiPointText = leftParen pointText {comma pointText} rightParen;

multiLineStringText = leftParen lineStringText {comma lineStringText} rightParen;

multiPolygonText = leftParen polygonText {comma polygonText} rightParen;

geometryCollectionText = leftParen geomLiteral {comma geomLiteral} rightParen;

envelopeTaggedText = "ENVELOPE" envelopeText;

envelopeText = leftParen westBoundLon comma eastBoundLon comma northBoundLat comma southBoundLat [comma minElev comma maxElev] rightParen;

westBoundLon = signedNumericLiteral;

eastBoundLon = signedNumericLiteral;

northBoundLat = signedNumericLiteral;

southBoundLat = signedNumericLiteral;

minElev = signedNumericLiteral;

maxElev = signedNumericLiteral;

Appendix B: Queryables

The following is an extract from [2], including only the description of the Queryables extension for styling, used in VTP2 to expose the list of properties available for filtering.

A similar document is foreseen to be part of the OGC API - Features filtering extension, once it is ready.

B.1. Requirement Class "Queryables"

Requirements Class

http://www.opengis.net/t15/opf-styles-1/{m_n}/req/queryables

Target type

Web API

Dependency

OGC API - Features - Part 1: Core, conformance class "Core"

B.1.1. Fetch the queryable properties of the features in a collection

This operation returns the list of queryable properties that can be used to filter features in a collection and supports clients in constructing expressions for selection criteria in queries on features in the collection.

The response is an object with a member queryables, which contains an array with a description of the queryable properties of the feature collection. "Queryable" means that the property may be used in query expressions, such as in a query extension to OGC API - Features or as part of a selection criteria in an OGC SLD/SE or Mapbox styling rule.

Often the list of queryables for a collection will be a subset of all available properties in the features and be restricted to those properties that are, for example, indexed in the backend datastore to support performant queries.

For each queryable property the following information is or may be provided:

  • id (required) - the property name for use in expressions.

  • type (required) - the data type of the property, one of

    • string

    • uri

    • enum

    • number

    • integer

    • date

    • dateTime

    • boolean

  • description (optional) - a description of the property.

  • required (optional) - indicator whether the property is always present in features.

  • mediaTypes (optional) - in general, the representation of the queryables is meant to be independent of the feature encoding. However, this is not always the case. For example, length restrictions or namespace prefixes may result in different property identifiers for the same property. To support this, the definition of a queryable may be restricted to one or more feature encodings (media types).

  • pattern (optional, only for "string" and "uri") - a regular expression to validate the values of the property.

  • values (required, only for "enum") - an array of valid values of the property.

  • range (optional, only for "number", "integer", "date" and "dateTime") - the range of valid values expressed as an array with two items. Open ranges can be expressed using null for the minimum or maximum value.

Note that this is not about providing a schema for the features in the collection. A schema provides a complete syntactic definition of a specific feature encoding, typically for validation purposes. Schema languages like XML Schema or JSON Schema are much richer and support more complex syntactic rules, but are also more complex to parse.

Requirement 3

/req/queryables/op

A

The server SHALL support the HTTP GET operation at the path /collection/{collectionId}/queryables for each collection.

Requirement 4

/req/queryables/success

A

A successful execution of the operation SHALL be reported as a response with a HTTP status code 200.

B

The content of that response SHALL be based upon the OpenAPI 3.0 schema component "queryables", if the itemType of the collection is feature:

Listing 4. queryables
type: object
required:
  - queryables
properties:
  queryables:
    type: array
    nullable: true
    items:
      oneOf:
        - $ref: 'queryable-string'
        - $ref: 'queryable-enum'
        - $ref: 'queryable-number'
        - $ref: 'queryable-boolean'
        - $ref: 'queryable-date'
        - $ref: 'queryable-dateTime'
Listing 5. queryable
type: object
nullable: true
required:
  - id
  - type
properties:
  id:
    type: string
    nullable: true
    description: |-
      the property name for use in expressions
  title:
    type: string
    nullable: true
    description: |-
      the title of the property for presentation to a
      human user
  description:
    type: string
    nullable: true
    description: |-
      a description of the property
  required:
    type: boolean
    nullable: true
    default: false
    description: |-
      indicator whether the property is always present
      in features
  mediaTypes:
    type: array
    nullable: true
    description: |-
      In cases where a property is available only in a
      subset of the supported feature encodings, the
      list of the media types of the encodings can be
      specified.

      This capabilitiy is also needed for cases where
      the names of properties may differ between
      feature encodings. For example, identifiers in an
      XML/GML encoding may include a namespace,
      in GeoJSON or MVT this is not the case.

      There are other reasons, too. For example, the
      property identifier in a Shapefile may be different
      because of length restrictions.
    items:
      type: string
  type:
    type: string
    nullable: true
    description: |-
      the data type of the property
    enum:
      - string
      - uri
      - enum
      - number
      - integer
      - date
      - dateTime
      - boolean
discriminator:
  propertyName: type
  mapping:
    string: queryable-string
    enum: queryable-enum
    uri: queryable-string
    number: queryable-number
    integer: queryable-number
    date: queryable-date
    dateTime: queryable-dateTie
    boolean: queryable-boolean
Listing 6. queryable-string
allOf:
- $ref: 'queryable'
- type: object
  nullable: true
  properties:
    pattern:
      type: string
      nullable: true
      description: |-
        a regular expression to validate the values
        of the property
Listing 7. queryable-enum
allOf:
- $ref: 'queryable'
- type: object
  nullable: true
  required:
    - values
  properties:
    values:
      type: array
      nullable: true
      description: |-
        the list of values of the property
      items:
        type: string
Listing 8. queryable-number
allOf:
- $ref: 'queryable'
- type: object
  nullable: true
  properties:
    range:
      type: array
      nullable: true
      minItems: 2
      maxItems: 2
      items:
        type: number
        nullable: true
      description: |-
        a range of valid values; open range can be
        expressed using `null`
Listing 9. queryable-boolean
allOf:
- $ref: '#/components/schemas/queryable'
Listing 10. queryable-date
allOf:
- $ref: 'queryable'
- type: object
  nullable: true
  properties:
    range:
      type: array
      nullable: true
      minItems: 2
      maxItems: 2
      items:
        type: string
        format: date
        nullable: true
      description: |-
        a range of valid values; open range can be
        expressed using `null`
Listing 11. queryable-dateTime
queryable-dateTime:
  allOf:
  - $ref: 'queryable'
  - type: object
    nullable: true
    properties:
      range:
        type: array
        nullable: true
        minItems: 2
        maxItems: 2
        items:
          type: string
          format: date-time
          nullable: true
        description: |-
          a range of valid values; open range can be
          expressed using `null`

C

The id member of each queryable SHALL be unique.

Note that this requirements class does not specify any requirements on collections that are not feature collections.

Example 1. JSON encoding of queryables
{
  "queryables": [
    {
      "id": "name",
      "description": "the name of the vegetation area",
      "required": true,
      "type": "string",
      "example": "[A-Z0-9]{5}"
    },
    {
      "id": "type",
      "description": "the dominant characteristic of the vegetation area",
      "type": "enum",
      "values": [
        "grassland",
        "forest",
        "farmland"
      ]
    },
    {
      "id": "count",
      "description": "the number of cattle",
      "type": "integer",
      "range": [
        0,
        null
      ]
    },
    {
      "id": "fenced",
      "description": "indicator whether the area is walled or fenced",
      "type": "boolean"
    },
    {
      "id": "inspectionDate",
      "description": "the date of the last inspection",
      "type": "date",
      "range": [
        "2010-01-01",
        null
      ]
    },
    {
      "id": "lastUpdate",
      "description": "the date of the last update of the feature",
      "type": "dateTime",
      "range": [
        "2018-01-01T00:00:00Z",
        null
      ]
    }
  ]
}

Appendix C: Filter capabilities

A filter capabilities document allows a server to enumerate the supported filter operators, as well as documenting the filter functions included for extensibility.

The following document is an excerpt from a GeoServer 2.17.x filter capabilities, as implemented during the STAC and OGC API - Features and Catalogues Sprint.

The list of functions has been truncated to keep the example short, more information about GeoServer supported functions can be found in the filter functions reference.

{
  "conformanceClasses": [
    "http://www.opengis.net/spec/cql/1.0/conf/core",
    "http://www.opengis.net/spec/cql/1.0/conf/spatial",
    "http://www.opengis.net/spec/cql/1.0/conf/temporal"
  ],
  "capabilities": [
    {
      "name": "logical",
      "operators": [ "and", "or", "not" ]
    },
    {
      "name": "comparison",
      "operators": [ "lt", "lte", "gt", "gte", "gt", "neq", "like", "between", "in" ]
    },
    {
      "name": "spatial",
      "operators": [
        "equals",
        "disjoint",
        "touches",
        "within",
        "overlaps",
        "crosses",
        "intersects",
        "contains"
      ]
    },
    {
      "name": "temporal",
      "operators": [
        "after",
        "before",
        "begins",
        "begunby",
        "tcontains",
        "during",
        "endedby",
        "ends",
        "tequals",
        "meets",
        "metby",
        "toverlaps",
        "overlappedby",
        "anyinteracts",
        "intersects"
      ]
    },
    {
      "name": "arithmetic",
      "operators": [ "+", "-", "*", "/" ]
    }
  ],
  "functions": [
    {
      "name": "Area",
      "returns": {
        "name": "area",
        "type": "number"
      },
      "arguments": [ { "name": "geometry", "type": "geometry" } ]
    },
    {
      "name": "Concatenate",
      "returns": {
        "name": "result",
        "type": "string"
      },
      "arguments": [ { "name": "text", "type": "string" } ]
    },
    {
      "name": "IEEEremainder",
      "returns": {
        "name": "remainder",
        "type": "number"
      },
      "arguments": [
        {
          "name": "dividend",
          "type": "integer"
        },
        {
          "name": "divisor",
          "type": "integer"
        }
      ]
    },
    {
      "name": "PolyLabeller",
      "returns": {
        "name": "result",
        "type": "geometry"
      },
      "arguments": [
        {
          "name": "polygon",
          "type": "geometry"
        },
        {
          "name": "precision",
          "type": "number"
        }
      ]
    },
    {
      "name": "abs",
      "returns": {
        "name": "abs",
        "type": "integer"
      },
      "arguments": [ { "name": "int", "type": "integer" } ]
    },
    {
      "name": "acos",
      "returns": {
        "name": "arc cosine",
        "type": "number"
      },
      "arguments": [ { "name": "value", "type": "number" } ]
    },
    {
      "name": "all",
      "returns": {
        "name": "return",
        "type": "string"
      },
      "arguments": []
    },
    {
      "name": "any",
      "returns": {
        "name": "return",
        "type": "string"
      },
      "arguments": []
    }
  ]
}

Appendix D: Revision History

Table 4. Revision History
Date Editor Release Primary clauses modified Descriptions

November 11, 2019

G. Hobona

.1

all

initial version

November 20, 2019

A. Aime

.2

1

added document number

December 10, 2019

A. Aime

.3

all

references, bibliography, chapter structure and UML model

January 7, 2020

A. Aime

.4

all

more work on document structure

January 21, 2020

A. Aime

.5

all

updated UML model, update findings based on latest meetings

February 7, 2020

A. Aime

.6

all

improved filter descriptions, added CQL examples

February 18, 2020

A. Aime

.7

6

expanding previous work section

February 26, 2020

A. Aime

.8

10

GeoSolutions server and client implementations described

February 26, 2020

C. Portele

.9

10

interactive instruments server implementation described

March 19, 2020

G. Hobona

.10

various

updated bibliograpy and updated contributors list, fixed figure identifiers

March 24, 2020

G. Hobona and A. Aime

.10

various

applied G. Hobona review feedback, expanded on reccomendations and future work

March 25, 2020

C. Reed and A. Aime

.11

various

applied C. Reese review feedback

March 28, 2020

C. Portele

.12

implementations

Remove contents shared with the summary ER

March 30, 2020

A. Aime

.13

various

Refine GeoSolutions implementation entries, merge findings and results

April 14, 2020

A. Aime

.13

various

Refine GeoSolutions implementation entries, merge findings and results

April 8, 2020

J. Yutzler

.14

GeoPackage filtering

First draft of the GeoPackage filtering section

April 10, 2020

J. Jacovella-St-Louis

.15

GeoPackage filtering, Implementations

Ecere components description

April 11, 2020

J. Johnson

.16

Implementations

Terranodo components description

April 14, 2020

S. Taleisnik

.16

Implementations

Skymantics components description

April 29, 2020

T. Idol and Andrea Aime

.17

various

applied T. Idol review feedback

April 29, 2020

J. Harrison and Andrea Aime

.17

various

added target use case

May 4th, 2020

G. Hobona and Andrea Aime

.17

various

applied G. Hobona review feedback

Appendix E: Bibliography

[1] Portele, C.: OGC Testbed-14 Next Generation APIs: Complex Feature Handling Engineering Report. OGC 18-021,Open Geospatial Consortium, https://docs.opengeospatial.org/per/18-021.html (2019).

[2] Portele, C.: OGC Testbed-15: Styles API Engineering Report. OGC 19-010r2,Open Geospatial Consortium, http://docs.opengeospatial.org/per/19-010r2.html (2019).