Schema.org の語彙で RDFS 推論してみる(2):機械可読な語彙定義ファイル

本記事では Schema.org が提供する RDFS ベースの語彙定義を概観します。

【目次】

[1]はじめに

本記事は、記事『Schema.org の語彙で RDFS 推論してみる(1):準備』の続き(第2回)です。

前回の記事で、Schema.org の語彙を使って記述されている Web コンテンツに埋め込まれた JSON-LD を、RDF を扱える Python ライブラリ RDFLib に読み込んで、RDFの可視化や情報抽出の例を見ました。

ところで、Schema.org は RDFS ベースの語彙定義ファイルを提供しており、これを利用すると、さらに進んだ情報利用が可能になります。

そこで本記事では、Schema.org が提供する語彙定義を概観しておきます。

[2]Schema.org の RDFS 語彙定義を概観してみる

Schema.org では、多くの語彙を定義しています。ここでいう語彙とは主に、概念(タイプ、クラス)とそれらの関係です。
  • (注意)本記事で用いている語彙や概念、タイプ、クラス、関係、プロパティなどの用語は、RDFやOWLの定義に従って厳密に使い分けているわけではありません。

まずはブラウザを利用して、Schema.org がどのような語彙を定義しているのか概観してみます。

これによると、現在 797タイプ、1453 プロパティが定義されている云々とありますので、非常に多くの語彙が定義されていることが分かります。

これらを全て見ていくのは大変ですが、これらは無秩序に定義されているわけではなく、体系立てて作られていますので、国語辞典を最初のページから読んでいくのとは異なる見方ができます。

例えば、Schema.org のような語彙定義には、タイプ(概念、クラス)の階層構造が定義されています。

タイプ(概念、クラス)とは、例えば「乗り物」とか「自動車」といった概念を表す語彙で、多くの場合「名詞」にあたります。

このような概念間に「上位概念」と「下位概念」といった関係を定義して概念階層が構成されています。

例えば、「乗り物」が「自動車」の上位概念(「自動車」は「乗り物」の下位概念)といった具合です。

オブジェクト指向をご存知の方であれば、クラスの継承関係と似たような考え方です。

以下では、これらを Schema.org のページで少し見ておきます。

上記ページを見ると、以下のような Thing を頂点とする階層が表示されると思います。

Schema.org Thing の下位クラス


「Thing」とは何か?を知りたい場合は、「Thing」をクリックするとその説明が表示されます。ここには「The most generic type of item.」と書かれています。

何のことか分かり難いと思いますが、Schema.orgが定義するタイプ(概念、クラス)の最も上位にある概念です。そして Schema.org が定義するクラスは全て Thing でもあります。

もしオブジェクト指向のプログラミング言語を何かご存知でしたら、ルートクラス(Object)にあたるものだと考えれば分かりやすいと思います。
  • (参考)上記のThingは、Schema.org が定義している schema:Thing であり、owl:Thing ではありません。

Thing の下に、Action、CreativeWork、Event、Person 等々、馴染みのある概念が並んでいますが、Schema.org が定義するタイプは、Thing の下位概念として整理されています。

以下では本記事の流れから、例として、Schema.org で Article と BlogPosting がどのように関係付けられているかを見てみます。

「CreativeWork」の横にある「+」あるいは「▶」をクリックすると、その下位概念が展開されます。そして「Article」以下も同様に展開していくと以下のように表示されます。

Schema.org Article と BlogPosting の関係


CreativeWork の下に Article があり、その下に SocialMediaPosting があり、さらにその下に BlogPosting があります。

つまり、Article の下位概念として BlogPosting が定義されています。(Article は BlogPosting の上位概念。)

よって BlogPostingであれば Article でもある、といえる関係が定義されてます。

この関係を利用すれば、前の記事の検索例のように Article と BlogPosting を個別に指定しなくても、Article を指定するだけで記事を抽出できることになります。

但し Articleを指定すると、BlogPosting だけでなく NewsArticle や Report などの Article の下位概念にあたるものは全て該当することになります。
  • (参考)
    • これだけ見ると単純な木構造の階層関係のように見えますが、RDFSでは複数の上位概念を持てますので、複雑な上下関係を表現可能です。
    • こういった階層関係は、タイプ(クラス)だけでなく、プロパティにもあります。これはオブジェクト指向言語とは違った面白いところです。

それ以外にも Schema.org には興味深いことが沢山ありますが、本記事ではここまでとして先に進みます。

[3]機械可読な語彙定義ファイルのダウンロード

先に見た Schema.org サイトの語彙定義は、人間には見やすいものですが、プログラムで扱いやすいものとは言えません。

Schema.org では、サイトで説明されている語彙定義を RDFS に基づく機械可読なファイルでも提供しています。


さて、本記事執筆時点では、以下のように File と Format を指定してダウンロードできるようになっています。

Schema.org 語彙定義ファイルのダウンロード

ここで、File と Format は以下の選択が可能です。
  • File:
    • schemaorg-current-https
    • schemaorg-all-https
    • schemaorg-current-http
    • schemaorg-all-http
  • Format:
    • JSON-LD
    • Turtle
    • Triples
    • Quads
    • RDF/XML
    • CSV
      • CSVの場合のみ、Types と Properties の選択があります。

Format は RDF のシリアライズ形式の選択ですので、定義内容は同じです。よって、利用するツールのサポート状況に応じて選択すればよいことになります。(CSVは少し趣が異なりますが。)

一方、File の選択については Schema.org の事情?を知らないと分かり難いと思います。

上記を見ると File には、「schemaorg」に続いて、「current」と「all」、そして「https」と「 http」 の組み合わせで4種類の選択肢があります。

「current」と「all」の違いは、含まれている語彙の違いです。

どちらも現在有効な全ての定義を含んでいますが、「all」には現在有効なものだけではなく、現在使われていない(過去に定義されていた)語彙も含んでいます。

よって、通常は「current」を利用することになります。

一方、https と http の違いは何でしょうか?

これは、通信プロトコルとしての https と http の違いではなく、Schema.org の語彙の識別子(IRI)の違いになります。

これについて以降で少し詳しく見ていきます。

[4]「http」と「https」の混在

(1)JSON-LD コンテキストの場所を表すURL

記事『Web ページ内の JSON-LD を Python + PyLD で覗いてみる(Schema.org)』で、Wikipedia と Blogger の Web サイトに埋め込まれた JSON-LD の例を見てみました。

ここで、@context は以下のように設定されてました。
  • Wikipedia の例
    • "@context": "https://schema.org"
  • Blogger の例
    • "@context": "http://schema.org"

@context に指定する URL は、JSON-LDのコンテキストをダウンロードする場所を示すだけですので、Schema.org の語彙とは何ら関係はありません。

実際に、http でアクセスしても https にリダイレクトされますので、同じコンテキストの実体を参照することになります。

これは単に常時SSL化の流れにそっているだけ、だと思いますし、コンテンツ制作者側にとっても特に問題ないと思います。

問題があるとすれば、JSON-LD を提供する側ではなく、利用する側で @context に指定される URL によって処理を切り替える必要がある場合くらいかと思います。(が大した問題でもない気がします。)

ちなみに、Google の構造化データ例をみると、@context の値は「https://schema.org」となっているようです。今後は「https」の流れかと思います。

(2)語彙の IRI

これもコンテンツ制作側には関係ない殆ど問題だと思いますが、JSON-LD を利用する側は少々シビアな問題として、語彙の IRI の違いがあります。


詳細は割愛しますが、RDF では全てのリソースを IRI (Internationalized Resource Identifier)で識別します。つまり、概念や関係の語彙は IRI で特定します。

具体的には「Article」は、正確には「https://schema.org/Article」のように IRI で表現します。

実は、この「https://schema.org/」の部分に「https」ではじまるものと「http」ではじまるものが利用される可能性があります。

具体的には「https://schema.org/Article」と「http://schema.org/Article」が利用される可能性があるということですが、この二つは異なる IRI であるため、このままでは異なる語彙になってしまいます。

コンテンツ制作者側は、例えば JSON-LD の場合は IRI で語彙を指定しませんので問題ありません(意識することもありません)。

一方、JSON-LD を RDF に展開して検索したり、推論を行う場合には問題になることがあります。

Schema.org は「https」と「http」のどちらも許容すべきという立場のため、RDFとして扱う場合は、何らかの方法でこの二つの表現を同一のものとして扱えるようにする必要があります。

