1
1

Amazon NeptuneでグラフDBを体験してみる② Gremlinを用いた超単純なデータの操作

Last updated at Posted at 2024-09-05

こんにちは、Kaneyasuです。

本記事はAmazon NeptuneでグラフDBを体験してみるシリーズの2回目です。

本シリーズ記事の目標

  • グラフDBの意味と用途を理解する
  • プログラムからAmazon Neptuneにアクセスする方法を習得する
  • Amazon Neptuneのセキュリティの確保方法を習得する
  • Amazon Neptuneのスケーリングを習得する
  • Amazon Neptuneのバックアップ、リカバリ方法を習得する

本シリーズ記事執筆における前提条件

  • グラフDBはAmazon Neptuneを使用
  • モデルはプロパティグラフ、クエリ言語はGremlinを使用
  • クエリ言語の実行はPythonのgremlinpythonで行う
  • PythonはJupyter Notebookで実行
  • Jupyter NotebookはAmazon SageMakerのNotebookインスタンスで実行

第2回目の目標

  • Amazon Neptune上のプロパティグラフに対してGremlinでデータ操作する基本構文を押さえる

プロパティグラフの用語

本シリーズではグラフDBのモデルにプラパティグラフを使用しています。
プロパティグラフの基本的な用語は以下の通りです。
本記事ではクエリにGremlinを使うのでGremlinの言葉遣いを優先して用語を書いています。
例えば、Vertex=頂点はノードとも言われますが、GremlinではVertexなのでそちらを優先しています。

用語 説明
Vertex (V) 頂点。エンティティを表すノード。例: 人、場所、物など。
Edge (E) エッジ。2つの頂点間の関係を表す。例: 「友人」「購入」「関連」など。
Property プロパティ。頂点やエッジに付与されるキーと値のペア。例: 名前、年齢、色など。
Label 頂点やエッジの種類を識別するためのタグ。例: 'person', 'knows', 'product' など。

Gremlinとは

Gremlinは、Apache TinkerPopプロジェクトの一部として提供されているグラフデータベース用のクエリ言語です。
グラフデータベース上で頂点(Vertex)やエッジ(Edge)を操作するために使用され、プロパティグラフモデルに基づいて、グラフデータの照会、挿入、更新、削除などの操作を行うことができます。

なお、プロパティグラフを操作するクエリ言語はGremlinの他にopenCypherがあります。
私の周りだとGremlinを使っているという声が大きく、AWS公式ページの記載もGremlinの方が先で、openCypherはその次なので、2024年9月現在だとプロパティグラフのクエリ言語はGremlinがメジャーのようです。

Note
You can access property graph data in Neptune using both Gremlin and >openCypher, but not using SPARQL. Similarly, you can only access RDF data >using SPARQL, not Gremlin or openCypher.

Gremlinを用いた超単純なグラフデータの操作

グラフデータの操作はこちらのページを参考します。

Gremlinを、gremlinpythonライブラリを用いてPythonから実行します。

頂点の登録

g.addV('person').property('name', 'justin').iterate()

addV()VはVertex(頂点)の略です。
addV()の引数はラベルで、頂点の種類を示します。
property()で頂点に対する属性を付与します。

このGremlinのグラフデータを操作する一連の文をトラバーサルと言います。
Gremlinのトラバーサルにおいて、データベースの状態に影響を与える操作を副作用があると表現します。
iterate()は、副作用を実行するためのメソッドです。
iterate()がない場合、トラバーサルは評価されず、データベース(Neptuneなど)に反映されません。

Gremlinにはiterate()のように、トラバーサルを評価して実行するメソッドが複数あります。

以下のメソッドは Neptune DB インスタンスにクエリを送信します。
toList()
toSet()
next()
nextTraverser()
iterate()

これらの違いは改めて調べます。

登録した結果を確認

登録した結果を確認します。
初回なのですべての頂点を取得して確認してみます。

all_nodes = g.V().valueMap(True).toList()
print("All Nodes:", all_nodes)

toList()でクエリの実行結果をリスト化しています。
valueMap()は頂点やエッジのプロパティとその値を辞書形式で取得するための関数です。
valueMap(False)または、valueMap()を指定しないと頂点やエッジのオブジェクト情報やIDが表示されますが、個別のプロパティ値(例えばnameやageなど)は出力されません。

頂点の登録と確認のPythonコード

