An extented mappings for collection filters

From Hydra Community Group

This page proposes an extension to the filtering concept (ISSUE-45) with indirect mappings, compare operators, multiple filter properties, usage of external concepts, etc.

The proposal inspired by discussion on the mailing list.

The goal of the design proposal is to have an extendible mappings which could allow coverage of more current and future use cases.

Direct Mapping & Comparison Operators

In the simplest case we want to filter (or create a view for a collection) members of a collection by exact values of their properties, e.g. filter friends by their given names:

 {
   "@id": "/friends",
   ...
   "view": {
     "template": "/friends{?name}",
     "mapping": [
       {
         "@type": "DirectMapping",
         "variable": "name",
         "property": "schema:givenName",
         "comparator": "equals"
       }
     ]
   }
   ...
 }

The mapping in the example above has hydra:DirectMapping type which means the instances are filtered by schema:givenName (which they all have). Such mapping type doesn't allow to use property which is not defined for the given instances.

Also this example proposes a new property hydra:comparator which specifies the way the value of an instance will be compared with the value given by the filter. In this example hydra:equals is proposed, similar operators could be introduced: lessOrEquals, greaterOrEquals, contains, startsWith, etc.

A more complex example illustrates a use of hydra:comparator:

 {
   "@id": "/laptops",
   "view": {
     "template": "/laptops{?minPrice,maxPrice,minDisplaySize,maxDisplaySize,color,manufacturer}",
     "mapping": [
       { "@type": "DirectMapping", "variable": "minPrice", "property": "schema:price", "comparator": "greaterOrEquals" },
       { "@type": "DirectMapping", "variable": "maxPrice", "property": "schema:price", "comparator": "lessOrEquals" },
       { "@type": "DirectMapping", "variable": "minDisplaySize", "property": "ceo:hasDisplaySize", "comparator": "greaterOrEquals" },
       { "@type": "DirectMapping", "variable": "maxDisplaySize", "property": "ceo:hasDisplaySize", "comparator": "lessOrEquals" },
       { "@type": "DirectMapping", "variable": "color", "property": "schema:color", "comparator": "contains" },
       { "@type": "DirectMapping", "variable": "manufacturer", "property": "schema:manufacturer", "comparator": "contains" }
     ]
   }
 }

Multiple mapping properties

Another example suggests the direct mapping of a single filter variable to multiple properties which instances have:

 {
   "@id": "/friends",
   "view": {
     "template": "/friends{?name}",
     "mapping": [
       { "@type": "DirectMapping", "variable": "name", "property": ["schema:givenName", "schema:familyName"], "comparator": "equals" }
     ]
   }
 }

(BTW: Probably it's already supported by the filtering concept, the example above aims to clarify that.)'

Indirect mapping

The direct mapping is not always desired and possible. A simple example were provided by Tomasz Pluskiewicz: To filter people by their age, though their foaf:age is not defined in the underlying data, but schema:birthDate is defined instead.

Such example could be represented by a different mapping type hydra:IndirectMapping which says that the instances aren't directly filtered by a property they have, but by a property which they have "indirectly".

 {
   "@id": "/people",
   "view": {
     "template": "/people{?minAge,maxAge}",
     "mapping": [
       {
         "@type": "IndirectMapping",
         "mapping": { "variable": "minAge", "property": "foaf:age" }
         "property": "schema:birthDate",
         "comparator": "greaterOrEquals",
       },
       {
         "@type": "IndirectMapping",
         "mapping": { "variable": "maxAge", "property": "foaf:age" }
         "property": "schema:birthDate",
         "comparator": "lessOrEquals",
       }
     ]
   } 
 }

Indirect mapping with external concepts

A more complex indirect mapping is inspired by filtering instances by their geocoordinates with a geometry circle which is defined by the coordinates of its center and the radius:

 {
 "@id": "/sensors",
 "view: {
     "template": "/sensors{?lat,long,radius}",
     "mapping": [
       {
         "@type": ["IndirectMapping", "schema:GeoCircle"] ,
         "property": ["schema:latitude", "schema:longitude"],
         "comparator": "in",
         "mapping": [
           { "variable": "lat", "property": "schema:geoMidpoint/schema:latitude" },
           { "variable": "long", "property": "schema:geoMidpoint/schema:longitude" },
           { "variable": "radius", "property": "schema:geoRadius" }
         ]
       },
     ]
   }
 }

The example above proposes complex indirect mappings represented by concepts from external vocabularies (in this example schema:GeoCircle). Since external concepts may have non flat structure, it's proposed to use a subset of SPARQL Property Paths to specify the mapping to target properties.