このため Schema.org では、機械可読な語彙定義ファイルを https と http の二種類で提供しています。

そして[3]のダウンロードにおける File の選択は以下のようになります。
  • 「https://schema.org」ではじまる語彙を利用する時
    • 「schemaorg-current-https」を選択する。
  • 「http://schema.org」ではじまる語彙を利用する時
    • 「schemaorg-current-http」を選択する。

なお、廃止された語彙も必要な場合は「current」ではなく「all」を選択します。

FAQによると、Schema.org は、今後は「https」をデフォルトとしていく方向性のようです。

実際、ダウンロードファイルのデフォルトは「schemaorg-current-https」です。

では「https」があれば十分か?というと、そうとは限りません。

前の記事の『(2)実行して結果を可視化してみる』では、2つのサイトからJSON-LDを RDFLib に読み込んで Turtle 形式で表示してみました。

この「@prefix」の値を見ると <http://schema.org/> となっています。つまり「http」で展開されています。

この理由は、Schema.org が現在提供している JSON-LD のコンテキストファイルは、「http」で展開するように定義されているからです。
  • (注意)紛らわしいですが、JSON-LDのコンテキストファイルと、RDFSの語彙定義ファイルは別ものです。

よって、JSON-LD を Schema.org のコンテキストに沿って RDF に展開するケースのように、「http」ではじまる語彙定義のデータを扱う場合は、「schemaorg-current-http」をダウンロードして利用するのが便利です。

もしかすると、将来的には Schema.org の JSON-LD コンテキストが「https」に変換するように置き換えられる時がくるかもしません。その時は「https」の語彙定義ファイルを利用するのが便利だと思います。

(3)雑感

ここで少し脱線ですが、極めて個人的な(現在の)印象を書きます。

一般にオントロジーといわれるものは、かなり厳格な印象が強い世界と感じていましたので、Schema.org の https と http のどちらも許容するような考え方や、比較的緩めの語彙の利用方法には不思議な感覚がありました。

一方、Schema.org は以下のページに「The type hierarchy presented on this site is not intended to be a 'global ontology' of the world.」とか「schema.org is not intended as a universal ontology.」と書いています。

Schema.org はクローラ専用の語彙ではありませんが、作ってもらったデータを利用させてもらうというクローラの立場からすると、制作側の負担を極力減らして有意なデータを提供してもらい、利用するクローラ側も相応の負担するという考え方とも言えます。(もっとも検索精度やリッチスニペットなど制作側のメリットも大きいという、うまいバランスがあるように思えます。)

このような考え方は、Schema.org が定義する語彙の目的を考えると、とても現実的で、Schema.org が成功した要因の一つだと思います。

このあたりが、Schema.org のサイトにオントロジーという言葉が強調されていない理由のようにも思えるし、Schema.org らしいと思います。

ところで、語彙の識別子としての役割だけなら http を https にわざわざ変えなくても良いのでは?と思うところですが、Schema.org 語彙の IRI は、URL として利用できて、ブラウザでも説明を参照できます。

常時SSL化の流れからすれば、やはり「https」へ移行していくのがよいのかもしれません。

そして思ったのは、「CoolなURI」って難しいな、ということでした。

[5]RDFS定義ファイルをRDFLibに読み込んでみる

前書きが長くなりましたが、Schema.org が提供している機械可読な語彙定義ファイルを RDFLib に読み込む方法を見ておきます。

Graph への読み込みは、 parse メソッドに語彙定義ファイルのURLを指定するだけです。(書くほどではないですね(笑))

ここでは次の記事との関係もありますので、Graph へ読み込む簡単な関数を定義しておきます。

def load_schema_org_rdfs(g:Graph, scheme, format="ttl"):
    # 指定の Graph に Schema.org の語彙定義ファイルをロードする。
    # scheme には "http"または"https"を指定する。format には拡張子を指定する。
    rdfs_url = f"https://schema.org/version/latest/schemaorg-current-{scheme}.{format}"
    g.parse(rdfs_url)
    return g

この関数を使って、Turtle形式(拡張子 ttl)の「https://schema.org」ではじまる語彙定義を 新しいGraph に読み込んでみます。

g_ttl = load_schema_org_rdfs(Graph(), "https")

