SPARQL-запрос для возврата сущностей, удовлетворяющих некоторым условиям - PullRequest
0 голосов
/ 09 мая 2018

У меня есть требование написать SPARQL-запрос для возврата тех сущностей, которые удовлетворяют фиксированному количеству условий (не всегда всех). Идея состоит в том, что мне нужно получить все те объекты, которые удовлетворяют, скажем, 2 из 4 предоставленных условий. Я пишу следующий запрос

SELECT ?ent WHERE {
    BIND(0 as ?cnt).
    OPTIONAL {
       ?ent ns:age ?age.
       FILTER(?age > 20 && ?age <= 40).
       BIND(?cnt + 1, ?cnt).
    }.
    OPTIONAL {
        ?ent ns:livesIn nst:Mauritius.
        BIND(?cnt + 1, ?cnt).
    }.
    OPTIONAL {
        ?ent ns:maritalStatus nst:Married.
        BIND(?cnt + 1, ?cnt).
    }.
    OPTIONAL {
        ?ent ns:fatherIs/ns:age ?fatherAge.
        FILTER(?fatherAge > 55 && ?fatherAge <= 80).
        BIND(?cnt + 1, ?cnt).
    }
} HAVING(?cnt > 2)

Правильно ли я решаю проблему? Я что-то упускаю? Есть ли лучший способ решить мою проблему?

РЕДАКТИРОВАТЬ 1: вышеупомянутый запрос дал мне ошибку. Сейчас я пытаюсь с этим

SELECT ?ent ?cnt WHERE {
    BIND(0 as ?cnt1).
    BIND(0 as ?cnt2).
    BIND(0 as ?cnt3).
    BIND(0 as ?cnt4).
    OPTIONAL {
       ?ent ns:age ?age.
       FILTER(?age > 20 && ?age <= 40).
       BIND(1 as ?cnt1).
    }.
    OPTIONAL {
        ?ent ns:livesIn nst:Mauritius.
        BIND(1 as ?cnt2).
    }.
    OPTIONAL {
        ?ent ns:maritalStatus nst:Married.
        BIND(1 as ?cnt3).
    }.
    OPTIONAL {
        ?ent ns:fatherIs/ns:age ?fatherAge.
        FILTER(?fatherAge > 55 && ?fatherAge <= 80).
        BIND(1 as ?cnt4).
    }
    BIND((?cnt1 + ?cnt2 + ?cnt3 + ?cnt4) as ?cnt)
} ORDER BY DESC(?cnt)

Этот запрос возвращает значение 0 ниже? Cnt для всех записей

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Вероятно, следует подробнее остановиться на использовании UNION, который я предложил в приведенном выше комментарии. например извлечь все, что соответствует первому условию И, чтобы не было одного из остальных ИЛИ решений, где выполняется второе условие И, по крайней мере, один из двух других ИЛИ солутонов, где последние два присутствуют вместе, что-то вроде этого:

SELECT ?ent WHERE {
{
    ?ent ns:age ?age.
    FILTER(?age > 20 && ?age <= 40).
    {
        ?ent ns:livesIn nst:Mauritius.
    } union {
        ?ent ns:maritalStatus nst:Married.
    } union {
            ?ent ns:fatherIs/ns:age ?fatherAge.
            FILTER(?fatherAge > 55 && ?fatherAge <= 80).
    }
} union {
    ?ent ns:livesIn nst:Mauritius.
    {
        ?ent ns:maritalStatus nst:Married.
    } union {
            ?ent ns:fatherIs/ns:age ?fatherAge.
            FILTER(?fatherAge > 55 && ?fatherAge <= 80).
    }    
} union {
    ?ent ns:maritalStatus nst:Married.
    ?ent ns:fatherIs/ns:age ?fatherAge.
    FILTER(?fatherAge > 55 && ?fatherAge <= 80).
  }
}

Другим возможным подходом является использование GROUP BY поверх перенапряжения, но это будет работать только в том случае, если в каждом опциональном блоке одно решение точно равно одному, тогда запрос представляет собой простой UNION между всеми условиями, а затем использует HAVING для отфильтруйте то, что не нужно:

SELECT ?ent WHERE {
{
    ?ent ns:age ?age.
    FILTER(?age > 20 && ?age <= 40).
} union {
    ?ent ns:livesIn nst:Mauritius.
} union {
    ?ent ns:maritalStatus nst:Married.
} union {
        ?ent ns:fatherIs/ns:age ?fatherAge.
        FILTER(?fatherAge > 55 && ?fatherAge <= 80).
}
} GROUP BY ?ent
HAVING (count(*) > 1)
0 голосов
/ 09 мая 2018

Я бы предложил следующий наивный подход.

SELECT ?ent ?cnt WHERE {
    ?ent a foaf:Person .
    OPTIONAL {
        ?ent ns:age ?age.
        FILTER(?age > 20 && ?age <= 40).
    }
    OPTIONAL {
        ?ent ns:livesIn ?livesIn.
        FILTER (?livesIn = nst:Mauritius)
    }
    OPTIONAL {
        ?ent ns:maritalStatus ?maritalStatus.
        FILTER (?maritalStatus = nst:Married).
    }
    OPTIONAL {
        ?ent ns:fatherIs/ns:age ?fatherAge.
        FILTER(?fatherAge > 55 && ?fatherAge <= 80).
    }
    BIND(xsd:integer(bound(?age)) +
         xsd:integer(bound(?livesIn)) +
         xsd:integer(bound(?maritalStatus)) +
         xsd:integer(bound(?fatherAge))
         AS ?cnt)
    FILTER (?cnt > 2)
} ORDER BY DESC(?cnt)

В вашем последнем запросе есть две проблемы:

...