Почему этот федеративный запрос SPARQL работает в TopBraid, но не в Apache Fuseki?

У меня есть следующий федеративный запрос SPARQL, который работает должным образом в TopBraid Composer Free Edition (версия 5.1.4), но не работает в Apache Fuseki (версия 2.3.1):

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT ?s WHERE {
    SERVICE <http://data.linkedmdb.org/sparql> {
        <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
        ?actor movie:actor_name ?actorName .
    }
    SERVICE <http://dbpedia.org/sparql?timeout=30000> {
        ?s ?p ?o .
        FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
    }
}

Я слежу за подзапросами SPARQL, которые выполняются под капотом, и замечаю, что TopBraid правильно выполняет следующий запрос к http://dbpedia.org/sparql:

SELECT  *
WHERE
  { ?s ?p ?o
    FILTER regex(str(?s), replace("Paul Reubens", " ", "_"))
  }

в то время как Apache Fuseki выполняет следующий подзапрос:

 SELECT  *
WHERE
  { ?s  ?p  ?o
    FILTER regex(str(?s), replace(?actorName, " ", "_"))
  }

Обратите внимание на разницу; TopBraid заменяет переменную ?actorName на конкретное значение Paul Reubens, а Apache Fuseki этого не делает. Это приводит к ошибке конечной точки http://dbpedia.org/sparql, поскольку в набор результатов, но не назначен.

Это ошибка в Apache Fuseki или функция в TopBraid? Как я могу заставить Apache Fuseki правильно выполнять этот федеративный запрос.

обновление 1: чтобы немного подробнее прояснить разницу в поведении TopBraid и Apache Fuseki. TopBraid сначала выполняет подзапрос connectedmdb.org, а затем выполняет подзапрос dbpedia.org для каждого результата запроса connectedmdb.org) (и заменяет имя исполнителя на результаты запроса connectedmdb.org). Я предположил, что Apache Fuseki ведет себя аналогичным образом, но первый подзапрос к dbpedia.org завершился ошибкой (потому что в результирующем наборе используется, но не назначается имя исполнителя), и поэтому он не продолжается. Но теперь я не уверен, действительно ли он хочет выполнить подзапрос к dbpedia.org несколько раз, потому что он никогда не попадает туда.

обновление 2: я думаю, что и TopBraid, и Apache Fuseki используют Jena / ARQ, но я заметил, что в трассировках стека из TopBraid имя пакета выглядит примерно как com.topbraid.jena. *, что может означать, что они используют модифицированная версия Jena / ARQ?

обновление 3: Джошуа Тейлор говорит ниже: «Разве вы не ожидаете, что второй служебный блок будет выполняться для каждого из них?». И TopBraid, и Apache Fuseki используют именно этот метод для следующего запроса:

PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT ?film ?label ?subject WHERE {
    SERVICE <http://data.linkedmdb.org/sparql> {
        ?film a movie:film .
        ?film rdfs:label ?label .
        ?film owl:sameAs ?dbpediaLink 
        FILTER(regex(str(?dbpediaLink), "dbpedia", "i"))
    }
    SERVICE <http://dbpedia.org/sparql> {
        ?dbpediaLink dcterms:subject ?subject
    }
}
LIMIT 50

но я согласен с тем, что в принципе они должны выполнить обе части один раз и присоединиться к ним, но, может быть, из соображений производительности они выбрали другую стратегию?

