Агрегирование результатов из запроса SPARQL

Я запрашиваю набор данных твитов:

SELECT * WHERE {
  ?tweet smo:tweeted_at ?date ;
         smo:has_hashtag ?hashtag ;
         smo:tweeted_by ?account ;
         smo:english_tweet true .
  FILTER ( ?date >= "20130722"^^xsd:date && ?date < "20130723"^^xsd:date )
}

Если твит имеет несколько хэштегов, в результирующем наборе есть одна строка для каждого хэштега. Можно ли вместо этого объединить хэштеги в массив?

1 ответ

Решение

Вы можете GROUP BY переменными, которые идентифицируют твит, а затем используют GROUP_CONCAT объединить хэштеги во что-то вроде массива, но все равно это будет строка, которую вам нужно будет проанализировать позже. Например, данные даны как

@prefix smo: <http://example.org/> .
@prefix : <http://example.org/> .

:tweet1 smo:tweeted_at "1" ;
        smo:has_hashtag "tag1", "tag2", "tag3" ;
        smo:tweeted_by "user1" ;
        smo:english_tweet true .

:tweet2 smo:tweeted_at "2" ;
        smo:has_hashtag "tag2", "tag3", "tag4" ;
        smo:tweeted_by "user2" ;
        smo:english_tweet true .

Вы можете использовать запрос как

prefix smo: <http://example.org/>

select ?tweet ?date ?account (group_concat(?hashtag) as ?hashtags) where {
  ?tweet smo:tweeted_at ?date ;
         smo:has_hashtag ?hashtag ;
         smo:tweeted_by ?account ;
         smo:english_tweet true .
}
group by ?tweet ?date ?account

чтобы получить результаты, такие как:

--------------------------------------------------
| tweet      | date | account | hashtags         |
==================================================
| smo:tweet2 | "2"  | "user2" | "tag4 tag3 tag2" |
| smo:tweet1 | "1"  | "user1" | "tag3 tag2 tag1" |
--------------------------------------------------

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

(group_concat(?hashtag;separator="|") as ?hashtags)

вместо этого и получить

--------------------------------------------------
| tweet      | date | account | hashtags         |
==================================================
| smo:tweet2 | "2"  | "user2" | "tag4|tag3|tag2" |
| smo:tweet1 | "1"  | "user1" | "tag3|tag2|tag1" |
--------------------------------------------------

Если вы работаете на языке, который имеет некоторый синтаксис буквального массива, вы можете даже скопировать это:

(concat('[',group_concat(?hashtag;separator=","),']') as ?hashtags)
----------------------------------------------------
| tweet      | date | account | hashtags           |
====================================================
| smo:tweet2 | "2"  | "user2" | "[tag4,tag3,tag2]" |
| smo:tweet1 | "1"  | "user1" | "[tag3,tag2,tag1]" |
----------------------------------------------------

Теперь, это не влияет на данные здесь, но group_concat будет фактически включать дубликаты в конкатенацию, если они присутствуют в данных. Например, из следующего (где я просто предоставляю данные с values для примера)

prefix : <http://example.org/>

select ?tweet (concat('[',group_concat(?hashtag;separator=','),']') as ?hashtags)
where {
  values (?tweet ?hashtag) { 
    (:tweet1 "tag1") (:tweet1 "tag1") (:tweet1 "tag2") (:tweet1 "tag3")
    (:tweet2 "tag2") (:tweet2 "tag3") (:tweet2 "tag4")
  }
}
group by ?tweet

мы получаем результаты, в том числе [tag1,tag1,tag2,tag3] дублирующее значение ?hashtag Включено:

-------------------------------------
| tweet   | hashtags                |
=====================================
| :tweet2 | "[tag2,tag3,tag4]"      |
| :tweet1 | "[tag1,tag1,tag2,tag3]" |
-------------------------------------

Мы можем избежать этого, используя group_concat(distinct ?hashtag;...):

prefix : <http://example.org/>

select ?tweet (concat('[',group_concat(distinct ?hashtag;separator=','),']') as ?hashtags)
where {
  values (?tweet ?hashtag) { 
    (:tweet1 "tag1") (:tweet1 "tag1") (:tweet1 "tag2") (:tweet1 "tag3")
    (:tweet2 "tag2") (:tweet2 "tag3") (:tweet2 "tag4")
  }
}
group by ?tweet
--------------------------------
| tweet   | hashtags           |
================================
| :tweet2 | "[tag2,tag3,tag4]" |
| :tweet1 | "[tag1,tag2,tag3]" |
--------------------------------
Другие вопросы по тегам