Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Azure Cosmos DBを使って日本語をグラフで表現してみる

皆さんこんにちは。最近ちょっとずつ体重が増えて、若干年齢を感じている@Ssk1029Takashiです。

日常生活の中で、文章を読む機会というのは数多くありますが、もう少し簡単に要点を押さえたいということが多いかと思います。
読むというよりは、図に表示されて理解できると、直感的に理解できてわかりやすいです。

ということで、今回は日本語のSVOに注目してみます。
SVOだけを残すことで余分な単語がなく、ぱっと見の理解が早くなります。
また、これをグラフ表現に起こすことで、見やすくならないか試してみます。

やりたいこと

今回やりたいことは、文章からSVO(主語・述語・目的語)を抽出して、グラフ表現に落とし込んでみます。
例えば、「AcroquestはGPTWを受賞した。」という文章からは以下のような図を作っていきます。
f:id:acro-engineer:20210126075023p:plain

これらを複数の文章から作成することで、名詞と名詞の相関図を作ってみたら見やすくならないか試してみます。

グラフ表現には、Azureが提供しているNoSQLデータベースサービスであるAzure Cosmos DBを活用します。
Cosmos DBはグラフでのデータ構造を格納することができ、なおかつセットアップが簡単なので、選びました。

Azure Cosmos DBとは

Azure Cosmos DBはフルマネージドのNoSQLデータベースです。
高い可用性と応答時間の早さが特徴です。
詳細は以下のページを参照してください。
docs.microsoft.com

また、Azure Cosmos DBはグラフDBとしての機能も備えておりGremlinというAPIを使うことで、グラフデータを扱うことができます。
docs.microsoft.com

SVOを文章から抜き出す

今回はGiNZAの係り受け解析を使って、文章から主語・述語・目的語を抜き出します。
GiNZAの係り受け解析では、以下のように、述語を中心に、係り方の種類で判別できます。
f:id:acro-engineer:20210126080554p:plain
例えば、nsubjは主語・述語関係を表すので、上の図では、述語「受賞」に対する主語は「Acroquest」だとわかります。
また、「obj」は述語に対する目的語を表すので、「受賞」の目的語は「GPTW」であることもここからわかります。

このように、係り受け解析結果から、nsubjやobjなどの関係を抽出することで、文章のSVOを抽出することが可能です。

コードにすると以下のようになります。

def get_svo(token):
    """
    SVOを出力
    :param token:
    :return:
    """
    if token.dep_ == 'nsubj' or token.dep_ == 'iobj': # iobjがあるのはGiNZAが主格関係をiobjと誤認識する不具合があるため
        # 主語の場合、依存関係で動詞をたどる
        verb_token = token.head
        if verb_token.dep_ == 'verb' or verb_token.dep_ == 'ROOT':
            # 動詞から依存関係をたどる
            for object_token in verb_token.children:
                # 目的語があったら、SVOがそろう
                if object_token.dep_ == 'obj':
                    return {"verb": verb_token.orth_, "sub": token.orth_, "obj": object_token.orth_}

これによって、SVOの組み合わせを抽出できます。

Azure Cosmos DBにグラフ情報を格納する

主語述語関係を抽出したら、その情報をグラフDBに格納していきましょう。

Azure Cosmos DBにグラフ情報を格納するためには、Gremlinという言語を使ってグラフを記述します。

グラフを構成する要素としては、以下の2点になります。
1. ノード(頂点)
2. エッジ(辺)

Gremlinを使ってノード・エッジを追加するには以下のようなコードが必要になります。
ノード

g.addV('<グラフ名>').property('id', '<頂点名>').property('pk', '<プライマリキー>')

エッジ

g.V('<辺の元の頂点>').addE('<辺のラベル>').to(g.V('辺の先の頂点'))||<

例として、はじめに例文とした「AcroquestはGPTWを受賞した」という文章を例に考えてみましょう。
図に書いた通り、ここでのノードは「Acroquest」と「GPTW」になり、エッジは「受賞」になります。
それぞれDBに追加するには以下のようなコードになります。

# ノード
g.addV('sentence').property('id', 'Acroquest').property('pk', 'pk')
g.addV('sentence').property('id', 'GPTW').property('pk', 'pk')
# エッジ
g.V('Acroquest').addE('受賞').to(g.V('GPTW'))

実際の文章で試してみる

今回試すうえで、一つの文章の中に、主語・述語・目的語が現れるのが望ましいので、物語を対象にしてみます。
なので、例題として、以下で公開している「走れメロス」を題材にしてみます。
www.aozora.gr.jp

入れてみた結果は、Azure PortalのCosmos DBの画面にある、データエクスプローラーから確認できます。
f:id:acro-engineer:20210127013413p:plain

対象のグラフを選ぶグラフが出てきます。
f:id:acro-engineer:20210127013533p:plain
このように、頂点からどのような辺がどの頂点に伸びているかということが確認できます。

例えば、「メロス」に着目してみると、比較的多くの辺が伸びていることがわかります。
f:id:acro-engineer:20210127013655p:plain

とりあえず「セリヌンティウス」が「メロス」を抱きしめたことは解りましたね。
このように、ざっくりとした相関図がグラフDBで表現できました。

まとめ

今回はGiNZAとAzure Cosmos DBのグラフDBを使って、文章のSVOを可視化してみました。
グラフDBにすることで、「メロス」が「見つめる」のは何?というような検索も可能になります。
ただし、日本語というのは主語を省くことが多い言語なので、真面目にやろうと思うと照応解析や文脈解析などが平行して必要になってきます。
また、SVO以外の5W1Hのような関係も抽出してみると面白いかもしれません。
それではまだ。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com