Tim; Following your recipe, I do see that the values are bound.
However, these values are from ct:Project.  I'm pretty sure this is a
defect - constructors should only apply to the class they are defined
on.  You can see this by creating an instance of ct:ProjectResource,
where the constructor is defined.  The behavior should be the same
regardless of where in TBC the constructor is called.  We will look
into this.

> The real question is, in the context of TBC/E/L, how do I control how URIs
> are created in a way that does not require the user to think about it?

As stated, using bnodes or spif:generateUUID() is the way to do this.
Please also note that the constructor behavior you see in Composer
only works automatically in Composer.  To use this in TBL or TBE, you
will need to design a SPARQLMotion script that calls sml:ApplyTopSPIN,
specifying spin:constructor running once on the class definition.

bnodes may not be a bad idea as a first step.  Then the next step,
which I presume you need, is to transform the imported triples to some
model.  When that occurs, chances are that you will have a way to
uniquely name and align URIs so the data ends up in the right place.

BTW, I do believe spif:buildUniqueURI() will be helpful to you here.
It will construct a unique URI by adding a numeric count (the ?index,
as described in the Help file) if it detects that the URI is already
in the inferred or asserted graph.  This is to say it hashes through
the current graph and builds a unique URI.

Use of owl:sameAs doesn't work well when using it with an OWL reasoner
because it is computationally expensive.  But owl:sameAs can be used
effectively in SPARQL queries to get all data for an equivalence
class.  This is commonly used in linked data applications.  For
example, the following will find all properties for an equivalence set
defined by ct:Thing_1:

SELECT DISTINCT ?p ?o
WHERE
{  BIND (ct:Thing_1 AS ?subject)
   {  ?subject ?p ?o
   }
  UNION
   {  ?subject owl:sameAs ?rsc .
      ?rsc ?p ?o
   }
   UNION
   {  ?rsc owl:sameAs ?subject .
     ?rsc ?p ?o
   }
}

You may find the UNIONs to be "ugly", but this can be abstracted into
a magic property, and it's less computationally expensive than running
OWL across all sameAs relations.  So this could be helpful as well...

-- Scott

