模式中的备选方案(Alternatives in a Pattern)
在处理半结构化数据时,另一种方法是查询可能性中的其中一种。本节将介绍 UNION 模式,即从多种可能性中选择一种进行查询。
在使用 UNION 关键字时,如果两个子模式都匹配,并且它们的结果有重叠,那么查询结果中可能会包含重复的值。就是说不管两个子模式的变量是否相同,都会输出两个值。
使用 UNION 操作符来实现获取相同数据的两种方式。
vCard词汇表和FOAF词汇表都有用于表示人名的属性。在vCard中,这个属性是vCard:FN,它代表“格式化名称”;而在FOAF中,这个属性是foaf:name。在本节中,我们将查看一小部分数据,其中的人名可以用 FOAF 或 vCard 词汇表给出。
假设我们有 一个 RDF 图 ,其中包含使用 vCard 和 FOAF 词汇表的姓名信息。下面的两部分是 RDF 文件的 Turtle 格式。
1、如果一个节点具有两个属性,属性间用 “;” 隔开。
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
_:a a foaf:Person ;
foaf:name "Matt Jones" .
_:b a foaf:Person ;
foaf:name "Sarah Jones";
vcard:FN "Sarah Jones11111" .
_:c a foaf:Person ;
vcard:FN "Becky Smith" .
_:d a foaf:Person ;
vcard:FN "John Smith" .
2、如果一个节点具有两个属性,属性间用 “,” 隔开。
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
_:a foaf:name "Matt Jones", "2313521" .
_:b foaf:name "Sarah Jones" .
_:c vcard:FN "Becky Smith" .
_:d vcard:FN "John Smith" .
[]
是一个空白节点(匿名资源)的缩写。它表示一个不具体的资源,相当于占位符。在这个模式中,它表示我们不关心这个资源是什么,只要它有 foaf:name 属性即可。当名称信息可以是两种形式时,访问名称信息的查询可以是 (q-union1.rq):
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name
WHERE
{
{ [] foaf:name ?name } UNION { [] vCard:FN ?name }
}
这将返回以下结果:
-----------------
| name |
=================
| "Matt Jones" |
| "Sarah Jones" |
|"Sarah Jones02"|
| "Becky Smith" |
| "John Smith" |
-----------------
Java 代码如下:
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryExecutionFactory;
import org.apache.jena.query.QueryFactory;
import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Union01 {
static final String inputFileName = "java01/src/main/java/come/jena/rdf/test02.ttl";
public static void main(String[] args) {
// Load RDF data into a model
Model model = ModelFactory.createDefaultModel();
InputStream inputStream = null;
try {
inputStream = new FileInputStream(inputFileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RDFDataMgr.read(model, inputStream, Lang.TURTLE);
// Define a SPARQL query
String queryString = "PREFIX pr:<http://www.w3.org/2001/vcard-rdf/3.0#>\n" +
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n" +
"SELECT ?name " +
"WHERE { { [] foaf:name ?name } UNION { [] pr:FN ?name }}";
Query query = QueryFactory.create(queryString);
// Execute the query
try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) {
ResultSet results = qexec.execSelect();
// Process the query results
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
//System.out.println(soln);
//System.out.println( soln);
System.out.println("name: " + soln.get("?name"));
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
运行结果:
名称使用哪种表达式并不重要,重要的是设置名称变量。正如本查询(q-union-1alt.rq)所示,使用 FILTER 可以实现这一目的,这两种查询的结果一样:
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name
WHERE
{
[] ?p ?name
FILTER ( ?p = foaf:name || ?p = vCard:FN )
}
Java 代码如下:
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryExecutionFactory;
import org.apache.jena.query.QueryFactory;
import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Union01 {
static final String inputFileName = "java01/src/main/java/come/jena/rdf/test02.ttl";
public static void main(String[] args) {
// Load RDF data into a model
Model model = ModelFactory.createDefaultModel();
InputStream inputStream = null;
try {
inputStream = new FileInputStream(inputFileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RDFDataMgr.read(model, inputStream, Lang.TURTLE);
// Define a SPARQL query
String queryString = "PREFIX pr:<http://www.w3.org/2001/vcard-rdf/3.0#>\n" +
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n" +
"SELECT ?name " +
"WHERE { [] ?p ?name . " +
" FILTER (?p = foaf:name || ?p = pr:FN) }";
Query query = QueryFactory.create(queryString);
// Execute the query
try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) {
ResultSet results = qexec.execSelect();
// Process the query results
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
System.out.println("name: " + soln.get("?name"));
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
运行结果:
测试属性是一个 URI 还是另一个 URI。解决方案的顺序可能不尽相同。 第一种形式更有可能更快,这取决于所使用的数据和存储,因为第二种形式可能需要从图中获取所有三元组,以匹配每个未绑定变量(或空白节点)的三元组模式,然后测试每个 ?p
是否与其中一个值相匹配。这将取决于查询优化器的复杂程度,即它是否发现可以更有效地执行查询,并能将约束向下传递以及传递到存储层。
UNION-记住数据是在哪里找到的。
上面的例子在每个分支中使用了相同的变量。如果使用不同的变量,则应用程序可以发现导致匹配的子模式(q-union2.rq):
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name1 ?name2
WHERE
{
{ [] foaf:name ?name1 } UNION { [] vCard:FN ?name2 }
}
查询结果:
---------------------------------
| name1 | name2 |
=================================
| "Matt Jones" | |
| "Sarah Jones" | |
|"Sarah Jones02"| |
| | "Becky Smith" |
| | "John Smith" |
---------------------------------
Java 代码如下:
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryExecutionFactory;
import org.apache.jena.query.QueryFactory;
import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Union01 {
static final String inputFileName = "java01/src/main/java/come/jena/rdf/test02.ttl";
public static void main(String[] args) {
// Load RDF data into a model
Model model = ModelFactory.createDefaultModel();
//model.read(inputFileName); // Load your RDF data file
InputStream inputStream = null;
try {
inputStream = new FileInputStream(inputFileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RDFDataMgr.read(model, inputStream, Lang.TURTLE);
// Define a SPARQL query
String queryString = "PREFIX pr:<http://www.w3.org/2001/vcard-rdf/3.0#>\n" +
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n" +
"SELECT ?name1 ?name2 " +
"WHERE { { [] foaf:name ?name1 } UNION { [] pr:FN ?name2 } }";
Query query = QueryFactory.create(queryString);
// Execute the query
try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) {
ResultSet results = qexec.execSelect();
// Process the query results
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
System.out.print("name1: " + soln.get("name1"));
System.out.println(" name2: " + soln.get("name2"));
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
运行结果:
第二个查询通过将姓名分配给不同的变量,保留了姓名来源的信息。
OPTIONAL and UNION
在实际应用中,OPTIONAL 比 UNION 更常用,但两者都有各自的用途。OPTIONAL 用于扩充找到的解决方案,而 UNION 则用于连接两种可能性的解决方案。它们不一定以相同的方式返回信息:
查询(q-union3.rq):
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name1 ?name2
WHERE
{
?x a foaf:Person
OPTIONAL { ?x foaf:name ?name1 }
OPTIONAL { ?x vCard:FN ?name2 }
}
查询结果:
---------------------------------
| name1 | name2 |
=================================
| "Matt Jones" | |
| "Sarah Jones" | |
|"Sarah Jones02"| |
| | "Becky Smith" |
| | "John Smith" |
---------------------------------
但要注意在每个 OPTIONAL 中使用 ?name
,因为这是一个取决于顺序的查询。
Jena 官方文档:https://jena.apache.org/tutorials/sparql_union.html
下一篇:命名图