неожиданное поведение с ФИЛЬТРОМ на xsd:date

Как я могу отфильтровать количество результатов (количество забастовок) до определенного года (1970)? Мое решение дает неожиданные результаты. В запросе я записал альтернативы, которые пробовал, и их результаты.

Решения, упомянутые другими ([1], [2]) не решил проблему.

Конечная точка: https://api.druid.datalegend.net/datasets/rlzijdeman/ClariahTech2017/containers/clariahTech2017/sparql

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX gg: <http://www.gemeentegeschiedenis.nl/gg-schema#>
PREFIX strikes: <https://iisg.amsterdam/vocab/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT ?muni ?sdate (COUNT(?muni) as ?muniCount)  
WHERE {
  ?strike strikes:place ?splace .
  ?strike strikes:date ?sdate .
  ?muni rdf:type gg:Municipality .
  ?muni rdfs:label ?ggplace . 
  FILTER regex(?splace, ?ggplace)

  ### TASK: Filter results above to strikes in 1970 only

  # solution 1: extract year and FILTER on 1970
  # FILTER ( year(?sdate) = 1970 )
  ### Virtuoso 22003 Error SR586: Incomplete RDF box as argument 0 for year().

  # solution 2: filter on ?sdate
  # FILTER ( ?sdate >= '1970-01-01'^^xsd:date && ?sdate <= '1970-12-31'^^xsd:date )
  ### Virtuoso 2201B Error SR098: regexp error at '? [Arnhem ( Gelderland )]' column 0 (nothing to repeat)
  ####### Why? This was no problem under solution 1 ?!
  ####### Also: note that each of these works seperately, but not together(!):
  # FILTER ( ?sdate >= '1970-01-01'^^xsd:date )
  # FILTER ( ?sdate <= '1970-12-31'^^xsd:date )

} 
LIMIT 10

person Richard    schedule 07.10.2017    source источник


Ответы (1)


Относительно «Решения 1»:

Функция year принимает на вход литерал типа xsd:dateTime — ваши данные содержат только литералы xsd:date и xsd:gYearMonth. Вот почему актерский состав, вероятно, терпит неудачу.

Относительно «Решения 2»:

Возможно ошибка в Virtuoso. Но вообще я не уверен, зачем вам здесь REGEX. Если вы просто хотите избавиться от языковых тегов для сравнения, используйте функцию str. Это также намного быстрее:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX gg: <http://www.gemeentegeschiedenis.nl/gg-schema#>
PREFIX strikes: <https://iisg.amsterdam/vocab/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT * {
  ?strike strikes:place ?splace .
  ?strike strikes:date ?sdate .
  ?muni rdf:type gg:Municipality .
  ?muni rdfs:label ?ggplace . 
  FILTER (?sdate >= '1970-01-01'^^xsd:date && ?sdate < '1971-01-01'^^xsd:date)
  FILTER(str(?splace) = str(?ggplace)) 
} 
LIMIT 10

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

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX gg: <http://www.gemeentegeschiedenis.nl/gg-schema#>
PREFIX strikes: <https://iisg.amsterdam/vocab/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT ?muni (COUNT(?strike) as ?strikes) {
  ?strike strikes:place ?splace .
  ?strike strikes:date ?sdate .
  ?muni rdf:type gg:Municipality .
  ?muni rdfs:label ?ggplace . 
  FILTER (?sdate >= '1970-01-01'^^xsd:date && ?sdate < '1971-01-01'^^xsd:date)
  FILTER(str(?splace) = str(?ggplace)) 
} 
GROUP BY ?muni
LIMIT 10

Кроме того, получение ?sdate не имеет смысла, если есть несколько предупреждений, верно? Если вы не хотите получать даты всех забастовок следующим образом:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX gg: <http://www.gemeentegeschiedenis.nl/gg-schema#>
PREFIX strikes: <https://iisg.amsterdam/vocab/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT ?muni (COUNT(?strike) as ?strikes) (GROUP_CONCAT(?sdate; separator = ";") as ?s_dates) {
  ?strike strikes:place ?splace .
  ?strike strikes:date ?sdate .
  ?muni rdf:type gg:Municipality .
  ?muni rdfs:label ?ggplace . 
  FILTER (?sdate >= '1970-01-01'^^xsd:date && ?sdate < '1971-01-01'^^xsd:date)
  FILTER(str(?splace) = str(?ggplace)) 
} 
GROUP BY ?muni
LIMIT 10

Незначительный комментарий

Я также пытался сначала выполнить приведение к xsd:dateTime, а затем выбрать year:

FILTER (year(xsd:dateTime(?sdate)) = 1970)

Как ни странно, это не удалось из-за 29.2. :Д :

Virtuoso 22007 Error DT006: Cannot convert 1911-02-29 to datetime : Too many days (29, the month has only 28)

Не уверен, что значение 28 для февраля жестко закодировано в Virtuoso или оно связано с високосными годами - по крайней мере, это имело бы смысл, поскольку 1911 год не был високосным (1911 не делится на 4, поэтому это обычный год )

person UninformedUser    schedule 07.10.2017
comment
Я знаю, я не должен этого делать: но большое спасибо: ваш ответ полный, он помогает мне понять гораздо больше, чем просто эту проблему. - person Richard; 07.10.2017
comment
Возможно, ошибка в Virtuoso. — я думаю, причина в том, что скобки не экранируются, когда REGEX(?splace, ?ggplace) оценивается как REGEX("Arnhem (Gelderland)", "Arnhem (Gelderland)") или что-то в этом роде. Кроме того, кажется, что @Richard использует REGEX, потому что значения strikes:place иногда не равны меткам муниципалитетов. Вероятно, он мог бы использовать STRSTARTS, но, конечно, это должно быть проблемой мейнтейнера конечной точки, чтобы сделать значения strikes:place вещей вместо строк, не заставляя пользователей выполнять эти нечеткие соединения... - person Stanislav Kralin; 07.10.2017
comment
Вопрос в том, почему запрос не завершается ошибкой без фильтра даты. Даже удаление LIMIT и тайм-аут, равный 0, не приводит к этому исключению. - person UninformedUser; 07.10.2017
comment
Что касается соответствия места, возможно, вы правы. Я просто пытался найти обходной путь. Но вообще я не думаю, что есть смысл использовать здесь что-то кроме точного совпадения - да и то не гарантия корректных результатов. Взгляните на следующий запрос: - person UninformedUser; 07.10.2017
comment
Это показывает, что сопоставление подстрок приведет к неправильным результатам. - person UninformedUser; 07.10.2017
comment
@AKSW IMO, довольно глупо, что ты должен делать year(xsd:dateTime(?gYearMonth)). xsd:gYearMonth отображается в то же пространство значений, что и xsd:dateTime (вместе с несколькими другими типами данных XML-схемы), поэтому для разработчиков SPARQL должно быть тривиально разрешить year(?gYearMonth) напрямую. Я предполагаю, что для этого была какая-то причина стандартизации, может быть, функции XPath не поддерживают перегрузку или какая-то другая историческая причина? - person Wouter Beek; 08.10.2017