Nested structures / ISSUE-26 (was: An updated draft of the schema.org/Action proposal)

I changed the subject to focus on nested structures in this thread.


On Tuesday, January 28, 2014 4:57 PM, Sam Goto wrote:
> On Tue, Jan 28, 2014 at 6:22 AM, Markus Lanthaler wrote:
> > On Tuesday, January 28, 2014 6:02 AM, Sam Goto wrote:
> > >
> > > Here is another challenge with this approach: how do you set up the
> > > expectations on the properties of the Action class? That is, most of
> > > the invocations take more than one parameter and they map to one of
> > > the Action properties (e.g. RsvpAction takes an "agent" as well as an
> > > "attendance" -- whether the agent is going or not).
> > 
> > It depends. If the agent, e.g., is fixed as it is in most cases when
> > you send an invitation by email I would encode it in the URL the
> > response is sent to. If it isn't, I would create an RsvpResponse class
> > defining those two properties as you do below.
> 
> Right. Agreed that authentication/authorization has different
> transport mechanisms (e.g. cookies or oauth tokens). That wasn't a
> great example on second though.
> 
> Reviews might be a good one. As you are making a review, services take
> "reviewBody" as well as "ratingValue" (which is nested inside a
> "reviewRating" property of type "Rating", hence the nested object).
> 
> https://developers.google.com/gmail/actions/reference/review-action
>  
[...]
> 
> > > Markus, have you run into problems describing nested objects on
> > > "expects" (e.g. a bug needs an author which in turn needs to have at a
> > > minimum an id?)?
> > 
> > Yeah, I have been thinking about this but wasn't able to find an
> > elegant solution yet. If you start relying on Linked Data principles,
> > i.e., dereferenceable URLs to look up definitions (of course all
> > concepts can be defined in a single document) a lot of these deeply
> > nested structures go away as you simply reference the various
> > concepts. In many other cases, it is possible to eliminate the nesting
> > by creating a new specialized type or by encoding some of the
> > information in the URL the data is sent to.
> 
> 
> As I mentioned to you before, we really need a solution to this. A non
> trivial number of my actions take nested objects and we need to deal
> with this requirement from day one.

OK, I've raised ISSUE-26 to keep track of this in the context of Hydra

  https://github.com/HydraCG/Specifications/issues/26


> Here are a few examples that could inform/help us come up with
> something better:
> 
> hotel reservations
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/hotels/123
> events rsvp-ing
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/events/123
> taxistand reservations
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/taxistands/123/reservations
> restaurant orders
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/restaurants/123/orders
> product reviews
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/products/123

Let's use the review example as it is fairly compact. In your examples above you currently use something like this (I slightly simplified it and added a required: true):

  {
    ...
    "operation": {
      "@type": "ReviewAction",
      "expects": {
        "supportedProperty": [
          {
            "property": "http://schema.org/reviewBody",
            "required": true
          }
          {
            "property": "http://schema.org/reviewRating",
            "required": true
            "rangeIncludes": {
              "subClassOf": "Rating",
              "supportedProperty": {
                "property": http://schema.org/ratingValue",
                "required": true
              }
            }
          }
        ]
      }
    }
  }

This describes the following structure:

  http://schema.org/reviewBody - required
  http://schema.org/reviewRating - required
      (subClassOf: Rating)
      http://schema.org/ratingValue - required

So we either have to replicate that nesting or flatten it somehow.

One option we already discussed it is to avoid the class/supportedProperty indirection and instead point directly to properties. In this case it wouldn't help much as the nested property is nested inside a rangeIncludes.

  {
    ...
    "operation": {
      "@type": "ReviewAction",
      "expects": [
        {
          "property": "http://schema.org/reviewBody",
          "required": true
        }
        {
          "property": "http://schema.org/reviewRating",
          "required": true
          "rangeIncludes": {
            "subClassOf": "Rating",
            "supportedProperty": {
              "property": http://schema.org/ratingValue",
              "required": true
            }
          }
        }
      ]
    }
  }

Thus, in order to simplify it we probably need to use something else than "rangeIncludes". We could perhaps reuse "supportedProperty" but that would make the data difficult to understand IMO. In lack of a better name, I used "supportedRange" below and allow its value to be either a Property, a SupportedProperty or a Class.


  {
    "@context": "http://schema.org",
    "@id": "http://code.sgo.to/products/123",
    "@type": "Product",
    "name": "A product that can be reviewed",
    "operation": {
      "@type": "ReviewAction",
      "expects": [
        {
          "property": "http://schema.org/reviewBody",
          "required": true
        }
        {
          "property": "http://schema.org/reviewRating",
          "required": true
          "supportedRange": {
            "property": http://schema.org/ratingValue",
            "required": true
          }
        }
      ]
    }
  }

This does indeed simplify the description. The nesting corresponds 1:1 to the "abstract nesting": 

  http://schema.org/reviewBody - required
  http://schema.org/reviewRating - required
      http://schema.org/ratingValue - required

In that sense, it's optimal. Now if really necessary, we could try to flatten this representation but I don't know how much value that really provides. A trivial approach would be to specify the parent (in this case specifying the parent property, another option would be to give the SupportedProperty an identifier and use a reverse property for supportedRange to connect them):

  {
    "@context": "http://schema.org",
    "@id": "http://code.sgo.to/products/123",
    "@type": "Product",
    "name": "A product that can be reviewed",
    "operation": {
      "@type": "ReviewAction",
      "expects": [
        {
          "property": "http://schema.org/reviewBody",
          "required": true
        }
        {
          "property": "http://schema.org/reviewRating",
          "required": true
        },
        {
          "property": http://schema.org/ratingValue",
          "required": true,
          "parent": "http://schema.org/reviewRating"
        }
      ]
    }
  }

I find this flattening quite confusing and counterintuitive. If there are nested properties, I think it's reasonable to have the same nesting in the descriptions thereof.

What do you think about this options Sam?

I have to say that I don't find the example using rangeIncludes too bad even though rangeIncludes (in contrast to rdfs:range) might be a bit counterintuitive when used with required properties as it suggests that these required properties are somehow nevertheless optional as there might be other valid ranges as well.



--
Markus Lanthaler
@markuslanthaler

Received on Monday, 3 February 2014 17:03:45 UTC