From 8e8f0b75c6b3e4af22764a20e8233035ab90839d Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Wed, 12 Mar 2025 17:20:38 -0700 Subject: [PATCH 1/2] Add vector functions --- pyTigerGraph/__init__.py | 2 +- pyTigerGraph/common/base.py | 3 +- pyTigerGraph/pyTigerGraphVertex.py | 76 ++++++++++++++++++-- pyTigerGraph/pytgasync/pyTigerGraphVertex.py | 72 +++++++++++++++++-- 4 files changed, 141 insertions(+), 12 deletions(-) diff --git a/pyTigerGraph/__init__.py b/pyTigerGraph/__init__.py index f93cd71b..228f4ade 100644 --- a/pyTigerGraph/__init__.py +++ b/pyTigerGraph/__init__.py @@ -2,6 +2,6 @@ from pyTigerGraph.pytgasync.pyTigerGraph import AsyncTigerGraphConnection from pyTigerGraph.common.exception import TigerGraphException -__version__ = "1.8.4" +__version__ = "1.8.5" __license__ = "Apache 2" diff --git a/pyTigerGraph/common/base.py b/pyTigerGraph/common/base.py index 1d17fa18..f90383c4 100644 --- a/pyTigerGraph/common/base.py +++ b/pyTigerGraph/common/base.py @@ -271,7 +271,8 @@ def _error_check(self, res: dict) -> bool: if "error" in res and res["error"] and res["error"] != "false": # Endpoint might return string "false" rather than Boolean false raise TigerGraphException( - res["message"], (res["code"] if "code" in res else None)) + res["message"], (res["code"] if "code" in res else None) + ) return False def _prep_req(self, authMode, headers, url, method, data): diff --git a/pyTigerGraph/pyTigerGraphVertex.py b/pyTigerGraph/pyTigerGraphVertex.py index bfe434cf..6224170e 100644 --- a/pyTigerGraph/pyTigerGraphVertex.py +++ b/pyTigerGraph/pyTigerGraphVertex.py @@ -77,7 +77,7 @@ def getVertexAttrs(self, vertexType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getAttributes") + logger.info("entry: getVertexAttrs") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -85,15 +85,78 @@ def getVertexAttrs(self, vertexType: str) -> list: ret = [] for at in et["Attributes"]: + at["AttributeType"]["AttributeType"] = at["AttributeType"].pop("Name") ret.append( - (at["AttributeName"], self._getAttrType(at["AttributeType"]))) + (at["AttributeName"], at["AttributeType"]) + ) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getAttributes") + logger.info("exit: getVertexAttrs") return ret + def getVertexVectors(self, vertexType: str) -> list: + """Returns the names and types of the embedding attributes of the vertex type. + + Args: + vertexType: + The name of the vertex type. + + Returns: + A list of (vector_name, vector_type) tuples. + The format of vector_type is one of + - "scalar_type" + - "complex_type(scalar_type)" + - "map_type(key_type,value_type)" + and it is a string. + """ + logger.info("entry: getVertexVectors") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + et = self.getVertexType(vertexType) + ret = [] + + for vt in et["EmbeddingAttributes"]: + ret.append( + (vt["Name"], vt) + ) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getVertexVectors") + + return ret + + def getVectorStatus(self, vertexType: str, vectorAttr: str = "") -> bool: + """Check the rebuild status of the vertex type or the embedding attribute + + Args: + vertexType: + The name of the vertex type. + vectorAttr: + The name of the vector attribute, optional. + + Returns: + a bool indicates whether vector rebuild is done or not + + Endpoint: + - `GET /vector/status/{graph_name}/{vertex_type}/[{vector_name}]` + """ + logger.info("entry: getVectorStatus") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + ret = self._req("GET", self.restppUrl + "/vector/status/" + + self.graphname + "/" + vertexType + "/" + vectorName) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getVectorStatus") + + return len(ret["NeedRebuildServers"]) == 0 + def getVertexType(self, vertexType: str, force: bool = False) -> dict: """Returns the details of the specified vertex type. @@ -215,7 +278,7 @@ def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = None) ``` Example: ``` - {"name": "Thorin", points: (10, "+"), "bestScore": (67, "max")} + {"name": "Thorin", points: (10, "+"), "bestScore": (83, "max"), "embedding": [0.1, -0.2, 3.1e-2]} ``` For valid values of `` see xref:tigergraph-server:API:built-in-endpoints.adoc#_operation_codes[Operation codes]. @@ -268,7 +331,8 @@ def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = False) ---- [ (2, {"name": "Balin", "points": (10, "+"), "bestScore": (67, "max")}), - (3, {"name": "Dwalin", "points": (7, "+"), "bestScore": (35, "max")}) + (3, {"name": "Dwalin", "points": (7, "+"), "bestScore": (35, "max")}), + (4, {"name": "Thorin", points: (10, "+"), "bestScore": (83, "max"), "embedding": [0.1, -0.2, 3.1e-2]}) ] ---- @@ -799,4 +863,4 @@ def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withType: b logger.debug("return: " + str(ret)) logger.info("exit: vertexSetToDataFrame") - return ret \ No newline at end of file + return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py index 7fcf5b56..ca550f6d 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py @@ -87,8 +87,10 @@ async def getVertexAttrs(self, vertexType: str) -> list: ret = [] for at in et["Attributes"]: + at["AttributeType"]["AttributeType"] = at["AttributeType"].pop("Name") ret.append( - (at["AttributeName"], self._getAttrType(at["AttributeType"]))) + (at["AttributeName"], at["AttributeType"]) + ) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) @@ -96,6 +98,67 @@ async def getVertexAttrs(self, vertexType: str) -> list: return ret + async def getVertexVectors(self, vertexType: str) -> list: + """Returns the names and types of the embedding attributes of the vertex type. + + Args: + vertexType: + The name of the vertex type. + + Returns: + A list of (vector_name, vector_type) tuples. + The format of vector_type is one of + - "scalar_type" + - "complex_type(scalar_type)" + - "map_type(key_type,value_type)" + and it is a string. + """ + logger.info("entry: getVertexVectors") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + et = await self.getVertexType(vertexType) + ret = [] + + for vt in et["EmbeddingAttributes"]: + ret.append( + (vt["Name"], vt) + ) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getVertexVectors") + + return ret + + async def getVectorStatus(self, vertexType: str, vectorAttr: str = "") -> bool: + """Check the rebuild status of the vertex type or the embedding attribute + + Args: + vertexType: + The name of the vertex type. + vectorAttr: + The name of the vector attribute, optional. + + Returns: + a bool indicates whether vector rebuild is done or not + + Endpoint: + - `GET /vector/status/{graph_name}/{vertex_type}/[{vector_name}]` + """ + logger.info("entry: getVectorStatus") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + ret = await self._req("GET", self.restppUrl + "/vector/status/" + + self.graphname + "/" + vertexType + "/" + vectorName) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.info("exit: getVectorStatus") + + return len(ret["NeedRebuildServers"]) == 0 + async def getVertexType(self, vertexType: str, force: bool = False) -> dict: """Returns the details of the specified vertex type. @@ -222,7 +285,7 @@ async def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = ``` Example: ``` - {"name": "Thorin", points: (10, "+"), "bestScore": (67, "max")} + {"name": "Thorin", points: (10, "+"), "bestScore": (83, "max"), "embedding": [0.1, -0.2, 3.1e-2]} ``` For valid values of `` see xref:tigergraph-server:API:built-in-endpoints.adoc#_operation_codes[Operation codes]. @@ -275,7 +338,8 @@ async def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = F ---- [ (2, {"name": "Balin", "points": (10, "+"), "bestScore": (67, "max")}), - (3, {"name": "Dwalin", "points": (7, "+"), "bestScore": (35, "max")}) + (3, {"name": "Dwalin", "points": (7, "+"), "bestScore": (35, "max")}), + (4, {"name": "Thorin", points: (10, "+"), "bestScore": (83, "max"), "embedding": [0.1, -0.2, 3.1e-2]}) ] ---- @@ -810,4 +874,4 @@ async def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withT logger.debug("return: " + str(ret)) logger.info("exit: vertexSetToDataFrame") - return ret \ No newline at end of file + return ret From 7f46793767ec1d15c88594dbdf5fbdfbb0a5d616 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Thu, 13 Mar 2025 14:29:32 -0700 Subject: [PATCH 2/2] fix typo --- pyTigerGraph/pytgasync/pyTigerGraphVertex.py | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py index ca550f6d..b5347a7f 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py @@ -83,14 +83,15 @@ async def getVertexAttrs(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - et = await self.getVertexType(vertexType) + vt = await self.getVertexType(vertexType) ret = [] - for at in et["Attributes"]: - at["AttributeType"]["AttributeType"] = at["AttributeType"].pop("Name") - ret.append( - (at["AttributeName"], at["AttributeType"]) - ) + if "Attributes" in vt: + for at in vt["Attributes"]: + at["AttributeType"]["AttributeType"] = at["AttributeType"].pop("Name") + ret.append( + (at["AttributeName"], at["AttributeType"]) + ) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) @@ -117,13 +118,14 @@ async def getVertexVectors(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - et = await self.getVertexType(vertexType) + vt = await self.getVertexType(vertexType) ret = [] - for vt in et["EmbeddingAttributes"]: - ret.append( - (vt["Name"], vt) - ) + if "EmbeddingAttributes" in vt: + for et in vt["EmbeddingAttributes"]: + ret.append( + (et["Name"], et) + ) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) @@ -131,7 +133,7 @@ async def getVertexVectors(self, vertexType: str) -> list: return ret - async def getVectorStatus(self, vertexType: str, vectorAttr: str = "") -> bool: + async def getVectorStatus(self, vertexType: str, vectorName: str = "") -> bool: """Check the rebuild status of the vertex type or the embedding attribute Args: