2015-03-15 1 views
1

Возьмите этот график:SPARQL алгебра: Исключение узлов на основе троек они

:thing1 a :Foo ; 
    :has :A ; 
    :has :B . 

:thing2 a :Foo ; 
    :has :B ; 
    :has :A . 

:thing3 a :Foo ; 
    :has :A ; 
    :has :B ; 
    :has :C . 

Я хочу, чтобы выбрать :thing1 и :thing2, но НЕ:thing3.

Вот запрос SPARQL, который я написал, который работает. Есть лучший способ сделать это?

SELECT ?foo WHERE { 
    ?foo a :Foo ; 
     :has :A ; 
     :has :B . 
    MINUS { 
     ?foo a :Foo ; 
      :has :A ; 
      :has :B ; 
      :has ?anythingElse . 
     FILTER(?anythingElse != :A && ?anythingElse != :B) 
    } 
} 

ответ

3

Альтернативой является МИНУС ФИЛЬТР НЕ СУЩЕСТВУЕТ:

SELECT ?foo WHERE { 
    ?foo a :Foo ; 
     :has :A, :B . 
    FILTER NOT EXISTS { 
     ?foo :has ?other . 
     FILTER (?other NOT IN (:A, :B)) 
    } 
} 

, который говорит, свободно, найти все Foo с: А и: B, а затем проверить, что у них нет никакой другой: имеет значение.

Что касается эффективности выполнения, то есть оптимизации, чтобы превратить некоторые шаблоны MINUS в FILTER NOT EXISTS и наоборот, а также есть возможность совместного использования общих паттернов.

Без оптимизатора, являющегося таким умным, FILTER NOT EXISTS, скорее всего, будет быстрее, потому что «? Foo a: Foo ;; имеет: A,: B». не повторяется, и FILTER рассматривает только те элементы, которые уже прошли «? foo a: Foo;; has: A,: B.».

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

+0

Я действительно считаю, что это на самом деле лучше, потому что минус-блок из исходного сообщения будет искать весь граф, тогда как фильтр не существует, будет искать только (и затем удалять) соответствующие тройки из результатов внешнего блока. Другими словами, это решение должно иметь лучшую производительность, поскольку оно удаляет тройки, которые ': has? Other' из подмножества троек, которые': имеют: A,: B'. Не могли бы вы добавить это объяснение в свое решение?Тогда я был бы рад принять его как ответ :) –

+0

Это немного сложнее, чем это :-). Оптимизатор может обнаружить, что форма MINUS может быть преобразована в форму FILTER NOT EXIST или может видеть, что блок MINUS может совместно использовать вычисления с основной частью и использовать это. Тем не менее, это сложная оптимизация (они не всегда работают), и я не считаю, что многие системы пытаются их использовать. В ARQ, FILTER NOT EXISTS является формой быстрее для этого случая, когда MINUS имеет множество общих черт. – AndyS

0

Вы можете сделать это с помощью использования NOT IN оператора вместо логического выражения, и в самом деле нет необходимости повторять три тройные модели, если заменить условие MINUS с FILTER NOT EXISTS пункта:

SELECT ?foo WHERE { 
    ?foo a :Foo ; 
     :has :A, :B . 
    FILTER NOT EXISTS { 
     ?foo :has ?other . 
     FILTER (?other NOT IN (:A, :B)) 
    } 
} 

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

+1

Не должно ли это быть «НЕ В?»? И если мы сделаем запрос короче, мы можем сокращать ': has: A; : имеет: B' как ': имеет: A,: B', тоже. :) –

+0

Это решение неверно, потому что минус-блок будет соответствовать всем троек, где '? Foo: has? Other', а затем удалить те, которые не соответствуют выражению фильтра, а затем, наконец, вычесть их из результатов внешнего блок. Это заставляет ': thing3' быть возвращенным из этого запроса –

+1

@BlakeRegalia Да, это должно быть' NOT IN' вместо 'IN', мое плохое. Исправлено сейчас, см. Отредактированный ответ. –

Смежные вопросы