#!/usr/bin/env python3# -*- coding: utf-8 -*-## Copyright 2020 Alibaba Group Holding Limited. All Rights Reserved.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#importloggingfromenumimportEnumfromgremlin_python.driver.clientimportClientfromgremlin_python.driver.driver_remote_connectionimportDriverRemoteConnectionfromgremlin_python.process.anonymous_traversalimporttraversalfromgraphscope.framework.dag_utilsimportgremlin_to_subgraphfromgraphscope.framework.utilsimportdeprecatedlogger=logging.getLogger("graphscope")classInteractiveQueryStatus(Enum):"""Enumeration class of current status of InteractiveQuery"""Initializing=0Running=1Failed=2Closed=3
[docs]classInteractiveQuery(object):"""`InteractiveQuery` class, is a simple wrapper around `Gremlin-Python <https://pypi.org/project/gremlinpython/>`_, which implements Gremlin within the Python language. It also can expose gremlin endpoint which can be used by any other standard gremlin console, with the method `gremlin_url()`. It also has a method called `subgraph` which can extract some fragments from origin graph, produce a new, smaller but concise graph stored in vineyard, which lifetime is independently of the origin graph. User can either use `execute()` to submit a script, or use `traversal_source()` to get a `GraphTraversalSource` for further traversal. """
[docs]def__init__(self,graph,frontend_gremlin_endpoint,frontend_cypher_endpoint):"""Construct a :class:`InteractiveQuery` object."""# graph object id stored in vineyardself._graph=graphself._session=graph._sessionself._gremlin_url=[f"ws://{endpoint}/gremlin"forendpointinfrontend_gremlin_endpoint.split(",")]self._cypher_url=[f"neo4j://{endpoint}"forendpointinfrontend_cypher_endpoint.split(",")]self._conn=Noneself._gremlin_client=Noneself._cypher_driver=Noneself.closed=False
@property@deprecated("Please use `gremlin_url` instead")defgraph_url(self):"""This will be deprecated in the future, use `gremlin_url` instead."""returnself._gremlin_url@propertydefgremlin_url(self):"""The gremlin graph url can be used with any standard gremlin console, e.g., tinkerpop."""returnself._gremlin_url@propertydefcypher_url(self):"""The cypher graph url can be used with any standard cypher console, e.g., neo4j."""returnself._cypher_url@propertydefobject_id(self):returnself._graph.vineyard_id@propertydefsession(self):returnself._session@propertydefsession_id(self):returnself._session.session_id
[docs]defexecute(self,query,lang="gremlin",request_options=None,**kwargs):"""A simple wrapper around `submit`, for compatibility"""returnself.submit(query,lang,request_options=request_options,**kwargs)
[docs]defsubmit(self,query,lang="gremlin",request_options=None,**kwargs):fromneo4jimportRoutingControl"""Execute gremlin or cypher querying scripts. <Gremlin> Args: query (str): Scripts that written in gremlin query language. request_options (dict, optional): Gremlin request options. format: { "engine": "gae" } Returns: :class:`gremlin_python.driver.client.ResultSet`: <Cypher> Args: query (str): Scripts that written in cypher query language. kwargs (dict, optional): Cypher request options. e.g.: routing_ = RoutingControl.READ Returns: :class:`neo4j.work.result.Result`: """iflang=="gremlin":returnself.gremlin_client.submit(query,request_options=request_options)eliflang=="cypher":returnself.cypher_driver.execute_query(query,routing_=RoutingControl.READ,**kwargs)else:raiseValueError(f"Unsupported query language: {lang} other than gremlin and cypher")
[docs]defsubgraph(self,gremlin_script,lang="gremlin",request_options=None):"""We currently only support subgraph using gremlin script. Create a subgraph, which input is the executor result of `gremlin_script`. Any gremlin script that output a set of edges can be used to construct a subgraph. Args: gremlin_script (str): Gremlin script to be executed. request_options (dict, optional): Gremlin request options. format: { "engine": "gae" } Returns: :class:`graphscope.framework.graph.GraphDAGNode`: A new graph constructed by the gremlin output, that also stored in vineyard. """assertlang=="gremlin","Only support gremlin script"# avoid circular importfromgraphscope.framework.graphimportGraphDAGNodeop=gremlin_to_subgraph(self,gremlin_script=gremlin_script,request_options=request_options,oid_type=self._graph._oid_type,)returnself._session._wrapper(GraphDAGNode(self._session,op))
[docs]deftraversal_source(self):"""We currently only support traversal_source using gremlin. Create a GraphTraversalSource and return. Once `g` has been created using a connection, we can start to write Gremlin traversals to query the remote graph. Raises: RuntimeError: If the interactive script is not running. Examples: .. code:: python sess = graphscope.session() graph = load_modern_graph(sess, modern_graph_data_dir) interactive = sess.gremlin(graph) g = interactive.traversal_source() print(g.V().both()[1:3].toList()) print(g.V().both().name.toList()) Returns: `GraphTraversalSource` """ifself._connisNone:self._conn=DriverRemoteConnection(self._gremlin_url[0],"g")returntraversal().withRemote(self._conn)