同様に、format 引数に「rdf」(RDF/XML)、「nt」(Triples)、「jsonld」(JSON-LD)を指定しても同じ内容が読み込まれます。(これらは情報内容に違いはなく、表現形式の違いだけです。)

これだけだと面白くないので、語彙定義ファイルがどのくらいの情報量なのか少し見てみます。

RDFLib では、Graph 内にあるトリプル数を len 関数で簡単に知ることができます。

といっても本記事では、RDFの説明を割愛しているのでトリプルの意味も書けないのですが、ここでは基本となる知識の数という程度で考えてください。前の記事には Turtle 形式を可視化した図を載せましたが、この図に書かれている矢印の数ともいえます。

前の記事で2つのサイトのJSON-LDを読み込んだグラフ(g)と、上記 Schema.org の語彙定義ファイルを読み込んだグラフ(g_ttl)を比較してみます。

print( f"len(g)={ len(g) }")
print( f"len(g_ttl)={ len(g_ttl) }")

# 出力結果
# len(g)=40
# len(g_ttl)=16204

元の JSON-LD から得た知識は 40 程度ですが、これに背景知識となる 16204 の知識を追加(マージ)できますので、より多くの情報が得られそうです。

(但し、Schema.org の語彙定義が増えると、数はさらに増えることになります。)

次の記事では、これらの知識をマージして RDFS 推論を行いますが、推論によりさらに知識の数を増やすことができます。

[6]参考:JSON-LDをhttps語彙でRDFLibに読み込む例

JSON-LD を RDFLib に読み込む場合は「http」で始まる語彙定義ファイルを使えばよいのですが、せっかく JSON-LD に関する記事を書いているので、「https」で始まる語彙に変換して RDFLib に取り込む方法も見ておきます。

実は、Schema.org では RDFS をベースにした語彙定義の他に OWL の語彙定義も提供しています。

ここで提供されている「schemaorg.owl」ファイルでは「https」から始まる語彙で定義されています。

この例のように、場合によっては「https」から始まるIRIに変換したいことがあるかもしれません。

さて、変換方法ですが、これはいくつか考えられます。

直感的に思いつくのは、RDF を一度ファイルに出力して、文字列操作で https に変換する方法です。(荒業ながら、案外現実的な方法という気がします。)

しかし、ここでは JSON-LD を扱う記事を書いているので、JSON-LD の特徴であるコンテキストを用いた変換を考えてみます。

Schema.org の JSON-LD コンテキストファイルは以下のURLで得られます。

ブラウザで、上記コンテキストのURLをクリックすれば内容が表示されます。

このコンテキストファイルをみると、以下のプリフィクス定義があります。

"schema": "http://schema.org/",

この「http」を「https」に変えると、JSON-LDをRDFに変換した時に「https」からはじまる語彙定義になるはずです。

以下は、「http」を「https」にすり替えたコンテキストを準備するコード例です。

def get_schema_org_https_context():
    # Schema.org の@contextにあるschemaのURIをhttpからhttpsに変換する
    res = requests.get("https://schema.org/docs/jsonldcontext.jsonld")
    if res.status_code == 200:
        js = json.loads(res.text)
        if js["@context"]["schema"] == "http://schema.org/":
            js["@context"]["schema"] = "https://schema.org/"
            return js
    else:
        return None

次に、前の記事で書いた SampleGraph クラスの import_jsonld 関数をオーバーライドします。

ここで Schema.org の JSON-LD を読み込む際には、オリジナルのコンテキストを利用せず、先に準備した「https」にすり替えたコンテキストを利用してRDFLibに読み込みます。

class SchemaOrgHttpsGraph(SampleGraph):
    def __init__(self) -> None:
        super().__init__()
        #
        self.https_context = None

    def import_jsonld(self, jsonld_data):
        ctx_url = jsonld_data["@context"]
        if ctx_url == "http://schema.org" or ctx_url == "https://schema.org":
            # Schema.org のContextの場合はhttpsのContextでロードする
            del jsonld_data["@context"]
            if self.https_context is None:
                self.https_context = get_schema_org_https_context()
            self.graph.parse(data=jsonld_data, format='json-ld', context=self.https_context)
        else:
            self.graph.parse(data=jsonld_data, format='json-ld')
        return self