頂点の登録と確認のPythonコードを一通り書くと以下のようになります。
次の2ステップをJupyter Notebookで実行します。

!pip install gremlinpython

Jupyter Notebookを使わずに普通にコマンドとして実行する場合は、!pip!不要です。

from gremlin_python import statics
from gremlin_python.structure.graph import Graph
from gremlin_python.process.graph_traversal import __
from gremlin_python.process.strategies import *
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
from gremlin_python.driver.aiohttp.transport import AiohttpTransport
from gremlin_python.process.traversal import *

import os

port = 8182
server = '{Neptuneのエンドポイント}'
    
endpoint = f'wss://{server}:{port}/gremlin'
print(endpoint)

graph=Graph()

connection = None

try:
    connection = DriverRemoteConnection(endpoint, 'g',
                                        transport_factory=lambda: AiohttpTransport(call_from_event_loop=True))

    g = graph.traversal().withRemote(connection)

    g.addV('person').property('name', 'satoshi').iterate()

    # すべての頂点を確認する
    all_nodes = g.V().valueMap(True).toList()
    print("All Nodes:", all_nodes)

finally:
    if connection is not None:
        connection.close()

実行すると以下のように出力されます。

実行結果
All Nodes: [{'name': ['satoshi'], <T.label: 4>: 'person', <T.id: 1>: 'b6c8dfb8-cb96-8798-cefd-6f98cb7343cd'}]

IDを指定した頂点の登録と参照

g.addV('person').property(T.id, '10').property('name', 'satoshi').iterate()

プロパティグラフにおいて、idは特別な意味を持つプロパティであり、各頂点やエッジを一意に識別するための属性です。idを使用することで、頂点やエッジを効率的に検索・更新・削除することができます。

上記のコードでは、property(T.id, '10')によってidを指定しています。通常、property()は(属性名, 属性値)の形式で指定しますが、idのような特別なプロパティを指定する場合は、T.idのようにGremlinの予約語を使用します。

T.idはGremlin-Pythonでidを指定するための特別な構文です。
他のプログラミング言語やGremlinライブラリの場合は書き方が変わります。

idを指定して頂点を取得するには以下のように書きます。

node = g.V('10').valueMap(True).toList()
print("Node:", node)

頂点の更新

g.V()で頂点を取得できます。
引数にIDを指定すればピンポイントで頂点を得られます。
これに対してproperty()で新たなプロパティを指定すればプロパティを追加できます。
property()addressを設定します。

g.V('10').property('address', 'japan').iterate()
node = g.V('10').valueMap(True).toList()
print("Node:", node)
実行結果
Node: [{'name': ['satoshi'], <T.label: 4>: 'person', 'address': ['japan'], <T.id: 1>: '10'}]

ここから、property()addressを上書きを試みます。

g.V('10').property('address', 'hiroshima').iterate()
node = g.V('10').valueMap(True).toList()
print("Node:", node)
実行結果
Node: [{'name': ['satoshi'], <T.label: 4>: 'person', 'address': ['hiroshima', 'japan'], <T.id: 1>: '10'}]

プロパティの値が上書きされず、追加されました。
これは、property()のデフォルトの動きがプロパティ値の追加だからです。
プロパティ値の追加ではなく、更新をする場合は以下のように書きます。

from gremlin_python.process.traversal import Cardinality

g.V('10').property(Cardinality.single, 'name', 'satoshi256kbyte').iterate()
node = g.V('10').valueMap(True).toList()
print("Node:", node)
実行結果
Node: [{'name': ['satoshi256kbyte'], <T.label: 4>: 'person', 'address': ['hiroshima', 'japan'], <T.id: 1>: '10'}]

すべての頂点を削除する

以下のように書きます。
今は実験中なので、これが重宝します。

g.V().drop().iterate()

g.V()は引数で何も指定していないので、すべての頂点を選択します。
drop()は選択されたすべての頂点と、それに関連するエッジを削除します。
iterate()によりクエリを実行して変更を確定します。

次回に向けて

今回はここまでです。
単純に登録・参照するだけでも調べることがたくさんあり長くなってしまいました。
第3回目は、もう少し色々なクエリにチャレンジします。
次の目標をGremlinのいろんなクエリを試すとしましたが、クエリを実行できる環境を整えないと検証がしづらいということで方針転換しました。
第3回目はAmazon NeptuneとTom Sawyer Graph Database Browserと接続です。

参考書籍

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1