Кроме того, обратите внимание, как указанный выше запрос работает в Apache Fuseki, а первый запрос этого сообщения - нет. Итак, в данном конкретном случае Apache Fuseki ведет себя аналогично TopBraid. Похоже, это связано с использованием переменной URI (? DbpediaLink) в двух тройных шаблонах (которая работает в Fuseki) по сравнению с использованием переменной String (? тройной шаблон в функции регулярного выражения FILTER (который не работает в Fuseki).


person Barry NL    schedule 12.07.2016    source источник
comment
Конечно, проблема в Fuseki, но мне интересно, будет ли запрос работать в Fuseki без параметра timeout в URL-адресе конечной точки?   -  person scotthenninger    schedule 12.07.2016
comment
@scotthenninger Я не уверен, что это ошибка Фусеки; подзапросы выполняются первыми, и это может быть то же самое для запросов service. В этом случае значение, связанное с первым запросом службы, не должно быть доступно во втором запросе службы.   -  person Joshua Taylor    schedule 12.07.2016
comment
Учитывая, что SPARQL является декларативным языком, значения запросов подграфа должны быть доступны. Детали реализации федеративных запросов представляют собой проблему. Поскольку оба используют Jena, мне интересно, не речь идет о разных версиях Jena.   -  person scotthenninger    schedule 12.07.2016
comment
Тем не менее, ?s ?p ?o запрос с таймаутом, который произвольно прерывает выполнение, не является хорошим выбором. LIMIT было бы лучше, а сокращение запроса до определенных членов класса DBPedia было бы еще лучше   -  person scotthenninger    schedule 12.07.2016
comment
@scotthenninger Если подумать об этом подробнее, ваша точка зрения на то, что это декларативный язык, является хорошей. SPARQL является декларативным, и запрос должен иметь те же результаты, если порядок вызовов службы был отменен. Но если бы блоки service были перевернуты, то результатов не было бы: запрос DBpedia не должен возвращать никаких значений, потому что ?actorName не будет иметь значения, и фильтр не сможет работать успешно. Итак, то, что делает TopBraid, неправильно, потому что он дает результаты, отличные от результатов запроса с перевернутыми службами, которые логически должны быть одинаковыми. Я обновил свой ответ.   -  person Joshua Taylor    schedule 12.07.2016
comment
Если запрос выполняется с помощью редактора запросов в TopBraid, он просто передается в Jena ARQ. Кажется маловероятным, что Фусеки работает иначе, но это возможно. Поэтому, кроме различий в версиях Jena, я не вижу, как один и тот же движок SPARQL дает разные результаты.   -  person scotthenninger    schedule 12.07.2016


Ответы (2)


Обновленный (более простой) ответ

В исходном ответе, который я написал (ниже), я сказал, что проблема заключается в том, что запросы SPARQL выполняются в первую очередь. Я думаю, что это все еще применимо и здесь, но я думаю, что проблему можно изолировать еще проще. Если у вас есть

service <ex1> { ... }
service <ex2> { ... }

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

service <ex1> { values ?a { 1 2 3 } }
service <ex2> { values ?a { 2 3 4 } }

будет выполняться, и у вас будет два возможных значения для ? a во внешнем запросе (2 и 3). В вашем запросе вторая служба не может дать никаких результатов. Если взять:

?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .

и выполнить его в DBpedia, вы не должны получить никаких результатов, потому что ?actorName не привязан, поэтому фильтр никогда не сработает. Похоже, что TopBraid сначала выполняет первую службу, а затем вводит полученные значения во вторую службу. Это удобно, но я не думаю, что это правильно, потому что он возвращает другие результаты, чем те, которые вы получили бы, если бы запрос DBpedia был выполнен первым, а другой запрос - вторым.

Оригинальный ответ

Подзапросы в SPARQL выполняются первыми внутри самого себя. Это означает, что такой запрос, как

select * {
  { select ?x { ?x a :Cat } }
  ?x foaf:name ?name
}

Сначала найдет всех кошек, а затем найдет их имена. «Возможные» значения для? X сначала определяются подзапросом, а затем эти значения для? X становятся доступными для внешнего запроса. Теперь, когда есть два подзапроса, например,

select * {
  { select ?x { ?x a :Cat } }
  { select ?x ?name { ?x foaf:name ?name } }
}

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

Насколько я понимаю, блоки службы имеют такую ​​же семантику. В вашем запросе у вас есть:

SERVICE <http://data.linkedmdb.org/sparql> {
    <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
    ?actor movie:actor_name ?actorName .
}
SERVICE <http://dbpedia.org/sparql?timeout=30000> {
    ?s ?p ?o .
    FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}

Вы говорите, что трассировка показывает, что TopBraid выполняет

SELECT  *
WHERE
  { ?s ?p ?o
    FILTER regex(str(?s), replace("Paul Reubens", " ", "_"))
  }

Если TopBraid уже выполнил первый блок службы и получил уникальное решение, это может быть приемлемой оптимизацией, но что, если, например, первый запрос вернул несколько привязок для? Разве вы не ожидаете, что второй сервисный блок будет выполняться для каждого из них? Вместо этого второй блок service выполняется так, как написано, и возвращает набор результатов, который будет соединен с набором результатов из первого.

Причина, по которой он, вероятно, «не работает» в Йене, заключается в том, что второй запрос на самом деле не связывает какие-либо переменные, поэтому в значительной степени необходимо просмотреть каждую тройку в данных, что, очевидно, это займет много времени.

Я думаю, что вы можете обойти это, вложив вызовы службы. Если все вложенные службы запускаются «локальной» конечной точкой (т. Е. Вложенный вызов службы не просит удаленную конечную точку выполнить другой удаленный запрос), то вы можете быть в состоянии сделать:

SERVICE <http://dbpedia.org/sparql?timeout=30000> {
    SERVICE <http://data.linkedmdb.org/sparql> {
      <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
      ?actor movie:actor_name ?actorName .
    }
    ?s ?p ?o .
    FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}

Это может дать вам ту оптимизацию, которую вы хотите, но все же кажется, что это может не сработать, если у DBpedia нет эффективных способов выяснить, какие тройки нужно получить, на основе вычисления replace < / сильный>. Вы просите DBpedia просмотреть все свои тройки, а затем сохранить те, в которых строковая форма темы соответствует определенному регулярному выражению. Вероятно, было бы лучше создать этот IRI вручную в подзапросе, а затем искать его. Т.е.,

SERVICE <http://dbpedia.org/sparql?timeout=30000> {
  { select ?actor {
      SERVICE <http://data.linkedmdb.org/sparql> {
        <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor . 
        ?actor movie:actor_name ?actorName .
      }
      bind(iri(concat("http://dbpedia.org/resource",
                      replace(?actorName," ","_")))
           as ?actor)
    } } 
  ?actor ?p ?o 
}
person Joshua Taylor    schedule 12.07.2016
comment
Я не верю, что от движков SPARQL требуется выполнение наизнанку. Я знаю, что это делает Йена, но это вариант реализации. - person scotthenninger; 12.07.2016
comment
DBPedia не принимает вызовы вложенных служб. Jena просто упаковывает вызов SERVICE с префиксами и т. Д. И отправляет запрос службе. В конце концов, вы просите службу вызвать службу, а DBPedia этого не сделает. - person scotthenninger; 12.07.2016
comment
Подвыбор не является допустимым запросом SPARQL, потому что субъект? Связан в тройном шаблоне. Следовательно, его нельзя использовать в операторе BIND. Однако это лучший подход, поскольку он не полагается на запрос SPO. - person scotthenninger; 12.07.2016
comment
@scotthenninger Фактический порядок выполнения не должен быть вывернутым наизнанку, но он должен быть концептуальным. В разделе 12 Подзапросы спецификации говорится, что из-за восходящего характера При оценке запроса SPARQL сначала логически оцениваются подзапросы, а результаты проецируются до внешнего запроса. Но, как я уже сказал, они ведут себя так логически, реализация может делать что-то в другом порядке, пока достигаются те же результаты. - person Joshua Taylor; 12.07.2016
comment
@scotthenninger Но в любом случае в том же разделе сказано: обратите внимание, что только переменные, спроецированные из подзапроса, будут видимы или находятся в области видимости для внешнего запроса. Если вызовы параллельных служб похожи на подзапросы, я не думаю, что значения, которые проецирует один, должны быть видны в области действия другого. В запросе OP OP просит движок обязательно выполнить первый вызов службы first, а затем передать эти привязки во второй вызов службы. Второй вызов службы не будет связывать никакие переменные самостоятельно (поскольку переменная в фильтре не может иметь никакого значения в этот момент). - person Joshua Taylor; 12.07.2016
comment
Наизнанку (функциональную) требуется для соединений. Все остальное - это оптимизация (по сути, объединение индексов). Точно так же, как log(1+2) означает переход 3 к функции журнала. - person AndyS; 12.07.2016

(длинный комментарий)

Рассмотреть возможность:

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT ?s WHERE {
    {
        <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
        ?actor movie:actor_name ?actorName .
    }
    {
        ?s ?p ?o .
        FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
    }
}

это тот же запрос, но без вызовов СЛУЖБЫ. ?actorName не входит в структуру внутренней секунды {}.

Поскольку соединение - это коммутативная операция, ответ на него такой же, как на первый запрос.

SELECT ?s WHERE {
    {
        ?s ?p ?o .
        FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
    }
    {
        <http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
        ?actor movie:actor_name ?actorName .
    }
}

Версия СЕРВИС подчеркивает это, потому что детали выполняются отдельно на разных машинах.

Соединение двух частей происходит по результатам каждой части.

person AndyS    schedule 12.07.2016