一定数のカテゴリを処理する
次のようなデータが与えられた場合
@prefix : <http://example.org/books/> .
:book1 a :Book, :Cat1 .
:book2 a :Book, :Cat1, :Cat3 .
:book3 a :Book, :Cat1, :Cat2 .
次のようなクエリを使用できます
prefix : <http://example.org/books/>
select ?individual
(if(bound(?cat1),1,0) as ?Cat1)
(if(bound(?cat2),1,0) as ?Cat2)
(if(bound(?cat3),1,0) as ?Cat3)
where {
?individual a :Book .
OPTIONAL { ?individual a :Cat1 . bind( ?individual as ?cat1 ) }
OPTIONAL { ?individual a :Cat2 . bind( ?individual as ?cat2 ) }
OPTIONAL { ?individual a :Cat3 . bind( ?individual as ?cat3 ) }
}
order by ?book
これらのような結果を得るために特定のトリプルが存在するかどうかに基づいて、特定の変数がバインドされている (それらがバインドされている特定の値は実際には重要ではありません)。
$ arq --data data.n3 --query matrix.sparql
-----------------------------------
| individual | Cat1 | Cat2 | Cat3 |
===================================
| :book1 | 1 | 0 | 0 |
| :book2 | 1 | 0 | 1 |
| :book3 | 1 | 1 | 0 |
-----------------------------------
任意の数のカテゴリを処理する
特定の結果が保証されているかどうかはわかりませんが、Jena で動作するように見えるソリューションを次に示します。(更新:このanswer.semanticweb.com の質問と回答に基づくと、この動作はSPARQL 仕様によって保証されていないようです。) もう少しデータがある場合、たとえば、どのものがカテゴリで、どれが本であるかについて、例えば、
@prefix : <http://example.org/books/> .
:book1 a :Book, :Cat1 .
:book2 a :Book, :Cat1, :Cat3 .
:book3 a :Book, :Cat1, :Cat2 .
:Cat1 a :Category .
:Cat2 a :Category .
:Cat3 a :Category .
次に、すべてのカテゴリを順番に選択するサブクエリを実行し、書籍ごとに、その書籍が各カテゴリに含まれているかどうかを示す文字列を計算します。
prefix : <http://example.org/books/>
select ?book (group_concat(?isCat) as ?matrix) where {
{
select ?category where {
?category a :Category
}
order by ?category
}
?book a :Book .
OPTIONAL { bind( 1 as ?isCat ) ?book a ?category . }
OPTIONAL { bind( 0 as ?isCat ) NOT EXISTS { ?book a ?category } }
}
group by ?book
order by ?book
これにより、次の出力が得られます。
$ arq --data data.n3 --query matrix2.query
--------------------
| book | matrix |
====================
| :book1 | "1 0 0" |
| :book2 | "1 0 1" |
| :book3 | "1 1 0" |
--------------------
これは質問の出力にはるかに近く、任意の数のカテゴリを処理します。?category
ただし、各 の値が同じ順序で処理されるかどうかに依存し、それ?book
が保証されるかどうかはわかりません。
このアプローチを使用して、テーブルのヘッダー行を生成することもできます。?category
繰り返しますが、これは各 に対して同じ順序で処理される値に依存します?book
。これは保証されていない可能性がありますが、Jena では機能するようです。カテゴリ ヘッダーを取得するには、?book
がバインドされていない行を作成するだけで、 の値が?isCat
特定のカテゴリを示します。
prefix : <http://example.org/books/>
select ?book (group_concat(?isCat) as ?matrix) where {
{
select ?category where {
?category a :Category
}
order by ?category
}
# This generates the header row where ?isCat is just
# the category, so the group_concat gives headers.
{
bind(?category as ?isCat)
}
UNION
# This is the table as before
{
?book a :Book .
OPTIONAL { bind( 1 as ?isCat ) ?book a ?category . }
OPTIONAL { bind( 0 as ?isCat ) NOT EXISTS { ?book a ?category } }
}
}
group by ?book
order by ?book
次の出力が得られます。
--------------------------------------------------------------------------------------------------------
| book | matrix |
========================================================================================================
| | "http://example.org/books/Cat1 http://example.org/books/Cat2 http://example.org/books/Cat3" |
| :book1 | "1 0 0" |
| :book2 | "1 0 1" |
| :book3 | "1 1 0" |
--------------------------------------------------------------------------------------------------------
いくつかの文字列操作を使用して、カテゴリに使用される URI を短縮したり、配列エントリを広げて正しい位置合わせを取得したりできます。1つの可能性はこれです:
prefix : <http://example.org/books/>
select ?book (group_concat(?isCat) as ?categories) where {
{
select ?category
(strafter(str(?category),"http://example.org/books/") as ?name)
where {
?category a :Category
}
order by ?category
}
{
bind(?name as ?isCat)
}
UNION
{
?book a :Book .
# The string manipulation here takes the name of the category (which should
# be at least two character), trims off the first character (string indexing
# in XPath functions starts at 1), and replaces the rest with " ". The resulting
# spaces are concatenated with "1" or "0" depending on whether the book is a
# member of the category. The resulting string has the same width as the
# category name, and makes for a nice table.
OPTIONAL { bind( concat(replace(substr(?name,2),"."," "),"1") as ?isCat ) ?book a ?category . }
OPTIONAL { bind( concat(replace(substr(?name,2),"."," "),"0") as ?isCat ) NOT EXISTS { ?book a ?category } }
}
}
group by ?book
order by ?book
次の出力が生成されます。
$ arq --data data.n3 --query matrix3.query
-----------------------------
| book | categories |
=============================
| | "Cat1 Cat2 Cat3" |
| :book1 | " 1 0 0" |
| :book2 | " 1 0 1" |
| :book3 | " 1 1 0" |
-----------------------------
これは、質問で持っていたものとほぼ同じです。