Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite Response for Facet Search #5

Open
nickevansuk opened this issue Jul 17, 2018 · 5 comments
Open

Composite Response for Facet Search #5

nickevansuk opened this issue Jul 17, 2018 · 5 comments

Comments

@nickevansuk
Copy link
Contributor

nickevansuk commented Jul 17, 2018

Use Case

To reduce latency and improve user experience, a single search endpoint should be available that returns results of a query that include relevant activities, disabilities, other filtered resource collections as one response.

Straw Man Proposal

Combining the results of the /activities and /sessions responses into one composite response keeps it consistent with each of the resource collection endpoints, however this also leads to confusion in several areas:

  • Hydra views within the sessions list don't reference the composite endpoint, as they originate from the /sessions endpoint
  • When filters reference properties via dot notation, it is not clear which properties are being referenced (e.g. is location.geo inside sessions or activities?).

Example

GET /search/sessions?latitude=51.5&longitude=-0.2&radius=5
->
{
  "@context": "https://www.openactive.io/ns/oa.jsonld",
  "activity": {
    "type": "Collection",
    "id": "https://example.com/api/activities?latitude=51.5&longitude=-0.2&radius=5",
    "totalItems": 32,
    "items": []
  },
  "sessions": {
    "@context": "https://www.openactive.io/ns/oa.jsonld",
    "id": "https://example.com/api/sessions?latitude=51.5&longitude=-0.2&radius=5",
    "type": "Collection",
    "totalItems": 145,
    "view": {
      "id": "https://example.com/api/sessions?latitude=51.5&longitude=-0.2&radius=5",
      "type": "PartialCollectionView",
      "first": "https://example.com/api/sessions?latitude=51.5&longitude=-0.2&radius=5&page=1",
      "next": "https://example.com/api/sessions?latitude=51.5&longitude=-0.2&radius=5&page=2",
      "last": "https://example.com/api/sessions?latitude=51.5&longitude=-0.2&radius=5&page=3"
    },
    "items": []
  }
}
@lukehesluke
Copy link

+1

This would be very useful for us in imin. We are building a search API which supports returning extra contextual information about a search. So, like in your example @nickevansuk , if you do a search for sessions within some set of filters (e.g. ?latitude=51.5&longitude=-0.2&radius=5) it can return not only sessions matching those filters but also activities, accessibility support info, gender restriction info, etc that can be found within that collection of sessions

Clients can then use this extra contextual information to, for example, populate a list of filters for the end-user to choose from, like the left-hand column in Amazon shopping search results (e.g. https://www.amazon.co.uk/s/ref=nb_sb_noss_2?field-keywords=cuckoo+clock)

We would ideally have this all returned by one endpoint as this means just one API call from the client and just one call to our search backend

@nickevansuk
Copy link
Contributor Author

One potential route here is to use potentialAction, as below:

{
  "@context": "https://www.openactive.io/ns/oa.jsonld",
  "type": "Collection",
  "id": "https://example.com/api/sessions?latitude=0.1232334&longitude=0.23423423",
  "totalItems": 3,
  "potentialAction": {
    "type": "SearchAction",
    "target": "https://example.com/api/sessions?latitude=0.1232334&longitude=0.23423423&activity={activity}",
    "activity-input": {
      "type": "PropertyValueSpecification",
      "valueRequired": false,
      "multipleValues": true,
      "valueName": "activity",
      "name": "Activity",
      "possibleValue": {
        "type": "Collection",
        "id": "https://example.com/api/activities?latitude=0.1232334&longitude=0.23423423",
        "totalItems": 2,
        "items": [
          {
            "type": "Concept",
            "id": "http://openactive.io/activity-list/#d5f34cb1-35c0-46e5-ad6d-181f77274640",
            "identifier": "d5f34cb1-35c0-46e5-ad6d-181f77274640",
            "prefLabel": "Cardiovascular Classes",
            "count": 67
          }
        ]
      }
    }
  }
}

Note that identifier is used here to remove the need for API users to parse the "id" (as only the latter segment of the id needs to be passed as in for the parameter).

The above is consistent because the potentialActions are available on the object "https://example.com/api/sessions?latitude=0.1232334&longitude=0.23423423", which means that the potential actions are restricted to searchActions that are available on that object (i.e. faceted)

This also provides the API user with a URI template they can use to construct the API call to add that facet to the search (though in reality they would want a construct the API call programatically to allow users to add and remove filters via a UI). So there's a question about whether the URI template is likely to actually be used.

@nickevansuk
Copy link
Contributor Author

nickevansuk commented Jul 20, 2018

Using the above the possibleValues could only be included if a parameter e.g. enumeratePossibleValue=activity,genderRestriction was present (to save bandwidth on mobile)

@lukehesluke
Copy link

@nickevansuk I do like that the root object is now the sessions collection as that makes sense conceptually. The facets are an accompaniment to the sessions, but the collection is still ostensibly the sessions. This also puts the view at the root level, which makes sense as the paging data encapsulated in that object is relevant to the collection as a whole, rather than some subset of the collection - if you move to page 2, you're moving to page 2 of the sessions, not the facets

However, it seems odd to have the facets enumerated in a potentialAction. The facets are an extra piece of data that augments the sessions collection

I wonder if it's worth changing the Collection spec to allow .facets, which is an object with keys equal to {facetName}-facet and values equal to Collections e.g.

{
  "@context": "https://www.openactive.io/ns/oa.jsonld",
  "type": "Collection",
  "id": "https://example.com/api/sessions?latitude=0.1232334&longitude=0.23423423",
  "totalItems": 3,
  "facets": {
    "activity-facet": {
      "type": "Collection",
      // Note that I haven't used an existing /api/activities endpoint for this as it's specifically the activities
      // that belong to sessions satisfying this query. Any facilities' activities wouldn't be included in this
      "id": "https://example.com/api/sessions?latitude=0.1232334&longitude=0.23423423#!/activites"
      "totalItems": 1,
      "items": [{
        "type": "Concept",
        "id": "http://openactive.io/activity-list/#d5f...",
        "identifier": "d5f...",
        "prefLabel": "Swimming",
        "count": 3
      }]
    },
    "genderRestriction-facet": {
      // ...etc
    }
  },
  // ...etc
}

@lukehesluke
Copy link

And @nickevansuk agreed that some logic similar to #3 should be worked out for excluding facets from response when not wanted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants