Позиция ЗНАЧЕНИЙ, по-видимому, имеет значение при использовании в BIND в SPARQL

#sparql

Вопрос:

Я пытаюсь понять, как ЗНАЧЕНИЯ ведут себя в отношении позиции в запросе. Идея состоит в том, чтобы использовать это для упрощения параметризации запросов SPARQL, которые исходят из шаблона.

Для большинства запросов это сработало так, как ожидалось, но теперь я столкнулся со случаем, который я не понимаю. Учитывая следующий запрос:

 SELECT * WHERE {

  # Hard coded version: 

  #BIND( (2020 - 2) AS ?year )

  # Works as expected:
  
  #VALUES ?startYear { 2020 }
  #BIND( (?startYear -2 ) AS ?year )

  # Does not work as expected: 
  # Year is "1" in Fuseki, empty in Stardog. The "-2" does not seem to have any effect in that scenario
  BIND( (?startYear -2 ) AS ?year )
  VALUES ?startYear { 2020 }
} 
 

Как вы можете видеть в комментариях, последнее не работает. Если ЗНАЧЕНИЯ находятся перед ПРИВЯЗКОЙ, все выглядит так, как ожидалось. В спецификации SPARQL 1.1 есть пример, в котором они перемещают ЗНАЧЕНИЯ, но я не могу найти объяснение тому, что я вижу здесь.

Почему это не работает, когда ЗНАЧЕНИЯ находятся в конце запроса, когда я использую его в ПРИВЯЗКЕ? В этом случае он хорошо работает в FILTER.

Комментарии:

1. важная часть содержится в спецификациях для BIND : «Использование BIND завершает предыдущий базовый шаблон графа» — это означает, что шаблон графа, включающий BIND в себя, оценивается перед VALUES предложением. И также обратите внимание, что a VALUES не помещает привязки во вложенные шаблоны графов. Это не похоже на нажатие фильтра в базах данных. Кстати, то же самое относится и к подзапросам.

2. ?год не определен в Fuseki.

Ответ №1:

Важна позиция BIND, а не ЗНАЧЕНИЯ. BIND в SPARQL всегда закрывает шаблон группового графа, т. Е. Он идет поверх всех шаблонов в том же {} блоке, которые предшествуют ему, см. https://www.w3.org/TR/sparql11-query/#bind

Это становится очевидным, если вы посмотрите на структуру запроса (так называемую «алгебру») в http://www.sparql.org/query-validator.html:

 SELECT *
WHERE {  
  VALUES ?startYear { 2020 }
  BIND( (?startYear -2 ) AS ?year )
}
 

имеет ли эта алгебра:

   9     (extend ((?year (- ?startYear 2)))
 10       (table (vars ?startYear)
 11         (row [?startYear 2020])
 12       ))))
 

ваше table VALUES и extend ваше BIND . Вычисляется BIND поверх VALUES и, следовательно ?startYear , имеет значение при вычитании 2.

 SELECT *
WHERE {  
  BIND( (?startYear -2 ) AS ?year )
  VALUES ?startYear { 2020 }
}
 

однако имеет следующую алгебру:

   9     (join
 10       (extend ((?year (- ?startYear 2)))
 11         (table unit))
 12       (table (vars ?startYear)
 13         (row [?startYear 2020])
 14       ))))
 

Здесь ничто не предшествует BIND в его блоке, и поэтому вы видите table unit его в качестве аргумента (это так называемая пустая группа). Он не связывает никаких переменных, поэтому ?startYear не имеет значения при BIND вычислении. Затем результат привязки соединяется с VALUES , но слишком поздно, поскольку - 2 это уже произошло.

Я всегда рекомендую использовать этот онлайн-инструмент для проверки семантики ваших запросов.