On Mon, Feb 25, 2013 at 5:50 PM, Joshua TAYLOR <[email protected]> wrote:
> On Mon, Feb 25, 2013 at 4:58 PM, Joshua TAYLOR <[email protected]> wrote:
>> On Mon, Feb 25, 2013 at 4:32 PM, Andy Seaborne <[email protected]> wrote:
>>> On 25/02/13 20:14, Joshua TAYLOR wrote:
>>>>
>>>> On Mon, Feb 25, 2013 at 2:15 PM, Joshua TAYLOR <[email protected]>
>>>> wrote:
>>>>>
>>>>> On Mon, Feb 25, 2013 at 1:43 PM, Joshua TAYLOR <[email protected]>
>>>>> wrote:
>>>>>>
>>>>>> On Mon, Feb 25, 2013 at 11:42 AM, Joshua TAYLOR <[email protected]>
>>>>>> wrote:
>>>>>>>
>>>>>>> I'm looking at upgrading a project to use the new 2.10.0 release, and
>>>>>>> things are coming along nicely so far (some possible hitches in some
>>>>>>> writing code, but can't run tests until I can build...).  I've got a
>>>>>>> bunch of cases of
>>>>>>>
>>>>>>> UpdateAction.execute(request, getModel(), binding);
>>>>>>>
>>>>>>> that don't compile, though;  according to the release notes [1],
>>>>>>> "SPARQL Update execution no longer supports setting an initial
>>>>>>> binding".  I'm going to keep looking for the new way to do this, but
>>>>>>> in case someone's got the quick answer prepared, and so that the list
>>>>>>> has a recorded answer, I figured I'd ask sooner rather than later:
>>>>>>> how can initial bindings be specified in Jena 2.10.0?
>>>>>>>
>>>>>>> [1]
>>>>>>> http://svn.apache.org/repos/asf/jena/trunk/jena-arq/ReleaseNotes.txt
>>>>>>
>>>>>>
>>>>>> After some lunch, and some searching, I've found discussion on the dev
>>>>>> list about removing initial bindings [1] and that the accepted way to
>>>>>> do this now is to use BIND or VALUES.   In our project, we've
>>>>>> implemented a number of EnhancedResources that perform graph updates
>>>>>> using an idiom where some SPARQL text refers to a ?this variable, and
>>>>>> the execution uses a binding that binds ?this to the enhanced resource
>>>>>> (which might not have a URI).   We'd much prefer to do the graph
>>>>>> modification via SPARQL because it involves a number of operations,
>>>>>> and we'd like to be able to use anonymous resources.  Here's a typical
>>>>>> example:
>>>>>>
>>>>>>          static private final UpdateRequest setSomePropertyRequest =
>>>>>> UpdateFactory.create(
>>>>>>                  "DELETE {\n"+
>>>>>>                   .... SPARQL code that uses variable ?this ...
>>>>>>                  "} INSERT {\n"+
>>>>>>                  "} WHERE {"+
>>>>>>                     ...
>>>>>>                  "}"
>>>>>>          );
>>>>>>
>>>>>>          public Invocation setSomeProperty( Value value ) {
>>>>>>                          final QuerySolutionMap binding = new
>>>>>> QuerySolutionMap();
>>>>>>                          binding.add("?this", this );
>>>>>>                          UpdateAction.execute( setSomePropertyRequest,
>>>>>> getModel(), binding);
>>>>>>                  }
>>>>>>                  return this;
>>>>>>          }
>>>>>>
>>>>>> Is there still a way to do something like this?  If it will involve
>>>>>> using VALUES or BIND, is there a way to make it work with blank nodes?
>>>>>>
>>>>>> Thanks in advance,
>>>>>> //JT
>>>>>>
>>>>>> [1]
>>>>>> http://mail-archives.apache.org/mod_mbox/jena-dev/201302.mbox/%3CCAPTxtVNWT1HncCLom14cTF0WcjJ04pyP8ALes5Vb5yuSDv8DWw%40mail.gmail.com%3E
>>>>>
>>>>>
>>>>> Sorry for so much noise, but I wonder if the following is a solution.
>>>>> This does depend, of course, on the model against which the update is
>>>>> run being on the same machine, and such.  If "this" has a URI, then I
>>>>> can use the URI in the query, and if it's anonymous, then I can use
>>>>> the Jena-specific-and-depending-on-local-data id.  Then I can use
>>>>> request.add( "BIND ( ... as ?this )" ) to add the binding constraints
>>>>> to the request.
>>>>>
>>>>>                          final UpdateRequest request =
>>>>> UpdateFactory.create(); // ... more
>>>>> query in real example
>>>>>                          if ( this.isAnon() ) {
>>>>>                                  request.add( "BIND (
>>>>> <_:"+this.getId()+"> as ?thisInvocation )" );
>>>>>                          }
>>>>>                          else {
>>>>>                                  request.add( "BIND (
>>>>> <_:"+this.getURI()+"> as ?thisInvocation )" );
>>>>>                          }
>>>>>                          UpdateAction.execute( request, model ); //
>>>>> executes with the
>>>>> requested binding
>>>>>
>>>>> If this is a solution, it's easy enough to wrap cleanly in a util
>>>>> method, and I'll be content with that.  Can anyone confirm or deny
>>>>> that this is a solution?  (I'm hoping that I understand the
>>>>> UpdateRequest#add( String ) method correctly.  The javadoc [1] is
>>>>> empty, so I'm going on a guess...)
>>>>>
>>>>> //JT
>>>>>
>>>>> [1]
>>>>> http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/update/UpdateRequest.html#add(java.lang.String)
>>>>
>>>>
>>>> Sorry for all the noise and self-replies, but this doesn't work.
>>>> UpdateRequest#add doesn't do what I hoped it did.  Again, the issue
>>>> is, what do we do instead of initial bindings in Jena 2.10.0.  We've
>>>> been using a bunch of precompiled update requests, and had been able
>>>> to provide initial bindings for them.  I understand that we should now
>>>> be using BIND to introduce bindings, but this will still require some
>>>> sort of parameterization  (which we did before using initial
>>>> bindings).  Thoughts?
>>>
>>>
>>> What about
>>>
>>>     ParameterizedSparqlString
>>>     .asUpdate()
>>
>> This may very well be the answer.  One of the reasons that we'd been
>> using UpdateRequests was a (hopefully not too mistaken?) attempt at
>> "pre-compiling" the queries.  If we move to parameterized SPARQL
>> strings, it seems like we'll be imposing a fair amount of overhead,
>> since "this class does not in any way check that your command is
>> syntactically correct until such time as you try and parse it as a
>> Query or UpdateRequest" [1].  Then again, maybe the parsing is much
>> quicker than running a query with initial bindings?  I haven't run
>> tests yet to compare this.
>>
>> As an aside,  the docs for ParameterizedSPARQLString state "The
>> intended usage of this is where using a QuerySolutionMap as initial
>> bindings is either inappropriate or not possible."  If one is doing
>> updates, are there any APIs that still support initial bindings?
>>
>>> The technical problem with initial bindings and SPARQL update is what do
>>> they apply to - your examples are one SPARQL Update operation; in general, a
>>> SPARQL Update request may be several operations.
>>
>> (I missed this part of your message at first reading;  some email
>> clients (e.g., GMail) treat everything below the double hyphen as a
>> signature.)  Ah, thanks.  I haven't done much SPARQL querying/updating
>> in Jena in a while, and I'm coming into code that someone else wrote.
>> I can see where this is a pretty useful way of combining remote
>> queries.
>>
>> For the moment, I'll change things to use parameterized SPARQL
>> strings.  Hopefully the much more frequent parsing won't be an issue
>> (we're executing some of these queries very frequently, and always
>> against local models).  If I run into problems, you can be sure I'll
>> be back!
>>
>> As always, many thanks for the help, and a great platform,
>> [1] 
>> http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/query/ParameterizedSparqlString.html
>
> This is pretty close, but there's still a problem.  When a blanknode
> is substituted into a ParameterizedSparqlString, it's replaced by
> something like "_:b0" rather than the pseudo-form <_:blank-node-id>.
> That's easy enough to get around;  I can use setIri and construct the
> blank node's iri from "_:"+node.getId().  This means that I can get a
> ParameterizedSparqlString that looks like the update that I want.
> However, asUpdate() turns those pseudo-iris back into the blank nodes
> like "_:b0".  Here's an example of this (code is set up as a JUnit
> test):
>
> public class ParameterizedSparqlStrings {
>         @Test
>         public void showResults() {
>                 OntModel model = ModelFactory.createOntologyModel( 
> OntModelSpec.OWL_DL_MEM );
>                 Individual a = model.createIndividual( OWL.Thing );
>                 Individual b = model.createIndividual(
> "http://example.org/individual";, OWL.Thing );
>                 String sparqlString = "INSERT {\n"+
>                   "  ?aByNode a ?ignore . \n"+
>                   "  ?aByIri  a ?ignore . \n"+
>                   "  ?bByNode a ?ignore . \n"+
>                   "  ?bByIri  a ?ignore . \n"+
>                   "} WHERE {}";
>                 ParameterizedSparqlString pss = new 
> ParameterizedSparqlString( sparqlString );
>
>                 pss.setParam( "?aByNode", a );
>                 pss.setIri( "?aByIri", "_:"+a.getId() );
>                 pss.setParam( "?bByNode", b );
>                 pss.setIri( "?bByIri", b.getURI() );
>
>                 System.out.println( "\n* Parameterized Sparql String with 
> Ids:\n" + pss );
>                 System.out.println( "\n* Parameterized Sparql String as 
> Update:\n" +
> pss.asUpdate() );
>         }
> }
>
> and here's the output:  (In the parameterized string, ?aByIRI is what
> I'd like to have for the update, but it gets clobbered by asUpdate().)
>
> * Parameterized Sparql String with Ids:
> INSERT {
>   _:b0 a ?ignore .
>   <_:-570c0f1c:13d1389a5a3:-7ffc>  a ?ignore .
>   <http://example.org/individual> a ?ignore .
>   <http://example.org/individual>  a ?ignore .
> } WHERE {}
>
> * Parameterized Sparql String as Update:
> INSERT {
>   _:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?ignore .
>   _:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?ignore .
>   <http://example.org/individual>
> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?ignore .
>   <http://example.org/individual>
> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?ignore .
> }
> WHERE
>   {  }
>
> Thoughts?

I want to add an update to that last message from yesterday.  It
occurred to me that the behavior I was seeing might not have anything
to do with ParameterizedSparqlString#asUpdate, and more to do with
UpdateFactory#create, so I wrote a quick little test to see what
UpdateFactory#create would produce from a string with a pseudo-iri in
it. Sure enough,


        public void testPseudoIRIsInFactory() {
                OntModel model = ModelFactory.createOntologyModel( 
OntModelSpec.OWL_DL_MEM );
                Individual a = model.createIndividual( OWL.Thing );
                String command = "INSERT { <_:"+a.getId()+"> a
<http://example.com/someClass> } WHERE {}";
                UpdateRequest update = UpdateFactory.create( command );
                System.out.println( update.toString() );
        }


produces as output:


INSERT {
  _:b0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://example.com/someClass> .
}
WHERE
  {  }


where is appears that the pseudo-IRI has been replaced by a generic
blank node, _:b0.  Then it occurred to me, though, that that might
just be in the printed representation, and that the UpdateRequest
might contain a reference to the pseudo-iri anyway.  The following
code creates a model with two individuals, a and b, and uses an INSERT
to add the type "http://example.com/otherClass"; to ?x where, in the
WHERE clause includes BIND( <_:{a's id}> as ?x ).  It also displays
the command string and UpdateRequest for comparison, and prints the
properties of a and b after executing the UpdateRequest.

        public void testPseudoIRIsInUpdateRequests() {
                OntModel model = ModelFactory.createOntologyModel( 
OntModelSpec.OWL_DL_MEM );
                
                OntClass c = model.createClass( "http://example.com/someClass"; 
);
                Individual a = model.createIndividual( OWL.Thing );
                Individual b = model.createIndividual( OWL.Thing );
                String command = "INSERT {\n"+
                                 "  ?x a <http://example.com/otherClass>\n"+
                                         "}\n"+
                                 "WHERE\n"+
                                 "  { BIND( <_:"+a.getId()+"> as ?x)\n"+
                                         "  }";
                UpdateRequest request = UpdateFactory.create( command );
                System.out.println( "======\nCommand String:\n"+command );
                System.out.println( 
"\n======\nRequest.toString():\n"+request.toString() );
                UpdateAction.execute( request, model );
                
                StmtIterator statements = a.listProperties();
                while ( statements.hasNext() ) {
                        System.out.println( "A: "+statements.next() );
                }
                
                statements = b.listProperties();
                while( statements.hasNext() ) {
                        System.out.println( "B: "+statements.next() );
                }
        }


This code produces:


======
Command String:
INSERT {
  ?x a <http://example.com/otherClass>
}
WHERE
  { BIND( <_:-273dda07:13d16fdc988:-7ff9> as ?x)
  }

======
Request.toString():
INSERT {
  ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://example.com/otherClass> .
}
WHERE
  { BIND(_:b0 AS ?x) }

A: [-273dda07:13d16fdc988:-7ff9,
http://www.w3.org/1999/02/22-rdf-syntax-ns#type,
http://example.com/otherClass]
A: [-273dda07:13d16fdc988:-7ff9,
http://www.w3.org/1999/02/22-rdf-syntax-ns#type,
http://www.w3.org/2002/07/owl#Thing]
B: [-273dda07:13d16fdc988:-7ff8,
http://www.w3.org/1999/02/22-rdf-syntax-ns#type,
http://www.w3.org/2002/07/owl#Thing]


Although the request string shows a blank node, only individual a has
the addition otherClass type, so the UpdateRequest seems to keep track
of the anonymous resource, even though the printed representation
didn't indicate it.

First, is this execution the expected behavior (and, of more direct
importance to me :)) can we depend on it?
Second, (a) is the printing behavior expected, and (b) if it is, is
there any way to see from the request whether a blank node in the
query is actually bound to some resource?

Thanks in advance,
//JT

-- 
Joshua Taylor, http://www.cs.rpi.edu/~tayloj/

Reply via email to