blob: 35a2590d31d53eba25ea77319680e263b5b2634b [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - ARQ Property Paths</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/query/property_paths.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item"><a href='/documentation/query'>QUERY</a></li>
<li class="breadcrumb-item active">PROPERTY PATHS</li>
</ol>
</div>
<h1 class="title">ARQ Property Paths</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#path-language">Path Language</a></li>
<li><a href="#path-evaluation">Path Evaluation</a></li>
<li><a href="#extended-language">Extended Language</a></li>
<li><a href="#examples">Examples</a>
<ul>
<li><a href="#simple-paths">Simple Paths</a></li>
<li><a href="#complex-paths">Complex Paths</a></li>
</ul>
</li>
<li><a href="#use-with-legal-sparql-syntax">Use with Legal SPARQL Syntax</a></li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<h1 id="arq---property-paths">ARQ - Property Paths</h1>
<p>A property path is a possible route through a graph between two
graph nodes. A trivial case is a property path of length exactly
one, which is a triple pattern.</p>
<p>Most property paths are now legal SPARQL 1.1 syntax, there are some advanced property
paths which are syntactic extensions and are only available if the query is parsed with language <code>Syntax.syntaxARQ</code>.</p>
<h2 id="path-language">Path Language</h2>
<p>A property path expression (or just &lsquo;path&rsquo;) is similar to a string
regular expression but over properties, not characters. ARQ
determines all matches of a path expression and binds subject or
object as appropriate. Only one match is recorded - no duplicates
for any given path expression, although if the path is used in a
situation where it&rsquo;s initial points is already repeated in a
pattern, then this duplication is preserved.</p>
<table>
<thead>
<tr>
<th>Path example</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt>dc:title | rdfs:label</tt></td>
<td>Dublin Core title or an RDFS label.</td>
</tr>
<tr>
<td><code>foaf:knows/foaf:name</code></td>
<td>Name of people one &ldquo;knows&rdquo; steps away.</td>
</tr>
<tr>
<td><code>foaf:knows/foaf:knows/foaf:name</code></td>
<td>Name of people two &ldquo;knows&rdquo; steps away.</td>
</tr>
</tbody>
</table>
<p>In the description below, <em><code>uri</code></em> is either a URI or a prefixed
name.</p>
<table>
<thead>
<tr>
<th>Syntax Form</th>
<th>Matches</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt><i>uri</i></tt></td>
<td>A URI or a prefixed name. A path of length one.</td>
</tr>
<tr>
<td><tt>^<i>elt</i></tt></td>
<td>Reverse path (object to subject)</td>
</tr>
<tr>
<td><tt>(<i>elt</i>)</tt></td>
<td>A group path <em><code>elt</code></em>, brackets control precedence.</td>
</tr>
<tr>
<td><tt><i>elt1</i> / <i>elt2</i></tt></td>
<td>A sequence path of <em><code>elt1</code></em>, followed by <em><code>elt2</code></em></td>
</tr>
<tr>
<td><tt><i>elt1</i> | <i>elt2</i></tt></td>
<td>A alternative path of <tt><i>elt1</i></tt>, or <tt><i>elt2</i></tt> (both possibilities are tried)</td>
</tr>
<tr>
<td><tt><i>elt</i>*</tt></td>
<td>A path of zero or more occurrences of <em><code>elt</code></em>.</td>
</tr>
<tr>
<td><tt><i>elt</i>+</tt></td>
<td>A path of one or more occurrences of <em><code>elt</code></em>.</td>
</tr>
<tr>
<td><tt><i>elt</i>?</tt></td>
<td>A path of zero or one <em><code>elt</code></em>.</td>
</tr>
<tr>
<td><tt>!<i>uri</i></tt></td>
<td>A path matching a property which isn&rsquo;t <tt><i>uri</i></tt> (negated property set)</td>
</tr>
<tr>
<td><tt>!(<i>uri1</i>|&hellip;|<i>uriN</i>)</tt></td>
<td>A path matching a property which isn&rsquo;t any of <code>uri1 ... uri</code> (negated property set)</td>
</tr>
</tbody>
</table>
<p>ARQ extensions: to use these you must use <code>Syntax.syntaxARQ</code></p>
<table>
<thead>
<tr>
<th>Syntax Form</th>
<th>Matches</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt><i>elt1</i> ^ <i>elt2</i></tt></td>
<td>Shorthand for <tt><i>elt1 / ^elt2</i></tt>, that is <em><code>elt1</code></em> followed by reverse <em><code>elt2</code></em>.</td>
</tr>
<tr>
<td><i><tt>elt</tt></i><code>{n,m}</code></td>
<td>A path between n and m occurrences of <em><code>elt</code></em>.</td>
</tr>
<tr>
<td><i><tt>elt</tt></i><code>{n}</code></td>
<td>Exactly <code>n</code> occurrences of <code>elt</code>. A fixed length path.</td>
</tr>
<tr>
<td><i><tt>elt</tt></i><code>{n,}</code></td>
<td><code>n</code> or more occurrences of <em><code>elt</code></em>.</td>
</tr>
<tr>
<td><i><tt>elt</tt></i><code>{,n}</code></td>
<td>Between 0 and <code>n</code> occurrences of <em><code>elt</code></em>.</td>
</tr>
</tbody>
</table>
<p>Precedence:</p>
<ol>
<li>URI, prefixed names</li>
<li>Negated property set</li>
<li>Groups</li>
<li>Unary ^ reverse links</li>
<li>Unary operators <code>*</code>, <code>?</code>, <code>+</code> and <code>{}</code> forms</li>
<li>Binary operators <code>/</code> and ^</li>
<li>Binary operator <code>|</code></li>
</ol>
<p>Precedence is left-to-right within groups.</p>
<h2 id="path-evaluation">Path Evaluation</h2>
<p>Paths are &ldquo;simple&rdquo; if they involve only operators / (sequence), ^
(reverse, unary or binary) and the form {<em>n</em>}, for some single
integer <em>n</em>. Such paths are fixed length. They are translated to
triple patterns by the query compiler and do not require special
path-evaluation at runtime.</p>
<p>A path of just a URI is still a single triple pattern.</p>
<p>A path is &ldquo;complex&rdquo; if it involves one or more of the operators
*,?, + and {}. Such paths require special evaluation and provide
expressivity outside of strict SPARQL because paths can be of
variable length. When used with models backed by SQL databases,
complex path expressions may take some time.</p>
<p>A path of length zero connects a graph node to itself.</p>
<p>Cycles in paths are possible and are handled.</p>
<p>Paths do not need to be anchored at one end of the other, although
this can lead to large numbers of result because the whole graph is
searched.</p>
<p>Property functions in paths are only available for simple paths.</p>
<h2 id="extended-language">Extended Language</h2>
<p>This involves is syntactic extension and is available if the query
is parsed with language <code>Syntax.syntaxARQ</code>.</p>
<p>Paths can be directly included in the query in the property
position of a triple pattern:</p>
<pre><code>PREFIX : &lt;http://example/&gt;
PREFIX rdf: &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt;
# Find the types of :x, following subClassOf
SELECT *
{
:x rdf:type/rdfs:subClassOf* ?t
}
</code></pre>
<h2 id="examples">Examples</h2>
<h3 id="simple-paths">Simple Paths</h3>
<p>Find the name of any people that Alice knows.</p>
<pre><code>{
?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows/foaf:name ?name .
}
</code></pre>
<p>Find the names of people 2 &ldquo;<code>foaf:knows</code>&rdquo; links away.</p>
<pre><code>{
?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows/foaf:knows/foaf:name ?name .
}
</code></pre>
<p>This is the same as the strict SPARQL query:</p>
<pre><code>{
?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows [ foaf:knows [ foaf:name ?name ]].
}
</code></pre>
<p>or, with explicit variables:</p>
<pre><code>{
?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows ?a1 .
?a1 foaf:knows ?a2 .
?a2 foaf:name ?name .
}
</code></pre>
<p>Because someone Alice knows may well know Alice, the example above
may include Alice herself. This could be avoided with:</p>
<pre><code>{ ?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows/foaf:knows ?y .
FILTER ( ?x != ?y )
?y foaf:name ?name
}
</code></pre>
<p>These two are the same query: the second is just reversing the
property direction which swaps the roles of subject and object.</p>
<pre><code>{ ?x foaf:mbox &lt;mailto:alice@example&gt; }
{ &lt;mailto:alice@example&gt; ^foaf:mbox ?x }
</code></pre>
<p>Mutual <code>foaf:knows</code> relationships: <code>?x</code> knows someone who knows
<code>?x</code></p>
<pre><code>{
?x foaf:knows^foaf:knows ?x .
}
</code></pre>
<p>Negated property sets define matching by naming one or more
properties that must not match. Match if there is a triple from
<code>?x</code> to <code>?y</code> which is not <code>rdf:type</code>.</p>
<pre><code>{
?x !rdf:type ?y .
}
{
?x !(rdf:type|^rdf:type) ?y .
}
</code></pre>
<p>Only properties and reverse properties are allowed in a negated
property set, not a full path expression.</p>
<h3 id="complex-paths">Complex Paths</h3>
<p>Find the names of all the people can be reached from Alice by
<code>foaf:knows</code>:</p>
<pre><code>{
?x foaf:mbox &lt;mailto:alice@example&gt; .
?x foaf:knows+/foaf:name ?name .
}
</code></pre>
<p>Again, because of cycles in <code>foaf:knows</code> relationships, it is
likely to include Alice herself.</p>
<p>Some forms of limited inference are possible as well. For example:
all types and supertypes of a resource:</p>
<pre><code>{ &lt;http://example/&gt; rdf:type/rdfs:subClassOf* ?type }
</code></pre>
<p>All resources and all their inferred types:</p>
<pre><code>{ ?x rdf:type/rdfs:subClassOf* ?type }
</code></pre>
<h2 id="use-with-legal-sparql-syntax">Use with Legal SPARQL Syntax</h2>
<p>A path can parsed, then installed as a
<a href="extension.html#propertyFunctions">property function</a> to be
referred to by URI. This way, when the URI is used in the predicate
location in a triple pattern, the path expression is evaluated.</p>
<pre><code>Path path = ...
String uri = ...
PathLib.install(uri, path) ;
</code></pre>
<p>For example:</p>
<pre><code>Path path = PathParser.parse(&quot;rdf:type/rdfs:subClassOf*&quot;, PrefixMapping.Standard) ;
String uri = &quot;http://example/ns#myType&quot; ;
PathLib.install(uri, path) ;
</code></pre>
<p>and the SPARQL query:</p>
<pre><code>PREFIX : &lt;http://example/&gt;
PREFIX ns: &lt;http://example/ns#&gt;
# Find the types of :x, following subClassOf
SELECT * { :x ns:myType ?t}
</code></pre>
<p>This also works with if an existing property is redefined (a URI in
a path expression is not interpreted as a property function) so,
for example, <code>rdf:type</code> can be redefined as a path that also
considers RDFS sub -class relationships. The path is a complex path
so the property function for <code>rdf:type</code> is not triggered.</p>
<pre><code>Path path = PathParser.parse(&quot;rdf:type/rdfs:subClassOf*&quot;, PrefixMapping.Standard) ;
PathLib.install(RDF.type.getURI(), path) ;
</code></pre>
<p><a href="index.html">ARQ documentation index</a></p>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#path-language">Path Language</a></li>
<li><a href="#path-evaluation">Path Evaluation</a></li>
<li><a href="#extended-language">Extended Language</a></li>
<li><a href="#examples">Examples</a>
<ul>
<li><a href="#simple-paths">Simple Paths</a></li>
<li><a href="#complex-paths">Complex Paths</a></li>
</ul>
</li>
<li><a href="#use-with-legal-sparql-syntax">Use with Legal SPARQL Syntax</a></li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>