はじめに
gremlin を気軽に使いたいなと思って始めたら、まあまあハマったので、他の方も同じ目に合わないために、記録しておきます。
gremlin console, gremlin python を使うための環境構築を中心に記録していきます。
とにかく、古い海外の情報しか見つけられず、情報整理・実験に時間がかなりかかりました・・
TL;DR
- サンプルそのままでは動作しない
- gremlin-server.yml をセットアップ
- host を、0.0.0.0 に
- serializer を設定
- remote.yml をセットアップ
- バージョンを揃える!
- バージョンにかなりセンシティブな印象
- gremlin-server
- gremlin-console
- gremlin python
- バージョンにかなりセンシティブな印象
- コード一式は、こちら
環境
対象 | バージョン |
---|---|
OS | macOS Big Sur (11.5.2) |
docker | Docker version 20.10.8, build 3967b7d |
docker-compose | docker-compose version 1.29.2, build 5becea4c |
python | Python 3.8.10 |
セットアップでやったこと
Dockerfile
gremlin-server
以下の内容の Dockerfile を作成
FROM tinkerpop/gremlin-server:3.4.8
WORKDIR /opt/gremlin-server/
ARG gremlin_version=3.4.8
RUN /bin/bash -c "bin/gremlin-server.sh install org.apache.tinkerpop gremlin-python ${gremlin_version}"
RUN /bin/bash -c "bin/gremlin-server.sh install org.apache.tinkerpop neo4j-gremlin ${gremlin_version}"
gremlin-python をインストールしておきます。
あとで、neo4j も試したいので、neo4j-gremlin も入れておきます。
gremlin-console
結局、Dockerfile 作らなくてもよかったんですが、何かインストールするかもしれないと作成していたので、そのまま Dockerfile に残しておきます。
FROM tinkerpop/gremlin-console:3.4.8
ここで、tinkerpop/gremlin-server
とバージョンがあってないと、console 利用時にうまく通信できずエラーになります。少なくとも、ためした範囲ではそうでした。
docker-compose.override.yml
docker-compose.yml に追記しても良かったのですが、開発用のコンテナ(app)がなくても動かせるように、override に切り出しました。
こんな感じです。
version: '3.7'
services:
gremlin-console:
build:
context: ./
dockerfile: docker/gremlin/console/Dockerfile
image: $project.gremlin-console
container_name: $project.gremlin-console
volumes:
- ./data/:/data/
- ./conf/gremlin/console/remote.yml:/opt/gremlin-console/conf/remote.yml
- ./conf/gremlin/console/remote-research.yml:/opt/gremlin-console/conf/remote-research.yml
gremlin-server:
build:
context: ./
dockerfile: docker/gremlin/server/Dockerfile
image: $project.gremlin-server
container_name: $project.gremlin-server
ports:
- "8182:8182"
volumes:
- ./data/:/data/
- ./conf/gremlin/server/gremlin-server.yml:/opt/gremlin-server/conf/gremlin-server.yml
- ./conf/gremlin/server/gremlin-server-neo4j.yml:/opt/gremlin-server/conf/gremlin-server-neo4j.yml
- ./conf/gremlin/server/neo4j.properties:/opt/gremlin-server/conf/neo4j.properties
entrypoint: >
/bin/bash bin/gremlin-server.sh conf/gremlin-server.yml
# /bin/bash bin/gremlin-server.sh conf/gremlin-server-neo4j.yml
ここで、設定ファイルを変更するため、ローカルの設定ファイル(conf 配下)をマウントしておき、entrypoint を上書きしています。
tinkerpop/gremlin-server のエントリーポイントが、設定ファイルの host を sed -i
で変更したり、拡張子が yml
じゃなくて、yaml
なのが好みに合わなかったので、entrypoint を上書きする方法を取りました。
※ Ubuntu 18.04 on WSL2 では、docker-server が、gremlin 用のユーザとグループ(100:101)で起動されるので、/data などにマウントしたり、ホストとファイル共有する際には、注意が必要です(自分は、この記事で紹介しているリポジトリではないですが、起動前に、chown する make タスクを作成しました。)
設定ファイルの作成&変更
gremlin-server のコンテナに入って、gremlin-server.yaml
をマウントした共有フォルダ(/data
など)を経由して、gremlin-server.yml
として保存しておきます。(拡張子を変えておく、yaml
-> yml
)
gremlin-server.yml の変更点
host を変更
よくある、バインドするhost
について、localhost を、0.0.0.0 に変更します。
host: 0.0.0.0
serializers に追加
gremlin 3.4.8 では、GryoMessageSerializerV3d0
(V3) を使うみたいなので、追記しておきます。(設定しないと、console 利用時にエラーになります)
serializers:
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+gryo
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV3d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+gryo-lite
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }} # application/vnd.gremlin-v1.0+gryo-stringd
remote.yml の作成
gremlin-console 利用時に、gremlin-server へ接続するための設定ファイルを作成しておきます。
ファイル名は、remote.yml
でなくてもよいです、その際は、gremlin-console のプロンプトで :remote connect tinkerpop.server conf/remote.yml
を実行する際に、remote.yml
のところを変更したファイル名に変更してください。
hosts: [gremlin-server]
port: 8182
gremlin-python をインストール
開発用の Dockerfile でインストールに使う requirements.txt
を作成しておきます。
gremlinpython
の バージョンを、gremlin-server, gremlin-console に合わせて、3.4.8
を指定します。(ここも重要です!)
# for sqa
pudb
pylint
flake8
black
coverage
pytest
pytest-flake8
pytest-cov
pytest-xdist
pytest-html
docutils==0.15
Sphinx
# for graph db
neo4j
neomodel
gremlinpython==3.4.8
以上で、セットアップは完了です。では、使っていきましょう
環境構築
リポジトリをクローン
リポジトリとして、まとめたのでクローンしてご利用ください。
git clone https://github.com/tkosht/gremlin
cd gremlin
コンテナのビルド&起動
make
起動確認
docker-compose ps
または、make ps
(docker-compose ps を Makefile でタスク定義したもの)で、確認します。
make ps
~/p/gremlin ❯❯❯ make ps
docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------------
gremlin.app /bin/bash Up
gremlin.gremlin-server /bin/bash bin/gremlin-serv ... Up 0.0.0.0:8182->8182/tcp,:::8182->8182/tcp
~/p/gremlin ❯❯❯
上のような感じで表示されれば、OKです。
使ってみる
gremlin-console から使う
gremlin-console の コマンドを並べたものを、src/gremlin/test.gremlin
として保存しているので、そのコマンドをリダイレクトして実行します。
~/p/gremlin ❯❯❯ make gremlin-console < src/gremlin/test.gremlin
docker-compose up -d app gremlin-server
gremlin.gremlin-server is up-to-date
gremlin.app is up-to-date
docker-compose run --rm gremlin-console
Creating gremlin_gremlin-console_run ... done
Sep 05, 2021 12:27:37 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin> :remote connect tinkerpop.server conf/remote.yml
==>Configured gremlin-server/172.30.0.2:8182
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [gremlin-server/172.30.0.2:8182] - type ':remote console' to return to local mode
gremlin> g.addV('person').property('name','hello')
==>v[0]
gremlin> g.addV('person').property('name','world')
==>v[2]
gremlin> g.V().values('name')
==>hello
==>world
gremlin> g.V().count()
==>2
gremlin> :exit
~/p/gremlin ❯❯❯
上のような出力結果が得られれば成功です!
python から使う
以下のように、make bash
で開発用コンテナをインタラクティブモードで起動し、python モジュール src.trial
を実行します。
~/p/gremlin ❯❯❯ make bash
docker-compose up -d app gremlin-server
gremlin.app is up-to-date
gremlin.gremlin-server is up-to-date
docker-compose exec app bash
dsuser@8307be2e3004:~/workspace$ python -m src.trial
names: ['hello', 'world']
dict: [{'name': ['hello']}, {'name': ['world']}]
count: 2
dsuser@8307be2e3004:~/workspace$
以上のように、表示されれば、成功です!
注意
コンテナを停止・削除(docker-compose down)すると、gremlin 上で作成・追加したグラフが消えます。
簡易エクスポート
エクスポートするための簡単な gremlin-console 用のスクリプト(src/gremlin/export.gremlin
)を作成したので、ご利用ください。
data/test.json
に保存します。
~/p/gremlin ❯❯❯ make gremlin-console < src/gremlin/export.gremlin
docker-compose up -d app gremlin-server
gremlin.app is up-to-date
gremlin.gremlin-server is up-to-date
docker-compose run --rm gremlin-console
Creating gremlin_gremlin-console_run ... done
Sep 05, 2021 12:37:37 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin> :remote connect tinkerpop.server conf/remote.yml
==>Configured gremlin-server/172.30.0.2:8182
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [gremlin-server/172.30.0.2:8182] - type ':remote console' to return to local mode
gremlin> // g.addV('person').property('name','hello')
==>null
gremlin> // g.addV('person').property('name','world')
==>null
gremlin> g.V().values('name')
==>hello
==>world
gremlin> g.V().count()
==>2
gremlin> g.io("/data/test.json").write()
gremlin> :exit
~/p/gremlin ❯❯❯ cat data/test.json
{"id":{"@type":"g:Int64","@value":0},"label":"person","properties":{"name":[{"id":{"@type":"g:Int64","@value":1},"value":"hello"}]}}
{"id":{"@type":"g:Int64","@value":2},"label":"person","properties":{"name":[{"id":{"@type":"g:Int64","@value":3},"value":"world"}]}}
~/p/gremlin ❯❯❯
簡易インポート
インポートするための簡単な gremlin-console 用のスクリプト(src/gremlin/import.gremlin
)を作成したので、ご利用ください。
data/test.json
からロードします。
動作確認のために、gremlin-server を down & up しておきます。
~/p/gremlin ❯❯❯ make reup
docker-compose down
Stopping gremlin.gremlin-server ... done
Stopping gremlin.app ... done
Removing gremlin.gremlin-server ... done
Removing gremlin.app ... done
Removing network gremlin_default
docker-compose up -d app gremlin-server
Creating network "gremlin_default" with the default driver
Creating gremlin.gremlin-server ... done
Creating gremlin.app ... done
~/p/gremlin ❯❯❯ make gremlin-console < src/gremlin/ref.gremlin
docker-compose up -d app gremlin-server
gremlin.gremlin-server is up-to-date
gremlin.app is up-to-date
docker-compose run --rm gremlin-console
Creating gremlin_gremlin-console_run ... done
Sep 05, 2021 12:40:24 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin> :remote connect tinkerpop.server conf/remote.yml
==>Configured gremlin-server/172.31.0.3:8182
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [gremlin-server/172.31.0.3:8182] - type ':remote console' to return to local mode
gremlin> g.V().values('name')
gremlin> g.V().count()
==>0
gremlin> :exit
~/p/gremlin ❯❯❯
次に、インポートします。
~/p/gremlin ❯❯❯ make gremlin-console < src/gremlin/import.gremlin
docker-compose up -d app gremlin-server
gremlin.app is up-to-date
gremlin.gremlin-server is up-to-date
docker-compose run --rm gremlin-console
Creating gremlin_gremlin-console_run ... done
Sep 05, 2021 12:41:36 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin> :remote connect tinkerpop.server conf/remote.yml
==>Configured gremlin-server/172.31.0.3:8182
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [gremlin-server/172.31.0.3:8182] - type ':remote console' to return to local mode
gremlin> g.io("/data/test.json").read()
gremlin> g.V().values('name')
==>hello
==>world
gremlin> g.V().count()
==>2
gremlin> :exit
~/p/gremlin ❯❯❯
ロードできているか確認します。
~/p/gremlin ❯❯❯ make gremlin-console < src/gremlin/ref.gremlin
docker-compose up -d app gremlin-server
gremlin.gremlin-server is up-to-date
gremlin.app is up-to-date
docker-compose run --rm gremlin-console
Creating gremlin_gremlin-console_run ... done
Sep 05, 2021 12:42:30 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin> :remote connect tinkerpop.server conf/remote.yml
==>Configured gremlin-server/172.31.0.3:8182
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [gremlin-server/172.31.0.3:8182] - type ':remote console' to return to local mode
gremlin> g.V().values('name')
==>hello
==>world
gremlin> g.V().count()
==>2
gremlin> :exit
WARN io.netty.channel.nio.NioEventLoop - Selector.select() returned prematurely 512 times in a row; rebuilding Selector io.netty.channel.nio.SelectedSelectionKeySetSelector@239e1c3a.
~/p/gremlin ❯❯❯
hello
, world
が ロードされていることが確認できました。
おっと、WARN も出てますね。。
:exit
後なので、一旦、置いておきます。
まとめ
上位互換性を結構期待して、環境セットアップをやってたら、本当にハマりました。
gremlin は、バージョンセンシティブだとかなり、体験できました。今後、間違いなく気をつけるでしょう笑。
同じように苦労し始めている方の助けになれば幸いです。
サーバ down&up の度に、export & import するのは微妙なので、
次は、neo4j ファイルとして永続化する方法を整理したいと思います。
Makefile のタスクとして定義すれば、export & import を毎回やってもよいのですが、データ量が増えた時は、export & import コストも侮れないと思いますので。
参考URL
めちゃくちゃ調べたんですが、記憶に残っているサイトだけ・・
Stack Overflow のサイトとか・・忘れました( ; ; )