このクラスを用いて、SimpleGraph の例と同じ内容を実行してみます。

g_https = SchemaOrgHttpsGraph() \
    .import_jsonld_from_html("https://en.wikipedia.org/wiki/JSON-LD") \
    .import_jsonld_from_html("https://technodaifuku.blogspot.com/2022/04/protege.html") \
    .graph

print(g_https .serialize(format='turtle'))

結果は以下のようになりました。
@prefix の schema のIRIが「https」から始まっていることがわかります。

@prefix schema: <https://schema.org/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<https://technodaifuku.blogspot.com/2022/04/protege.html> a schema:WebPage .

[] a schema:BlogPosting ;
    schema:author [ a schema:Person ;
            schema:name "テクノ大福" ] ;
    schema:dateModified "2022-07-31T18:20:30+09:00"^^schema:Date ;
    schema:datePublished "2022-04-27T20:55:00+09:00"^^schema:Date ;
    schema:description "本記事では&#12289;デスクトップ版の Protégé のセットアップと&#12289;オントロジーの可視化&#12289;推論などの使い方を簡単に見ていきます&#12290;   &#12304;目次&#12305;  &#65339;1&#65341;はじめに &#65339;2&#65341;Protégé Desktop のセットアップ &#65288;1&#65289;Ubuntu でのインストール手順 &#65288;2&#65289;起動確認 &#65288;3&#65289;起動..." ;
    schema:headline "オントロジーエディタ Protégé を使ってみる" ;
    schema:image [ a schema:ImageObject ;
            schema:height 630 ;
            schema:url <https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM1XoAmXI7mKT_9hFYwfU1uzlMJYtzZ4Irw_ZJ6kf0wpTj1UQAeYx3nvpQ6LFXJJtMo6XZLxHDxnvoz-y2Yn_fyv8frt4klSRmnTGE0Iz39nxbDqn78NRS4iYyqLx5418EaPxfYyoNjs27hqnY819tjhT75udNmd27GhgZOqwk-6oWnxPX8bQyNwiR/w1200-h630-p-k-no-nu/protegeinit.png> ;
            schema:width 1200 ] ;
    schema:mainEntityOfPage <https://technodaifuku.blogspot.com/2022/04/protege.html> ;
    schema:publisher [ a schema:Organization ;
            schema:logo [ a schema:ImageObject ;
                    schema:height 60 ;
                    schema:url <https://blogger.googleusercontent.com/img/b/U2hvZWJveA/AVvXsEgfMvYAhAbdHksiBA24JKmb2Tav6K0GviwztID3Cq4VpV96HaJfy0viIu8z1SSw_G9n5FQHZWSRao61M3e58ImahqBtr7LiOUS6m_w59IvDYwjmMcbq3fKW4JSbacqkbxTo8B90dWp0Cese92xfLMPe_tg11g/h60/> ;
                    schema:width 206 ] ;
            schema:name "Blogger" ] .

[] a schema:Article ;
    schema:author [ a schema:Organization ;
            schema:name "Contributors to Wikimedia projects" ] ;
    schema:dateModified "2022-06-15T04:04:15Z"^^schema:Date ;
    schema:datePublished "2011-12-30T17:43:17Z"^^schema:Date ;
    schema:headline "a method of encoding Linked Data using JSON" ;
    schema:mainEntity "http://www.wikidata.org/entity/Q6108942" ;
    schema:name "JSON-LD" ;
    schema:publisher [ a schema:Organization ;
            schema:logo [ a schema:ImageObject ;
                    schema:url <https://www.wikimedia.org/static/images/wmf-hor-googpub.png> ] ;
            schema:name "Wikimedia Foundation, Inc." ] ;
    schema:sameAs <http://www.wikidata.org/entity/Q6108942> ;
    schema:url <https://en.wikipedia.org/wiki/JSON-LD> .


なお、前の記事に書いた可視化も同じ結果になりますし、SPARQL の例も PREFIX を「https」に変えるだけで同様に動作します。

コメント

このブログの人気の投稿

Google Document AIで画像から表形式データを抽出する(Vision API OCRとの違い)

VirtualBoxのスナップショット機能

Ubuntu/Colab環境でPDFファイルのページを画像化する(pdf2image、pdftoppm、pdftocairo)