SPARQL-запрос работает в Fuseki, но не в Jena TDB
Мои данные организованы в несколько графиков. График, в котором сохраняется тройка, имеет значение. Структура данных сложна, но ее можно упростить следующим образом:
Мой магазин содержит торты, где есть иерархия различных типов тортов, все подклассы <cake>
<http://example.com/a1> a <http://example.com/applecake>
<http://example.com/a2> a <http://example.com/rainbowcake>
...
В зависимости от того, как они создаются пользователем в пользовательском интерфейсе, они оказываются на другом графике. Например, если пользователь "печет" торт, он отправляется в <http://example.com/homemade>
график, если они "покупают" один, он идет в <http://example.com/shopbought>
граф.
Когда я получаю свои пирожные в магазине, я хочу знать для каждого пирога, самодельный или купленный в магазине. Для этого нет свойства, я хочу получить информацию исключительно на основе графика, в котором хранится тройка.
Я пробовал различные способы достижения этого, но ни один из них не работает в Jena TDB. Проблема в том, что все торты возвращаются как "купленные в магазине". Однако все запросы работают в Fuseki (на точном наборе данных sae), и мне было интересно, является ли это ошибкой TDB или есть другой способ. Вот упрощенные запросы (без вариантов):
Версия 1:
SELECT DISTINCT *
FROM <http://example.com/homemade>
FROM <http://example.com/shopbought>
FROM NAMED <http://example.com/homemade>
FROM NAMED <http://example.com/shopbought>
WHERE {
?cake rdf:type ?caketype .
?caketype rdfs:subClassOf* <cake>
{
GRAPH <http://example.com/homemade> { ?cake rdf:type ?typeHomemade }
} UNION {
GRAPH <http://example.com/shopbought> { ?cake rdf:type ?typeShopbought }
}
BIND(str(if(bound(?typeHomemade), true, false)) AS ?homemade)
}
Версия 2:
SELECT DISTINCT *
FROM <http://example.com/homemade>
FROM <http://example.com/shopbought>
FROM NAMED <http://example.com/homemade>
FROM NAMED <http://example.com/shopbought>
WHERE {
?cake rdf:type ?caketype .
?caketype rdfs:subClassOf* <cake>
GRAPH ?g {
?cake rdf:type ?caketype .
}
BIND(STR(IF(?g=<http://example.com/homemade>, true, false)) AS ?homemade)
}
Есть идеи, почему это работает в Fuseki, но не в TDB?
Изменить: я начинаю думать, что это как-то связано с ключевым словом GRAPH. Вот несколько более простых запросов (которые работают в Fuseki и tdbquery) и результаты, которые я получаю с помощью Jena API:
SELECT * WHERE { GRAPH <http://example.com/homemade> { ?s ?p ?o }}
0 результатов
SELECT * WHERE { GRAPH ?g { ?s ?p ?o }}
0 результатов
SELECT * FROM <http://example.com/homemade> WHERE { ?s ?p ?o }
х результаты
SELECT * FROM <http://example.com/homemade> WHERE { GRAPH <http://example.com/homemade> { ?s ?p ?o }}
0 результатов
SELECT * FROM NAMED <http://example.com/homemade> WHERE { GRAPH <http://example.com/homemade> { ?s ?p ?o }}
0 результатов
1 ответ
Итак, мое решение на самом деле связано с тем, как я выполнил запрос. Моя первоначальная идея состояла в том, чтобы предварительно отфильтровать набор данных так, чтобы запрос выполнялся только для соответствующих графиков (набор данных содержит много графиков, и они могут быть довольно большими, что сделает запрос "все" медленным). Это может быть сделано либо путем добавления их в SPARQL, либо непосредственно в Jena (хотя это не будет работать для других тройных магазинов). Однако объединение обоих способов "быть на безопасной стороне" не работает.
Этот запрос выполняется для всего набора данных и работает как положено:
Query query = QueryFactory.create("SELECT * WHERE { GRAPH ?g { ?s ?p ?o } }", Syntax.syntaxARQ);
QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
ResultSet result = qexec.execSelect();
Тот же запрос может быть выполнен только для определенного графа, где не имеет значения, какой граф, он не дает никаких результатов:
//run only on one graph
Model target = dataset.getNamedModel("http://example.com/homemade");
//OR run on the union of all graphs
Model target = dataset.getNamedModel("urn:x-arq:UnionGraph");
//OR run on a union of specific graphs
Model target = ModelFactory.createUnion(dataset.getNamedModel("http://example.com/shopbought"), dataset.getNamedModel("http://example.com/homemade"), ...);
[...]
QueryExecution qexec = QueryExecutionFactory.create(query, target);
[...]
Мой обходной путь заключался в том, чтобы теперь всегда запрашивать весь набор данных (который отлично поддерживает ключевое слово SPARQL GRAPH) и для каждого запроса всегда указывать графики, на которых он должен выполняться, чтобы избежать необходимости запрашивать весь набор данных. Не уверен, что это ожидаемое поведение для Jena API