Условный подзапрос в функции SPIN (SPARQL)

Как изменить формулу запроса в зависимости от того, привязана переменная или нет?

Я вызываю магическое свойство следующим образом:

WHERE {
    VALUES (?subj) {
        ([my bound positional parameter value goes here...])
    }
    ?subj :myMagicProperty ?result .    
}

Внутри магического свойства я делаю союз:

?result a :Rule .
{
    ?result :someProp ?subj .
}
UNION
{
    FILTER NOT EXISTS {
        ?result :someProp ?anyValue .
    }
}

Другими словами, получить все результаты, где :someProp означает это значение, или :someProp не определено.

Вот сложная часть. Если ?subj не привязан (т. е. я установил его как UNDEF в блоке VALUES), приведенный выше запрос сходит с ума и возвращает все.

Вместо этого я хочу проверить, не привязан ли ?subj. Если ?subj не привязан, :myMagicProperty должен только возвращать следующие результаты:

FILTER NOT EXISTS {
    ?result ?someProp ?anyValue .
}

Я экспериментировал с использованием FILTER и функции BOUND, но не могу понять, как добиться правильного поведения. Как удалить одно из предложений UNION из моего запроса, если ?subj не привязано?

Обновления

В первый запрос добавлен блок VALUES.
Добавлен отсутствующий оператор ?result a :Rule ..
Исправлено ?someProp на :someProp.


person RMorrisey    schedule 12.10.2015    source источник


Ответы (3)


Сначала я хотел бы подтвердить ваши намерения. Я хотел бы сделать это, попросив вас ответить на следующий запрос, который вы можете запустить в TopBraid Composer.

SELECT *
  WHERE { GRAPH <http://topbraid.org/examples/kennedys> {
    VALUES (?property) {(kennedys:firstName) (kennedys:lastName) (UNDEF)}
    { 
      FILTER(BOUND(?property) )
      ?s ?property ?result .  
    }
  UNION 
   {
     FILTER(!BOUND(?property))
     BIND("not sure what you want to do in this case" AS ?result)
    }
   }
 }

Отличие приведенного выше кода от вашего заключается в том, что я устанавливаю значения вашего ?someProp в операторе VALUES, тогда как вы устанавливаете ?subj.

Объединенные подграфы используют BOUND и !BOUND в качестве защиты.

Прежде чем идти дальше с помощью, я хотел бы услышать от вас более четкое объяснение запроса, который вы хотите построить. Тогда я смогу показать вам волшебное свойство, которое понадобится.

Это часть вашего первоначального поста, которую мне нужно понять больше:

А вот и сложная часть. Если ?subj не привязан (т. е. я установил его как UNDEF в блоке VALUES), приведенный выше запрос сходит с ума и возвращает все.

Вместо этого я хочу проверить, не привязан ли ?subj. Если ?subj не привязан, myMagicProperty должен возвращать только следующие результаты:

FILTER NOT EXISTS {
   ?result ?someProp ?anyValue .
}*

Что вы ожидали получить с ?someProp undefined, а также ?result и ?anyValue? Также этот ваш подграф не имеет утверждений, которые заполнили бы граф и, следовательно, ничего не вернут.


Ральф

person ralphtq    schedule 13.10.2015
comment
Ральф, я обновил определение своего магического свойства в вопросе, чтобы добавить термин, отсутствующий в примере кода. Цель состоит в том, чтобы при заданном значении ?subj для всех ресурсов Rule найти правила, которые имеют rule.someProp == subj ИЛИ rule.someProp == null (свойство не определено). Если входное значение ?subj равно null, возвращаются только правила, где rule.someProp == null. - person RMorrisey; 13.10.2015
comment
Я пытался использовать что-то вроде FILTER(BOUND(?property) ), но я обнаружил, что ?property связывается из-за оператора под ним в том же блоке, поэтому он не отфильтровывает результаты так, как я хочу. к. - person RMorrisey; 13.10.2015

Хитрость в том, что мне нужно выполнить UNION, используя переменную отличную от той, которая была передана в качестве аргумента. Таким образом, операция UNION не приводит к связыванию несвязанного параметра. После UNION я могу использовать FILTER для управления результатами на основе входного параметра.

SELECT ?result
WHERE {
    ?result a :Rule .
    {
        SELECT ?rule ?value ?anyValueMatch
        WHERE {
            {
                ?rule :someProp ?value .
                BIND (false AS ?anyValueMatch) .
            }
            UNION
            {
                FILTER NOT EXISTS {
                    ?rule :someProp ?any .
                } .
                BIND (true AS ?anyValueMatch) .
            } .
        }
    } .
    FILTER ((bound(?subj) && (?value = ?subj)) || (?anyValueMatch = true)) .
}
person RMorrisey    schedule 13.10.2015

Другой способ сделать это с помощью COALESCE:

SELECT ?result
WHERE {
   ?result a :Rule .
   OPTIONAL {
      ?result :someProp ?value .
   }
   FILTER (COALESCE(?value = ?subj, !bound(?value)))
}

... это позволяет избежать подвыборки и просто фильтрует, чтобы включить только совпадения ?result, где '?value = ?subj', и если это предложение не выполняется, предложение !bound() гарантирует, что совпадения, которые не имеют свойства :someProp также включены.

person scotthenninger    schedule 18.02.2016