Filtering

From Hydra Community Group

This page collects design proposals for ISSUE-45. Proposals for the collection design in general can be found on the Collection Design page.

Open Questions

To summarize, the things that still need to be discussed/decided are:

  • do we need to make the filter function explicit or can we safely default to AND
  • should we focus on describing Filters or FilteredViews (or similar)
  • if it's the former, can a IriTemplate be a Filter itself at the same time
  • if it's the latter, how do we connect the filter, the FilteredView and the IriTemplate
  • assuming that the same property needs to be used multiple times in a IriTemplate, how we model that
  • assuming we need "transformations" or also just simply the equivalent of the SELECT part of a SQL/SPARQL query how do we possibly model that
  • how can we enable filteing by subject (@id)?


Proposed Designs

Implictly imply AND filter

{
  "@id": "/collection",
  "filter": {
    "@type": "IriTemplate",
    "template": "/collection{?first,last}",
    "mapping": [
      { "variable": "first", "property": "schema:givenName" },
      { "variable": "last", "property": "schema:familyName" }
    ]
  }
}

Pros:

  • Simple and straightforward

Cons:

  • Not very powerful and difficult to add more sophisticated filters later on as it would likely break clients


Explicitly describe the filter

{
  "@id": "/collection",
  "filter": {
    "@type": "IriTemplate",
    "filterSpecification": {
      "@type": "AndFilter",
      "input": [
        { "variable": "first" },
        { "variable": "last" }
      ]
    },
    "template": "/collection{?first,last}",
    "mapping": { "variable": "first", "property": "schema:givenName" },
    "mapping": { "variable": "last", "property": "schema:familyName" }
  }
}

This would allow to nest filters to describe more complicated expressions (the filter would be name OR (first AND last)):

{
  "@id": "/collection",
  "filter": {
    "@type": "IriTemplate",
    "filterSpecification": {
      "@type": "OrFilter",
      "input": [
        { "variable": "name" },
        {
          "@type": "AndFilter",
          "input": [
            { "variable": "first" },
            { "variable": "last" }
          ]
        }
      ]
    },
    "template": "/collection{?name,first,last}",
    "mapping": [
      { "variable": "name", "property": "schema:name" },
      { "variable": "first", "property": "schema:givenName" },
      { "variable": "last", "property": "schema:familyName" }
    ]
  }
}

Pros:

  • Rather simple to understand
  • Very powerful

Cons:

  • Puts a big burden on the client. If a client wants to filter a collection in a specific way, it would need to be able to check whether his query can be accepted directly by the server or whether it needs to rewrite the query into simpler subqueries or generalize the query and complement it with some additional client side querying.


Describe supported logical operators per parameter

A simpler alternative could look somewhat like this but is not as expressive as it doesn't allow grouping (the typical order of precedence is NOT, AND, OR) and is less intuitive:

{
  "@id": "/collection",
  "filter": {
    "@type": [ "IriTemplate", "Filter" ],
    "variableRepresentation": "FilterRepresentation",
    "template": "/collection{?name,first,last}",
    "mapping": [
      {
        "variable": "name",
        "property": "schema:name",
        "allowedOperators": [ "NOT", "OR" ]
      },
      {
        "variable": "first",
        "property": "schema:givenName",
        "allowedOperators": [ "NOT" ]
      },
      {
        "variable": "last",
        "property": "schema:familyName"
      }
    ] 
  }
}

If no operator is given, it would default to AND. This would allow to the following expressions (I hope I didn't forget any):

name AND first AND last
NOT name AND first AND last
NOT name OR first AND last
name OR first AND last
name AND NOT first AND last
NOT name AND NOT first AND last
NOT name OR NOT first AND last
name OR NOT first AND last

Pros:

  • Easier for a client to check if a query is supported by the server or not

Cons:

  • Difficult to understand
  • Some not so obvious limitations in the query expressivity


Using of hydra:view instead of hydra:filter

Instead of using hydra:filter to point to the IRI template, the more general hydra:view could be reused. This is orthogonal to the description of the filter itself.

{
  "@id": /collection",
  "@type": "Collection",
  "view": {
    "@type": "ViewTemplate",
    "template": "/collection{?n}",
    "mapping": {
      "variable": "n"
      "property": "schema:name"
      "filter": true
    }
  }
}

The result of a GET /collection?n=Markus would then look as follows:

{
  "@id": /collection",
  "@type": "Collection",
  "totalItems": 2,
  "member": [
    { "@id": "/markus", "name": "Markus" }
  ],
  "view": {
    "@id": /collection?n=Markus",
    "@type": "PartialCollectionView"
  }
}

Pros:

  • More generalized and better composable (whether that's true, is being debated on the mailing list)
  • Follows the pagination design

Cons:

  • There are no derived collections that are directly addressable (that could be probably be changed easily though)