510 likes | 638 Views
Programming with Jena. Sources for examples can be found @ http:// jenabean.googlecode.com/svn/jenabean-lab1 http:// jenabean.googlecode.com/svn/jenaclass. Taylor Cowan Travelocity 8982. [] a foaf:Person ; foaf:name Taylor Cowan; foaf:weblog <http://thewebsemantic.com>;
E N D
Programming with Jena Sources for examples can be found @ http://jenabean.googlecode.com/svn/jenabean-lab1 http://jenabean.googlecode.com/svn/jenaclass Taylor Cowan Travelocity 8982
[] a foaf:Person; • foaf:name Taylor Cowan; • foaf:weblog <http://thewebsemantic.com>; • foaf:workplaceHomepage <http://www.travelocity.com>; • foaf:holdsAccount <http://twitter.com/tcowan>; • foaf:currentProject <http://jenabean.googlecode.com>; • foaf:currentProject <http://geosparql.googlecode.com>; • foaf:currentProject <http://jo4neo.googlecode.com>;
Model m = ModelFactory.createDefaultModel(); Thing todaysTopic = new Thing("http://jenabean.googlecode.com", m); new Thing(m).isa(Foaf.Person.class) .name("Taylor Cowan") .weblog(URI.create("http://thewebsemantic.com")) .holdsAccount(URI.create("http://twitter.com/tcowan")) .currentProject(todaysTopic) .currentProject(URI.create("http://jo4neo.googlecode.com")); @see Card.java in package example.fluentwriter
AGENDA • Semantic Web Introduction • RDF basics • Coding Towards Jena’s Semantic Web Framework API • Java to Model Binding with JenaBean • Java to Model Binding with Fluent Interfaces
Why Not Microformats? • <xsl:choose> • <xsl:when test="(false() = not((.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'img' or local-name() = 'area')]/@alt) and (string-length(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'img' or local-name() = 'area')]/@alt)) = string-length(translate(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'img' or local-name() = 'area')]/@alt),' ',''))))) or (false() = not((.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'abbr')]/@title) and (string-length(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'abbr')]/@title)) = string-length(translate(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and (local-name() = 'abbr')]/@title),' ',''))))) or (false() = not((.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and not(local-name() = 'abbr' or local-name() = 'img')]) and (string-length(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and not(local-name() = 'abbr' or local-name() = 'img' or local-name() = 'area')][1])) = string-length(translate(normalize-space(.//*[not(ancestor-or-self::*[local-name() = 'del']) = true() and contains(concat(' ',normalize-space(@class),' '),' fn ') and not(local-name() = 'abbr' or local-name() = 'img')][1]),' ','')))))"> http://suda.co.uk/projects/microformats/hcard/xhtml2vcard.xsl
RDF != XML • “The site at http://www.travelocity.com, also known as Travelocity, is an online travel agency competing with expedia.com”
Concepts Serialized as N3 • :OnlineTravelAgency • a owl:Class . • :hasCompetitor • a rdf:Property . • <http://www.travelocity.com> • a :OnlineTravelAgency ; • rdfs:label "Travelocity"@en ; • :hasCompetitor <http://www.expedia.com> .
Concepts Serialized as RDF/XML <rdf:RDF …><owl:Classrdf:about="http://foo#OnlineTravelAgency"/><rdf:Propertyrdf:about="http://foo#hasCompetitor"/><OnlineTravelAgencyrdf:about="http://www.travelocity.com"><hasCompetitorrdf:resource="http://www.expedia.com"/><rdfs:labelxml:lang="en">Travelocity</rdfs:label></OnlineTravelAgency></rdf:RDF>
As N-Triples (Most Canonicalor Normalized) <hasCompetitor> <rdf:type><rdf:Property> . <http://travelocity.com> <hasCompetitor> <http://expedia.com>. <http://travelocity.com> <rdfslabel> "Travelocity"@en <http://travelocity.com> <rdf:type> <OnlineTravelAgency> . <OnlineTravelAgency><rdf:type> <owl:Class> . Subject,Verb, Object = a triple
As Java Code, using the Jena API OntModel m = ModelFactory.createOntologyModel(); OntClassota = m.createClass("OnlineTravelAgency"); Individual tvly = ota.createIndividual("http://www.travelocity.com"); tvly.setLabel("Travelocity", "en"); OntProperty p = m.createOntProperty("hasCompetitor"); tvly.setPropertyValue(p, m.createResource("http://www.expedia.com"));
Creating a Model • 1: Model m = ModelFactory.createDefaultModel(); • 2: m.setNsPrefix("foaf", FOAF.NS); • 3: Resource jazoon = m.createResource("http://jazoon.com/"); • 4: Resource java = m.createResource( • 5: "http://dbpedia.org/resource/Java_(software_platform)"); • 6: jazoon.addProperty(FOAF.primaryTopic, java); • 7: m.write(System.out, "N3"); <http://jazoon.com/> foaf:primaryTopic <http://dbpedia.org/resource/Java_(software_platform)> .
Assertion foaf:primaryTopic jazoon.com java
Creating an Inferencing Model • OntModelinfModel = ModelFactory.createOntologyModel( • OntModelSpec.OWL_MEM_MICRO_RULE_INF, m); • infModel.read("http://xmlns.com/foaf/spec/index.rdf"); • infModel.writeAll(System.out, "N3",null); In addition to known data, a new triple is inferred… <http://dbpedia.org/resource/Java_(software_platform)> foaf:isPrimaryTopicOf <http://jazoon.com/>
foaf:Document Knowledge after Inference Is a foaf:primaryTopic jazoon.com java foaf:isPrimaryTopicOf
The Semantic Web is Property focused • Properties have Classes, not vice versa • Don’t read “the domain of foaf:knows is a foaf:Person”, but instead “anything with foaf:knows relationship is a foaf:Person” • Properties can extend other properties • Properties can be declared as inverse, symmetric, and transitive, all resulting in new inferences.
List All Classes from an Ontology • OntModel model = ModelFactory.createOntologyModel(); • model.read("http://xmlns.com/foaf/spec/index.rdf"); • ExtendedIterator<OntClass> it = model.listClasses(); • while(it.hasNext()) { • OntClasscls = it.next(); • if (cls.getNameSpace().equals(FOAF.NS)) • System.out.println(cls.getURI()); • }
Models Can be Populated from URL, Either Public or Local • OntModel model = ModelFactory.createOntologyModel(); • // read from URL • model.read("http://xmlns.com/foaf/spec/index.rdf"); • model.read("file:mydata.n3","N3");
Models can be Populated from Other Models • Model modelA = ModelFactory.createDefaultModel(); • Model modelB = ModelFactory.createDefaultModel(); • … • //Add all statements from modelB to modelA • modelA.add(modelB);
Some example foaf: <http://www.ibm.com/developerworks/xml/library/j-jena/> a dc:Article ; dc:creator "Philip McCarthy"^^xsd:string ; dc:subject "jena, rdf, java, semantic web"^^xsd:string ; dc:title "Introduction to Jena"^^xsd:string .
Equivalent Raw Jena API Client Code • String NS = "http://purl.org/dc/elements/1.1/"; • OntModel m = ModelFactory.createOntologyModel(); • OntClassarticleCls = m.createClass(NS +"Article"); • Individual i = articleCls.createIndividual( • "http://www.ibm.com/developerworks/xml/library/j-jena/"); • Property title = m.getProperty(NS + "title"); • Literal l = m.createTypedLiteral("Introduction to Jena"); • i.setPropertyValue(title,l); • Property creator = m.getProperty(NS + "creator"); • l = m.createTypedLiteral("Philip McCarthy"); • i.setPropertyValue(creator,l); • Property subject = m.getProperty(NS + "subject"); • l = m.createTypedLiteral("jena, rdf, java, semantic web"); • i.setPropertyValue(subject,l); • m.write(System.out, "N3");
You need to create unique URI’s for every entity. You must specify the type of each primitive value. Properties must be created for each bean property. The impedance mismatch is similar to what we had with RDBMS Pain Points of Raw Jena API Programming
Creating The Same Assertions with JenaBean • Model m = ModelFactory.createDefaultModel(); • Bean2RDF writer = new Bean2RDF(m); • Article article = new Article( • "http://www.ibm.com/developerworks/xml/library/j-jena/"); • article.setCreator("Philip McCarthy"); • article.setTitle("Introduction to Jena"); • article.setSubject("jena, rdf, java, semantic web"); • writer.save(article); • m.write(System.out, "N3");
The JenaBean Project • Hosted at Google code • Bean binding, not code generation • Doesn’t use byte code interweaving • Doesn’t require implementing an interface • http://jenabean.googlecode.com
Programming with JenaBean is Simple • Bean2RDF writes objects • RDF2Bean reads objects • 3 Annotations • @Idspecifies unique field • @Namespaceprovides a domain • @RdfProperty maps java properties to RDF properties
The Simplest Possible Example • packageexamples.model; • importthewebsemantic.Id; • publicclass Person { • @Id • private String email; • public String getEmail() { returnemail;} • publicvoidsetEmail(String email) { • this.email = email;} • } <http://examples.model/Person> a <http://www.w3.org/2000/01/rdf-schema#Class> ; <http://thewebsemantic.com/javaclass> "examples.model.Person" . <http://examples.model/Person/thewebsemantic@gmail.com> a <http://examples.model/Person> ; <http://examples.model/email> "thewebsemantic@gmail.com"^^xsd:string .
Saving an Instance of Person • Model m = ModelFactory.createOntologyModel(); • Bean2RDF writer = new Bean2RDF(m); • Person p = new Person(); • p.setEmail("person@example.com"); • writer.save(p); • m.write(System.out, "N3"); • … • <http://example/Person> a owl:Class ; • <http://thewebsemantic.com/javaclass> "example.Person" . • <http://example/Person/taylor_cowan@yahoo.com> a <http://example/Person> ; • <http://example/email> "taylor_cowan@yahoo.com"^^xsd:string .
Overriding the Default Namespace • packageexamples.model; • importthewebsemantic.Id; • importthewebsemantic.Namespace; • @Namespace("http://mydomain#") • publicclass Person { … } <http://mydomain#Person> a <http://www.w3.org/2000/01/rdf-schema#Class> ; <http://thewebsemantic.com/javaclass> "examples.model.Person" . <http://mydomain#Person/thewebsemantic@gmail.com> a <http://mydomain#Person> ; <http://mydomain#email> "thewebsemantic@gmail.com"^^xsd:string .
Overriding the Default Property Bindings • @Namespace(“http://mydomain#”) • publicclass Person { • private String email; • @RdfProperty(FOAF.NS + "name") • private String name; <http://mydomain#Person> a <http://www.w3.org/2000/01/rdf-schema#Class> ; <http://thewebsemantic.com/javaclass> "examples.model.Person" . <http://mydomain#Person/thewebsemantic@gmail.com> a <http://mydomain#Person> ; <http://xmlns.com/foaf/0.1/name> "Taylor Cowan"^^xsd:string .
Extending Person to Support Friendship • public Collection<Person> friends = new • LinkedList<Person>(); • @RdfProperty("http://xmlns.com/foaf/0.1/knows") • public Collection<Person> getFriends() { returnfriends;}
Loading Beans from a Model • RDF2Bean reader = new RDF2Bean(m); • Person p = reader.load(Person.class,"person@example.com"); • Collection<Person> allPeople = reader.load(Person.class);
JenaBean Support for OWL Entailments publicclass Location { • @Id • public String id; public String name; @RdfProperty(transitive=true) public Collection<Location> within; @RdfProperty(inverseOf="within") public Collection<Location> contains; … <http://example.transitive/within> a rdf:Property , owl:TransitiveProperty . <http://example.transitive/contains> a rdf:Property ; owl:inverseOf <http://example.transitive/within> .
Reading Existing RDF/OWL • Up till this point we were generating the triples • JenaBean + annotations controlled the URI’s • The model knew the provenance of all data (the originating java class)
Example Geonames “feature” entry Jenabean will bind to existing URI’s <Feature rdf:about="http://sws.geonames.org/3333156/"> <name>London Borough of Islington</name> <alternateName xml:lang="fr">Islington</alternateName> <inCountryrdf:resource="http://www.geonames.org/countries/#GB"/> <population>185500</population> <wgs84_pos:lat>51.5333333</wgs84_pos:lat> <wgs84_pos:long>-0.1333333</wgs84_pos:long> </Feature>
Crafting beans for existing RDF requires care 1 @Namespace("http://www.geonames.org/ontology#") publicclass Feature { @Id private URI uri; @RdfProperty("http://www.w3.org/2003/01/geo/wgs84_pos#lat") publicdoublelat; 2 3 4 • Namespace must accurately match • Your java’s classname must match the Ontology class • Your @Id must be of type java.net.URI • All property URI’s must match the Ontology property
JenaBean can auto discover JenaBeans, provided it knows the package(s) 1: Model m = ModelFactory.createDefaultModel(); 2: m.read("http://ws.geonames.org/search?q=london&type=rdf"); 3: RDF2Bean reader = new RDF2Bean(m); 4: reader.bindAll("com.foo", "com.bar"); // type safe binding by class reader.bind(Feature.class); // or package reader.bind(Feature.class.getPackage());
JenaBean tip: handling lang encoded strings • If your data has something like this: • <alternateName xml:lang="es">Londres</alternateName> • Then use JenaBean‘s special type “LocalizedString“ public Collection<LocalizedString> alternateName; example.geonames
Query Support • Most most practical purposes there’s no need to utilize anything other than Jena’s ARQ api to query. JenaBean’s reader (RDF2Bean) can transform a node given it’s URI or it’s representation as a jena Resource… // load using a Jena Resource reader.load(Human.class, jenaResource); // load any node using it’s URI reader.load(Human.class, "http://any.uri");
thewebsemantic.SparqlUtil String query = "prefix ntn: <http://semanticbible.org/ns/2006/NTNames#>\n" + "SELECT ?s WHERE { ?s a ntn:Woman }"; Model m = ModelFactory.createOntologyModel(); m.read("file:NTNames.owl"); m.read("file:NTN-individuals.owl"); RDF2Bean reader = new RDF2Bean(m); reader.bindAll("example.query"); Collection<Woman> women = Sparql.exec(m, Woman.class, query); for (Human human : women) System.out.println(human.label + ":" + human.comment); example.query
Summary • @Namespace(“http://yournamespace.goes.here”) • Applies to class declaration • @Id • Applies to field or getter method • Should be a String or primitive type, or wrapper type • type java.net.URI is special • @RdfProperty(“http://specific.property.uri”) • Applies to field or getter method • Remember: by definition, JavaBeans must have a default constructor.
Summary • writer.save(mybean) • writer.saveDeep(mybean) • Save this and all related objects • reader.load(Class.class, key); • reader.loadDeep(…); • take care, could place entire graph into memory. • reader.bindAll(package, package, …); • Makes jenabean aware of your beans
JenaBean Fluent Programming API • AKA method chaining, foo.this().that().bar(); • A “Fluent Interface” aims to provide more readable code • A significant departure from JavaBeans • Is always connected to the jena graph • Entirely interface (not class) driven • Allows Individuals to morph into their various classes • Allows use of vocabulary terms against any Individual regardless of classification.
Example: wgs84 geo vocabulary importthewebsemantic.As; importthewebsemantic.Functional; importthewebsemantic.Namespace; @Namespace("http://www.w3.org/2003/01/geo/wgs84_pos#") publicinterface Geo extends As { interface Point extends Geo{} @Functional Geo lat(float l); Float lat(); @Functional Geo long_(float l); Float long_(); }
Create a new anonymous iCal event. Ical t = new Thing(m).isa(Ical.Vevent.class); Create a newiCal event with URI Ical t = new Thing(“http://uri”, m). isa(Ical.Vevent.class);
Full Example: Creating an iCal event for the meetup 1: Ical.Vevent t = new Thing(m).isa(Ical.Vevent.class); 2: t.uid("event_11978192@meetup.com"). 3: dtstart("20100124T200000Z"). 4: dtend("20100124T220000Z"). 5: summary("Jena Semantic Web…"). 6: location("Parisoma - …") 7: .as(Geo.class). 8: lat(37.77f). 9: long_(-122.41f); [] a ical:Vevent ; ical:dtend "20100124T220000Z" ; ical:dtstart "20100124T200000Z" ; ical:location "Parisoma - " ; ical:summary "Jena Semantic Web…" ; ical:uid "event_11978192@meetup.com" ; geo:lat "37.77"^^xsd:float ; geo:long "-122.41"^^xsd:float .
JenaBean comes with a few common vocabulary interfaces • thewebsemantic.vocabulary.Foaf • Geo • Ical • DCTerms • Sioc • Skos • Rdfs • ReviewVocab • You may want to copy and modify in some cases.
Fluent API summary: • Your interface should extend thewebsemantic.As • Provides polymorphic “as(Class)” to other vocabs. • Provides easy type declaration with “isa(Class)” • Use the @Namespace annotation to bind to the vocabulary • Name setters according to vocab, taking either an Object (literal) or anther Thing (relationship to other Individuals) • Name getters according to vocab, returning the same vocabulary type and taking no arguments. • If the vocabulary term collides with reserved term (as with long), append a dash. • Plural properties should return a Collection.
Create your own foaf document using the fluent interface. Integrate Jena/JenaBean with restlets restlets.org Use your favorite framework (struts, stripes, spring mvc) and create a user registration screen. Write JenaBeans that bind to jamendo or other music ontology at http://dbtune.org Write a foaf crawler beginning with Berners-Lee that traverses his social graph. Project Ideas cc nickjohnson http://flickr.com/photots/npj/
Java Triple Stores Jena (HP Labs) Sesame OpenRDF (Aduna) Mulgara Java Binding tools JenaBean (Jena) Jastor (Jena) Owl2Java (Jena) Elmo (Sesame) Empire Open Source Tools For Java Devs cc nickjohnson http://flickr.com/photots/npj/