Как рекурсивно расширить пустые узлы в запросе конструкции SPARQL?
Вероятно, на это легко ответить, но я даже не могу понять, как сформулировать запрос Google, чтобы найти его.
Я пишу строковые запросы SPARQL к набору данных, содержащему пустые узлы. Поэтому, если я делаю запрос типа
CONSTRUCT {?x ?y ?z .}
WHERE {?x ?y ?z .}
Тогда один из моих результатов может быть:
nm:John nm:owns _:Node
Это проблема, если все
_:Node nm:has nm:Hats
тройки также не попадают в результат запроса (потому что некоторые парсеры, которые я использую как rdflib для Python, действительно не любят болтающиеся bnodes).
Есть ли способ написать мой первоначальный запрос CONSTRUCT для рекурсивного добавления всех троек, прикрепленных к любым результатам bnode, таким образом, чтобы на моем новом графике не осталось ни одного bnodes?
Ответы
Ответ 1
Рекурсия невозможна. Ближайшим, о котором я могу думать, является пути свойств SPARQL 1.1 (обратите внимание: эта версия устарела), но тесты bnode недоступны (afaik).
Вы можете просто удалить инструкции с завершающими bnodes:
CONSTRUCT {?x ?y ?z .} WHERE
{
?x ?y ?z .
FILTER (!isBlank(?z))
}
или попробуйте получить следующий бит:
CONSTRUCT {?x ?y ?z . ?z ?w ?v } WHERE
{
?x ?y ?z .
OPTIONAL {
?z ?w ?v
FILTER (isBlank(?z) && !isBlank(?v))
}
}
(этот последний запрос довольно наказывается, btw)
Вам может быть лучше с DESCRIBE
, который часто пропускает bnodes.
Ответ 2
Как указывает пользователь205512, выполнение этого захвата рекурсивно невозможно, и, как они отмечают, использование необязательных (ых) вариантов произвольного уровня в ваших данных, получение узлов не представляется возможным ни на чем, кроме баз данных нетривиального размера.
Bnodes сами локально привязаны к набору результатов или к файлу. Там нет гарантии, что BNode вы получаете от разбора или из набора результатов - это тот же идентификатор, который используется в базе данных (хотя некоторые базы данных гарантируют это для результатов запроса). Кроме того, такой запрос, как "select? S, где {? S? P_: bnodeid1}", совпадает с "select? Where {? S? P? O}" - обратите внимание, что bnode рассматривается как переменная в этом случае, а не как "вещь с идентификатором" bnodeid1 ". Эта причуда конструкции затрудняет запрос для bnodes, поэтому, если вы контролируете данные, я бы предложил не использовать их. Нетрудно сгенерировать имена для вещей, которые иначе были бы bnodes, а имена ресурсов v. Bnodes не будут увеличивать накладные расходы во время запросов.
Это не поможет вам сбрасывать и захватывать данные, но для этого я не рекомендую делать такие общие запросы; они плохо масштабируются и обычно возвращаются больше, чем вы хотите или нуждаетесь. Я предлагаю вам делать больше направленных запросов. Ваш исходный запрос конструкции приведет к потере содержимого всей базы данных, что обычно не то, что вы хотите.
Наконец, хотя описание может быть полезным, нет стандартной реализации; спецификация SPARQL не определяет какого-либо конкретного поведения, поэтому то, что оно возвращает, предоставляется поставщику базы данных, и это может быть другим. Это может сделать ваш код менее портативным, если вы планируете попробовать различные базы данных с вашим приложением. Если вы хотите, чтобы конкретное поведение не описывалось, вам лучше всего реализовать его самостоятельно. Выполнение чего-то вроде краткого описания ресурса - это простой фрагмент кода, хотя вы можете столкнуться с некоторыми головными болями вокруг Bnodes.
Ответ 3
Что касается работы с рубиновой библиотекой RDF.rb, которая позволяет запросы SPARQL со значительными удобными методами в объектах RDF:: Graph, следующее должно расширять пустые узлы.
rdf_type = RDF::SCHEMA.Person # for example
rdf.query([nil, RDF.type, rdf_type]).each_subject do |subject|
g = RDF::Graph.new
rdf.query([subject, nil, nil]) do |s,p,o|
g << [s,p,o]
g << rdf_expand_blank_nodes(o) if o.node?
end
end
def rdf_expand_blank_nodes(object)
g = RDF::Graph.new
if object.node?
rdf.query([object, nil, nil]) do |s,p,o|
g << [s,p,o]
g << rdf_expand_blank_nodes(o) if o.node?
end
end
g
end