Как рекурсивно расширить пустые узлы в запросе конструкции 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