👻

Azure Cosmos DB - Gremlin (Graph) API トラブルシューティング

2022/02/19に公開

Cosmos DBをグラフデータベースとして使おうと思ったら導入時につまづくポイントが結構あったので記録します。

手順

  1. AzureコンソールからCosmos DB作成
  2. 'Quick start' で ‘Persons’ graph を作成する
  3. .NET appサンプルコードを実行

Azure Cosmos DB - 'Quick start'

Cannot add a vertex where the partition key property has value 'null'.

素直に .NET appサンプルコードを実行するとCosmod DBサーバーから以下のレスポンスが返ってくる。

ERROR:root:
Received error message '{'requestId': '2442861a-0433-4b8c-9242-d4ab452159aa', 'status': {'code': 597, 'message': "\r\n\nActivityId : 459a50a2-2697-4107-afce-29af0ef9b52e\nExceptionType : GraphRuntimeException\nExceptionMessage : \r\n\tGremlin Query Execution Error: Cannot add a vertex where the partition key property has value 'null'.\n\tGremlinRequestId : 2442861a-0433-4b8c-9242-d4ab452159aa\n\tContext : graphcompute\n\tScope : graphcomp-execquery\n\tGraphInterOpStatusCode : GraphRuntimeError\n\tHResult : 0x80131500\r\n", 'attributes': {'x-ms-status-code': 1002, 'x-ms-activity-id': '459a50a2-2697-4107-afce-29af0ef9b52e', 'x-ms-request-charge': 2.18, 'x-ms-total-request-charge': 2.18, 'x-ms-server-time-ms': 1.7511, 'x-ms-total-server-time-ms': 1.7511}}, 'result': {'data': None, 'meta': {}}}'

これは addV() クエリのプロパティにpartition keyがないことが原因なので適当に付けると通る。

Program.cs
- { "AddVertex 1",    "g.addV('person').property('id', 'thomas').property('firstName', 'Thomas').property('age', 44)" },
+ { "AddVertex 1",    "g.addV('person').property('id', 'thomas').property('firstName', 'Thomas').property('age', 44).property('partitionKey', 'pk')" },

既存の設定が partitionKey になっていることは Data Explorer - Scale & Settings で確認できる

Data Explorer - Scale & Settings

GraphSON v3 IO is not supported.

急に例がPythonになるけどgremlin_pythonのこういう標準的なリクエストは以下のようにエラーになる

main.py
remote_connection = DriverRemoteConnection(f"wss://{ACCOUNT_NAME}.gremlin.cosmosdb.azure.com/gremlin:443", 'g', 
                                           username=f"/dbs/{DB_NAME}/colls/{GRAPH_NAME}", 
                                           password=auth_key)
g = traversal().withRemote(remote_connection)

print(g.V().toList())

gremlin_python.driver.protocol.GremlinServerError: 498: 

ActivityId : 6197093d-f330-4ed5-9d4b-e6b279a0a044
ExceptionType : GraphMalformedException
ExceptionMessage : 
	Gremlin Malformed Request: GraphSON v3 IO is not supported.
	GremlinRequestId : d3aeca93-d49e-42fb-bae5-497ad0704467
	Context : global
	GraphInterOpStatusCode : MalformedRequest
	HResult : 0x80131500

これはCosmod DBのGremlinエンドポイントが現在の最近のGraphSONv3に対応していないことが原因なので、自分でシリアライザーをGraphSONv2に指定する必要がある。

GraphSONv3 serializer isn't currently supported. Use GraphSONv2 Serializer, Reader, and Writer classes in the connection configuration. https://docs.microsoft.com/en-us/azure/cosmos-db/graph/gremlin-support#unsupported-features

main.py
remote_connection = DriverRemoteConnection(f"wss://{ACCOUNT_NAME}.gremlin.cosmosdb.azure.com/gremlin:443", 'g', 
                                           username=f"/dbs/{DB_NAME}/colls/{GRAPH_NAME}", 
                                           password=auth_key,
+                                          message_serializer=GraphSONSerializersV2d0())

Unsupported request operation: 'bytecode'

上記の修正をしても実はエラーが返ってくる

gremlin_python.driver.protocol.GremlinServerError: 498: 

ActivityId : 6448c06f-04a2-40fa-a9b7-d7d9a3b5ed8a
ExceptionType : GraphMalformedException
ExceptionMessage : 
	Gremlin Malformed Request: Unsupported request operation: 'bytecode'.
	GremlinRequestId : 085fbf1e-c650-4be5-b5bc-f36df61833f1
	Context : global
	GraphInterOpStatusCode : MalformedRequest
	HResult : 0x80131500

これはCosmod DBのGremlinエンドポイントがGremlin Bytecodeの仕様に対応していないかららしい。なのでGremlinクエリを文字列で送るようにしないといけない。

最終的にはこんな感じのコードになる

main.py
GRAPH_NAME = 'Persons'
client = client.Client(f"wss://{ACCOUNT_NAME}.gremlin.cosmosdb.azure.com/gremlin:443", 'g',
                                    username=f"/dbs/{DB_NAME}/colls/{GRAPH_NAME}",
                                    password=auth_key,
                                    message_serializer=GraphSONSerializersV2d0())

client.submit("""
g.addV('person')
    .property('id', 'mary')
    .property('firstName', 'Mary')
    .property('lastName', 'Andersen')
    .property('age', 39)
    .property('partitionKey', 'pk')
""")
result_set = client.submit("g.V()")

for result in result_set:
    for vertex in result:
        print(json.dumps(vertex, indent=2))

client.close()

バイトコードで送れないということはクエリ文字列の組立てが必要になり、ライブラリが提供するDSLで書けなくなるってことなので2年ぐらい前から要望のIssueがある。

https://github.com/Azure/azure-cosmos-dotnet-v2/issues/439

ところで今見付けたけどPython版のサンプルが以下にありました

https://github.com/Azure-Samples/azure-cosmos-db-graph-python-getting-started

Discussion