On Apr 18, 7:14 am, Tim Smith <[email protected]> wrote:
> Hi Scott & Holger -
>
> For the SM use case, I have defined a SPIN Template that is used to create
> specific SPIN functions for URI creation just as you suggested.
>
> The only improvement would be to associate the SPIN function with a class
> so it's obvious what function needs to be called when creating instances
> for a given Class.  That could probably be done using a property to
> associate the function to the class and then look up the function name when
> needed.
>
> For the "inside TBC" (and hopefully TBL/E too) use case, I tried what
> Holger suggested and moved the BIND statement inside a sub-select as
> follows:
>
> DELETE  {
>     ?this ?p ?o .
>     ?s1 ?p1 ?this .}
>
> INSERT  {
>     ?uri ?p ?o .
>     ?s1 ?p1 ?uri .}
>
> WHERE {
>     {
>         SELECT ?uri
>         WHERE {
>             BIND 
> (spif:buildURI("http://ontologies.pg.com/test#PROJECT_RESOURCE_{?1}";, 
> spif:generateUUID())
> AS ?uri) .
>         }
>     } .
>     ?this ?p ?o .
>     ?s1 ?p1 ?this .
>
> }
>
> This worked but didn't work.  It actually created the correct triples
> versus the two incorrect triples the first attempt created.  However, it
> still sent TBC into a massive recursion until a stack overflow occurred
> (same stack trace as shown below).
>
> Scott - I understand your comments about only ?this and ?uri being bound.
>
> However, this is not really the case.  If you change the constructor to the
> following:
>
> DELETE  {
>     ?this ?p ?o .
>     ?s1 ?p1 ?this .}
>
> INSERT  {
>     ?uri ?p ?o .
>     ?s1 ?p1 ?uri .}
>
> WHERE {
>     ?this ?p ?o .
>     ?s1 ?p1 ?this .
>     BIND 
> (spif:buildURI("http://ontologies.pg.com/test#PROJECT_RESOURCE_{?1}_{?2}_{?3}_{?4}_{?5}";,
> ?this, ?p, ?o, ?s1, ?p1) AS ?uri) .
>
> }
>
> While TBC throws an exception, you will see that all of the variables are
> bound.  To see this in TBC, create a new instance of ProjectResource by
> using Create and Add from the project_1 instance "hasResource" property.
> Once the error occurs, nothing will appear on the Project_1 instance view
> so navigate away from that object to anything else and then come back to
> Project_1 and you will see that it has created two entries - one for
> creating a label and one for the type.  See screenshot below.
>
> You can see the following bindings in the output:
>
> ?this - ct:ProjectResource_1
> ?p - rdf:type AND rdfs:label since the constructor creates both the type
> and label triples.
> ?o - ct:ProjectResource
> ?s1 - ct:Project_1
> ?p1 - ct:hasResource
>
> Obviously this is not working correctly but the necessary data is there.
> If you change the above BIND statement to something that does no variable
> substitution such as:
>
> BIND (spif:buildUniqueURI("http://ontologies.pg.com/test#PROJECT_RESOURCE_";)
> AS ?uri) .
>
> you can actually set the URI for the new resource via the constructor -
> which is what I need - just a more robust version :)
>
> The real question is, in the context of TBC/E/L, how do I control how URIs
> are created in a way that does not require the user to think about it?
>
> I think this is critical if you want to do anything on a large scale where
> triples are created in a multitude of places and are linked together using
> a Linked Data framework.  The other alternative is to not care and then
> attempt to identify the same instance across multiple sources and link them
> using owl:sameAs but we all know that does not work well in practice.
>
> Tim
>
> On Tue, Apr 17, 2012 at 11:05 PM, Scott Henninger <
>
>
>
>
>
>
>
> [email protected]> wrote:
> > Tim; Looking down this thread, I see that someone, perhaps me,
> > suggested using a DELETE statement in a constructor.  I'm not sure how
> > this makes sense, or why this was stated.  But a constructor by
> > definition starts with no data.  So {?this ?p ?o} will fail, but the
> > BIND statement is executed outside of the basic graph pattern (bgp) -
> > BIND translates to a select projection.
>
> > So, in the following query, the only variables that can be bound are ?
> > this and ?uri, and neither the DELETE nor the INSERT clause will
> > execute anything:
>
> > DELETE  {
> >    ?this ?p ?o .
> >    ?s1 ?p1 ?this .
> > }
> > INSERT  {
> >    ?uri ?p ?o .
> >    ?s1 ?p1 ?uri .
> > }
> > WHERE {
> >    ?this ?p ?o .
> >    ?s1 ?p1 ?this .
> >        BIND (spif:buildURI("
> >http://ontologies.pg.com/test#PROJECT_RESOURCE_{?1}";,
> > spif:generateUUID())
> > AS ?uri) .
> > }
>
> > Apologies for the confusion that may have created.  So let's go back
> > to a couple of key points in the original statement:
>
> > > This requires the use of the same "rules" to
> > > create the URI.  Currently, I must copy & paste and maintain these rules
> > in
> > > every SM module that needs to create the URIs.
>
> > In this case, you can create a SPIN function an place it in a file
> > with a .spin extension - for example myRules.spin.ttl.  The function
> > will then be available to all project in the workspace and you can
> > call this rule in any of the SPARQLMotion module queries.  For
> > example, if you had a SPIN function named
> > globals:createProjectResource with the spin:body
>
> > SELECT ?uri
> > WHERE
> > {  BIND (spif:buildURI("http://ontologies.pg.com/
> > test#PROJECT_RESOURCE_{?1}", spif:generateUUID()) AS ?uri) .
> > }
>
> > ..then this can be called anywhere in the workspace as
> >  BIND (globals:createProjectResource() AS ?myuri)
>
> > > It would be nice if there was a way to create the URI automatically
> > using a
> > > pre-defined template that is applied when the new instance is created as
> > > part of a CONSTRUCT query.
>
> > This is what bnodes do. But I understand being hesitant about using
> > bnodes.  Given that, spif:generateUUID() will give you a unique id and
> > i believe the aforementioned SPIN function will address your issues
> > with generating unique uri's.
>
> > -- Scott
>
> > On Apr 17, 7:50 pm, Holger Knublauch <[email protected]> wrote:
> > > On 4/18/2012 8:29, Tim Smith wrote:
>
> > > > To continue this thread a bit...
>
> > > > I ran into a case where I wanted to use this constructor inside TBC/E
> > > > to set the URI for an instance when the instance is created.  The
> > > > objective is to create useful, yet standardized URIs so that users do
> > > > not have to think about those details when creating new instances.
>
> > > > I placed the following into spin:constructor for a class (this was
> > > > just a test)
>
> > > > DELETE  {
> > > >     ?this ?p ?o .
> > > >     ?s1 ?p1 ?this .
> > > > }
> > > > INSERT  {
> > > >     ?uri ?p ?o .
> > > >     ?s1 ?p1 ?uri .
> > > > }
> > > > WHERE {
> > > >     ?this ?p ?o .
> > > >     ?s1 ?p1 ?this .
> > > >         BIND
> > > > (spif:buildURI("http://ontologies.pg.com/test#PROJECT_RESOURCE_{?1}
> > > > <http://ontologies.pg.com/test#PROJECT_RESOURCE_%7B?1%7D>",
> > > > spif:generateUUID()) AS ?uri) .
> > > > }
>
> > > > However, TBC fails with very odd behavior.
>
> > > > This is due  to the use of the spif:generateUUID() function.
>
> > > > In some cases you have to use a function like this to avoid naming
> > > > collisions.  I really need to use blank nodes here but I can't use
> > > > them because they won't work in a linked data scenario.
>
> > > > Is there any way to bind the output of generateUUID() once and avoid
> > > > multiple executions of the function?
>
> > > Would it work to place the BIND into a sub-select or { } block before
> > > the basic graph pattern? This should execute this block first and you
> > > can use a single value even if the rest of the query iterates multiple
> > > times.
>
> > > Holger
>
> > > > Or is there another way to create unique URIs as users enter them?
> > > > spif:buildUniqueURI() does not say what it does when it encounters a
> > > > duplicate URI.
>
> > > > Thanks,
>
> > > > Tim
>
> > > > The attached file has an example that I'll describe.
>
> > > > Two classes - Project and ProjectResource and one property -
> > hasResource.
>
> > > > hasResource is part of an AllValuesFrom restriction on Project that
> > > > points to ProjectResource.
>
> > > > The constructor shown above is the constructor for ProjectResource.
>
> > > > I then created an instance of Project, clicked on "hasResource" on the
> > > > new project instance (Project_1) and selected "Create and Add".
>
> > > > TBC attempts to add the instance, however it quickly fails with the
> > > > following error:
>
> > > > Operation failed.
>
> > > > On: Apr 17, 2012 5:52:49 PM
>
> > > > Reason:
> > > > java.lang.StackOverflowError
>
> > > > Once I close this window, I'm back to TBC and no new instance of
> > > > ProjectResource has been created, or so I think.
>
> > > > Now click on hasResource for Project_1 again and this time select
> > > > "Create blank node".  This will run to completion.
>
> > > > Once it returns, I see the new blank node instance as well as two
> > > > additional ProjectResource instances - one has an rdf:type the other
> > > > has an rdfs:label.
>
> > > > Shortened stack trace below.  The last line was repeated hundreds of
> > > > times.
>
> > > > Operation failed.
>
> > > > On: Apr 17, 2012 5:52:49 PM
>
> > > > Reason:
> > > > java.lang.StackOverflowError
>
> > > >     at com.hp.hpl.jena.graph.Node_URI.same(Node_URI.java:51)
>
> > > >     at com.hp.hpl.jena.graph.Node_URI.equals(Node_URI.java:46)
>
> > > >     at
>
> > com.hp.hpl.jena.graph.impl.SimpleReifier.matchesReification(SimpleReifier.java:222)
>
> > > >     at
> > > > com.hp.hpl.jena.graph.impl.SimpleReifier.find(SimpleReifier.java:211)
>
> > > >     at
>
> > com.hp.hpl.jena.graph.impl.SimpleReifier.findEither(SimpleReifier.java:238)
>
> > > >     at
>
> > com.hp.hpl.jena.graph.impl.SimpleReifier.findExposed(SimpleReifier.java:235)
>
> > > >     at
> > > > com.hp.hpl.jena.graph.impl.GraphBase.reifierTriples(GraphBase.java:318)
>
> > > >     at com.hp.hpl.jena.graph.impl.GraphBase.find(GraphBase.java:240)
>
> > > >     at
> > > > com.hp.hpl.jena.graph.impl.GraphBase.containsByFind(GraphBase.java:308)
>
> > > >     at
>
> > com.hp.hpl.jena.graph.impl.GraphBase.graphBaseContains(GraphBase.java:288)
>
> > > >     at
>
> > com.hp.hpl.jena.mem.faster.GraphMemFaster.graphBaseContains(GraphMemFaster.java:183)
>
> > > >     at
>
> ...
>
> read more »

-- 
You received this message because you are subscribed to the Google
Group "TopBraid Suite Users", the topics of which include Enterprise Vocabulary 
Network (EVN), TopBraid Composer,
TopBraid Live, TopBraid Ensemble, SPARQLMotion and SPIN.
To post to this group, send email to
[email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/topbraid-users?hl=en

Reply via email to