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

On Friday, February 14, 2014 1:31 AM, Sam Goto wrote:
>> 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 think that's a reasonable exploration of this approach. Just to keep
> this as a fair/comprehensive comparison, lets look into what it would
> look like "path-query-language" approach could look like*:

Oh yeah, sorry. I didn't intend to sweep this under the table.


> *majorly patterned after
> https://developers.google.com/gmail/actions/reference/review-action
> 
>   {
>     "@context": "http://schema.org",
>     "@id": "http://code.sgo.to/products/123",
>     "@type": "Product",
>     "name": "A product that can be reviewed",
>     "operation": {
>       "@type": "ReviewAction",
>       "requiredProperties": [{
>         "path": "reviewBody"
>       }, {
>         "path": "reviewRating.ratingValue"
>       }]
>     }
>   }
> 
> The "contents" of this payload is equivalent to:
> 
>   http://schema.org/reviewBody - required
>   http://schema.org/reviewRating - required (transitively inferred via
> a sub-property being required too)
>       http://schema.org/ratingValue - required
> 
> Now, you can certainly formalize the path language to something like
> SPARQL queries, XPATH/XSLT (yikes, I know) or the likes.

Right, the simplest thing however, would probably be to just use an ordered list

  {
    "@context": {
      "@vocab": "http://schema.org",
      "path": { "@type": "@vocab", "@container": "@list"}
    },
    "@id": "http://code.sgo.to/products/123",
    "@type": "Product",
    "name": "A product that can be reviewed",
    "operation": {
      "@type": "ReviewAction",
      "requiredProperties": [{
        "path": [ "reviewBody" ]
      }, {
        "path": [ "reviewRating", "ratingValue" ]
      }]
    }
  }

That way, your JSON-LD processor would take care of the expansion of "reviewRating" etc. to full IRIs if desired.



>> 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.
> 
> Right. One of the advantages of SupportedClass is that it allows you
> to link to to an external document. Take a look at the contents of
> this doc (view:source and search for itemscopes): http://code.sgo.to/h
> ttps+++developers.google.com.gmail+actions+reference+review-
> action.html

Exactly. I find that to be very powerful and still to be the cleanest approach, at least from a theoretical point of view. In my experience, it also makes it very easy to understand to most developers as you simply tell them that you just mark up (or separately serialize) exactly the same information they find in the documentation in a machine-processable way.


> And how it can be used inline:
> 
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/products/123

Another really cool demo. I hope it won't be too long till I myself again find the time to hack on prototypes.


> That is, with linked data, the developer's code becomes quite
> simpler/more concise (as you expose the expectations in external
> docs):
> 
>   {
>     "@context": "http://schema.org",
>     "@id": "http://code.sgo.to/products/123",
>     "@type": "Product",
>     "name": "A product that can be reviewed",
>     "operation": {
>       "@type": "ReviewAction",
>       "expects": [
>         {
>           "@id": "http://code.sgo.to/https+++developers.google.com.gmail+actions+reference+review-action.html",
>         }
>       ]
>     }
>   }

If you set the @type of "expects" to @id in the context, you can even get rid of that @id-object and set the value directly to http://code.sgo.to/https+++...

That being said, the code becomes really "fluid" as it is up to the developer to decide how much information he wants to embed inline and how much he prefers to reference externally.


--
Markus Lanthaler
@markuslanthaler

Received on Friday, 14 February 2014 17:19:54 UTC