こんにちは。
DevOpsが好きなアプリケーションサービス部の兼安です。
本記事は「Amazon Neptuneで始める初めてのグラフDB」というテーマの連載記事の2回目です。
- Amazon Neptuneで始める初めてのグラフDB① NeptuneクラスターとNotebookの作成
- Amazon Neptuneで始める初めてのグラフDB② Gremlinを用いたグラフデータの基本操作
- Amazon Neptuneで始める初めてのグラフDB③ Amazon NeptuneとTom Sawyer Graph Database Browserとの接続
- Amazon Neptuneで始める初めてのグラフDB④ G.V()を用いてローカル端末からAmazon Neptuneに接続する
本連載記事の目標
- Amazon Neptuneに対する基本的な操作・認証・運用方法を習得する
- Amazon Neptuneの全文検索を実装する
第2回目の目標
- Amazon Neptune上のプロパティグラフに対してGremlinでデータ操作する基本構文を押さえる
Gremlinとは
本連載記事ではグラフDBのモデルにプロパティグラフを使用しています。
Gremlinはこのプロパティグラフを操作するクエリ言語です。
Gremlinは、Apache TinkerPopプロジェクトの一部として提供されているグラフデータベース用のクエリ言語で、グラフデータベース上で頂点(Vertex)やエッジ(Edge)を操作するために使用され、プロパティグラフモデルに基づいて、グラフデータの照会、挿入、更新、削除などの操作を行うことができます。
プロパティグラフを操作するクエリ言語はGremlinの他にopenCypherがあります。
AWS公式ページの記載もGremlinの方が先なので、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を使うので、Gremlinのクエリに出てくる呼称に統一して書いていきます。
頂点/ノードは、GremlinではVertex
と表現されるので、これを翻訳した頂点
の方で統一します。
用語 | 用語 (日本語) |
説明 |
---|---|---|
Vertex (V) | 頂点 | エンティティを表す。例: 人、場所、物など。 |
Edge (E) | エッジ | 2つの頂点間の関係を表す。例: 「友人」「購入」「関連」など。 |
Property | プロパティ | 頂点やエッジに付与されるキーと値のペア。例: 名前、年齢、色など。 |
Label | ラベル | 頂点やエッジの種類を識別するための文字列。例: person , knows , product など。 |
Gremlinを用いたグラフデータの基本操作
Gremlinのクエリは、gremlinpythonライブラリを用いてPythonから実行します。
頂点の登録
g.addV("person").property("name", "justin").iterate()
addV()
のVはVertex(頂点)の略です。
addV()
の引数はラベルで、頂点の種類を示します。
property()
で頂点に対する属性を付与します。
このGremlinを用いたグラフデータ操作の一連のステップをトラバーサルと呼びます。
Gremlinのトラバーサルにおいて、データベースの状態に影響を与える操作を副作用があると表現します。
iterate()
はクエリの内容をNeptuneに送信するのに必要な関数で、これがないとクエリを書いても送信されないのでトラバーサルは評価されずNeptuneに反映されません。
Gremlinには、iterate() のようにクエリの内容を送信するためのメソッドが複数存在します。
以下のメソッドは Neptune DB インスタンスにクエリを送信します。 toList() toSet() next() nextTraverser() iterate()
登録した結果を確認
登録した結果を確認します。
初回のため、すべての頂点を取得して確認してみます。
all_vertices = g.V().valueMap(True).toList() print("All Vertices:", all_vertices)
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_vertices = g.V().valueMap(True).toList() print("All Vertices:", all_vertices) finally: if connection is not None: connection.close()
実行すると以下のように出力されます。
All Vertices: [{"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
はgremlinpythonでidを指定するための特別な構文です。
他のプログラミング言語やGremlinライブラリの場合は書き方が変わります。
idを指定した頂点の参照
idを指定して頂点を取得するには以下のように書きます。
vertex = g.V("10").valueMap(True).toList() print("Vertex:", vertex)
頂点の更新
g.V()
で頂点を取得できます。
引数にidを指定すればピンポイントで頂点を得られます。
これに対してproperty()
で新たなプロパティを指定すればプロパティを追加できます。
property()
でaddress
を設定します。
g.V("10").property("address", "japan").iterate() vertex = g.V("10").valueMap(True).toList() print("Vertex:", vertex)
Vertex: [{"name": ["satoshi"], <T.label: 4>: "person", "address": ["japan"], <T.id: 1>: "10"}]
ここから、property()
でaddress
を上書きを試みます。
g.V("10").property("address", "hiroshima").iterate() vertex = g.V("10").valueMap(True).toList() print("Vertex:", vertex)
Vertex: [{"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() vertex = g.V("10").valueMap(True).toList() print("Vertex:", vertex)
Vertex: [{"name": ["satoshi256kbyte"], <T.label: 4>: "person", "address": ["hiroshima", "japan"], <T.id: 1>: "10"}]
すべての頂点を削除する
以下のように書きます。
今は実験中なので、これが重宝します。
g.V().drop().iterate()
g.V()
は引数で何も指定していないので、すべての頂点を選択します。
drop()
は選択されたすべての頂点と、それに関連するエッジを削除します。
iterate()
によりクエリを実行して変更を確定します。
次回に向けて
今回はここまでです。
次回はグラフデータの可視化を行うために、可視化ツールを導入します。
参考ページ
兼安 聡(執筆記事の一覧)
アプリケーションサービス部 DS3課所属
2024 Japan AWS Top Engineers (Database)
2024 Japan AWS All Certifications Engineers
認定スクラムマスター
広島在住です。今日も明日も修行中です。