class WordVector(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = WordVector(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) def save_vertex(self, vector_id, properties): """ 保存词向量 :param vector_id: 词向量 ID :param properties: 词向量属性 :return: 保存结果 """ return self.g.save_vertex("word_vector", str(vector_id), properties) def save_edge(self, vector_id, related_id, related_type, properties): """ 保存词向量关系 :param vector_id: 词向量 ID :param related_id: 相关联的顶点 ID :param related_type: 关系类型 :param properties: 关系属性 :return: 保存结果 """ return self.g.save_edge(related_type, str(related_id), str(vector_id), properties)
class AddProperty(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = AddProperty(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) self.mock_data() def mock_data(self): # 创建一个 person 类型的顶点 dsl = """ g.addV('person') """ ret = self.g.exec_dsl(dsl).result().next() print(ret) def run(self): # 给 person 类型的顶点添加 name 和 age 属性 dsl = """ g.V().hasLabel("person"). property('name', name). property('age', age) """ bindings = {"name": "stephen", "age": "25"} self.g.exec_dsl(dsl, bindings) Common.get_instance().show_graph()
class Singer(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = Singer(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) def save_vertex(self, singer_id, properties): """ 保存歌手 :param singer_id: 歌手 ID :param properties: 歌手属性 :return: 保存结果 """ return self.g.save_vertex("singer", str(singer_id), properties) def save_edge(self, singer_id, related_id, related_type, properties): """ 保存歌手关系 :param singer_id: 歌手 ID :param related_id: 相关联的顶点 ID :param related_type: 关系类型 :param properties: 关系属性 :return: 保存结果 """ return self.g.save_edge(related_type, str(singer_id), str(related_id), properties)
class AddEdge(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = AddEdge(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) self.mock_data() def mock_data(self): # 创建两个 person 类型的顶点并设置 id 和 name dsl = """ g.addV('person'). property(id, uid_1). property('name', name_1). addV('person'). property(id, uid_2). property('name', name_2) """ bindings = { "uid_1": "1", "name_1": "marko", "uid_2": "2", "name_2": "stephen" } ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) def run(self): # 给两个 person 顶点添加 knows 类型的边 dsl = """ g.V(from_uid).addE('knows').to(V(to_uid)). property(id, edge_id) """ bindings = {"from_uid": "1", "to_uid": "2", "edge_id": "1-knows-2"} ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) Common.get_instance().show_graph()
class And(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = And(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) self.mock_data() def mock_data(self): # 创建两个 person 类型的顶点 dsl = """ g.addV('person'). property(id, uid_1). property('age', age_1). addV('person'). property(id, uid_2). property('age', age_2) """ bindings = {"uid_1": 1, "age_1": 20, "uid_2": 2, "age_2": 25} ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) def run(self): dsl = """ g.V().has('age', inside(start_1, end_1)). and(). has('age', outside(start_2, end_2)). values('age') """ # (10, 30) 与 (-∞, 15) U (20, +∞) 的交集 => 25 bindings = {'start_1': 10, 'end_1': 30, 'start_2': 15, 'end_2': 20} vertex_list = self.g.exec_dsl(dsl, bindings).result().next() print("ans: {}".format(vertex_list)) Common.get_instance().show_graph()
class AddVertex(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = AddVertex(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) def run(self): """ 创建一个 person 类型的顶点并设置 id 和 name """ dsl = "g.addV('person').property(id, uid).property('name', name)" bindings = {"name": "stephen", "uid": "1"} ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) Common.get_instance().show_graph()
class Utils(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = Utils(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) @staticmethod def format_graph_fields(graph_data): format_data = {} for k, v in graph_data.items(): format_data[str(k)] = v[0] if type(v) == list else v format_data['id'] = format_data['T.id'] format_data['label'] = format_data['T.label'] del format_data['T.id'] del format_data['T.label'] return format_data def graph_visualization(self, size=100): """ 将图数据库中的数据可视化 :param size: 起始点的数量(歌曲) :return: """ dsl = """ g.V().hasLabel('song').limit(size).as('SONGS'). project('song', 'user', 'singer'). by(select('SONGS').valueMap(true)). by(select('SONGS').in('favorite_song').valueMap(true).fold()). by(select('SONGS').in('create_song').valueMap(true).fold()) """ bindings = {"size": size} callback = self.g.query_dsl(dsl, bindings) relation = {"vertex": [], "edge": []} for ret in callback.result(): for data in ret: song = self.format_graph_fields(data["song"]) relation["vertex"].append(song) user_list = [] for user in data["user"]: user = self.format_graph_fields(user) user_list.append(user) relation["edge"].append({ "from": user["id"], "to": song["id"], "type": "favorite_song" }) relation["vertex"].extend(user_list) singer_list = [] for singer in data["singer"]: singer = self.format_graph_fields(singer) singer_list.append(singer) relation["edge"].append({ "from": singer["id"], "to": song["id"], "type": "create_song" }) relation["vertex"].extend(singer_list) result = { "type": "force", "categories": [{ "name": "用户" }, { "name": "歌曲" }, { "name": "歌手" }], "nodes": [], "links": [] } category_index = {"user": 0, "song": 1, "singer": 2} vertex_index = {} for i, vertex in enumerate(relation["vertex"]): result["nodes"].append({ "name": vertex["name"], "value": 1, "category": category_index[vertex["label"]] }) vertex_index[vertex["id"]] = i for edge in relation["edge"]: result["links"].append({ "source": vertex_index[edge["from"]], "target": vertex_index[edge["to"]] }) return json.dumps(result)
def __init__(self, graph_tag): self.g = Graph(graph_tag)
def __init__(self, graph_tag): self.g = Graph(graph_tag) self.mock_data()
class Common(object): _instances = {} WAITING_TIME = 1 @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = Common(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) def show_graph(self): time.sleep(Common.WAITING_TIME) vertex_list = self._get_vertex() edge_list = self._get_edge() data = {} if vertex_list: data["vertex"] = vertex_list if edge_list: data["edge"] = edge_list print(json.dumps(data, indent=4, sort_keys=True)) print("-" * 50) def _get_vertex(self): dsl = "g.V().valueMap(true)" callback = self.g.exec_dsl(dsl) result = [] for ret in callback.result(): for vertex in ret: data = self._format_graph_fields(vertex) result.append(data) return result def _get_edge(self): dsl = "g.E().valueMap(true)" callback = self.g.exec_dsl(dsl) result = [] for ret in callback.result(): for edge in ret: data = self._format_graph_fields(edge) result.append(data) return result @staticmethod def _format_graph_fields(graph_data): format_data = {} for k, v in graph_data.items(): format_data[str(k)] = v[0] if type(v) == list else v format_data['id'] = format_data['T.id'] format_data['label'] = format_data['T.label'] del format_data['T.id'] del format_data['T.label'] return format_data
class User(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = User(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) def find_similar_user(self, uid, top_n=3): """ 找到与当前用户兴趣相近的用户 :param uid: 用户 ID :return: 兴趣相近的用户信息 """ dsl = """ g.V(uid).as('v1'). out('favorite_song').in('favorite_song').dedup().where(neq('v1')).as('v2'). project('v1', 'v2', 'v1n', 'v2n'). by(select('v1')). by(select('v2')). by(select('v1').out('favorite_song').fold()). by(select('v2').out('favorite_song').fold()). as('q1'). project('v1', 'v2', 'i', 'u'). by(select('v1')). by(select('v2')). by(select('v1n').as('n'). select('q1').select('v2n').unfold(). where(within('n')). count()). by(union(select('v1n'). select('q1').select('v2n')).unfold(). dedup().count()). project('v1', 'v2', 'jaccard'). by(select('v1').valueMap(true)). by(select('v2').valueMap(true)). by(math('i/u')).order().by(select('jaccard'), desc). limit(top_n) """ bindings = {"uid": uid, "top_n": top_n} callback = self.g.query_dsl(dsl, bindings) result = [] for ret in callback.result(): for data in ret: v2_vertex = Utils.format_graph_fields(data["v2"]) result.append({ "uid": v2_vertex["id"], "name": v2_vertex["name"], "jaccard_score": round(data["jaccard"], 5) }) return result def save_vertex(self, uid, properties): """ 保存用户 :param uid: 用户 ID :param properties: 用户属性 :return: 保存结果 """ return self.g.save_vertex("user", str(uid), properties) def save_edge(self, uid, related_id, related_type, properties): """ 保存用户关系 :param uid: 用户 ID :param related_id: 相关联的顶点 ID :param related_type: 关系类型 :param properties: 关系属性 :return: 保存结果 """ return self.g.save_edge(related_type, str(uid), str(related_id), properties)
class Aggregate(object): _instances = {} @classmethod def get_instance(cls, graph_tag='default'): if graph_tag not in cls._instances: cls._instances[graph_tag] = Aggregate(graph_tag) return cls._instances[graph_tag] def __init__(self, graph_tag): self.g = Graph(graph_tag) self.mock_data() def mock_data(self): # 创建两个 person 类型的顶点和两个 song 类型的顶点 dsl = """ g.addV('person'). property(id, uid_1). property('name', name_1). addV('person'). property(id, uid_2). property('name', name_2). addV('song'). property(id, song_id_1). property('name', song_name_1). addV('song'). property(id, song_id_2). property('name', song_name_2) """ bindings = { "uid_1": "u1", "name_1": "marko", "uid_2": "u2", "name_2": "stephen", "song_id_1": "s1", "song_name_1": "song-A", "song_id_2": "s2", "song_name_2": "song-B" } ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) # 添加三条边: marko-like->song-A;stephen-like-song-A;stephen-like-song-B dsl = """ g.V(uid_1).addE('like').to(V(song_id_1)). property(id, edge_id_1). V(uid_2).addE('like').to(V(song_id_1)). property(id, edge_id_2). V(uid_2).addE('like').to(V(song_id_2)). property(id, edge_id_3) """ bindings = { "uid_1": "u1", "name_1": "marko", "uid_2": "u2", "name_2": "stephen", "song_id_1": "s1", "song_name_1": "song-A", "song_id_2": "s2", "song_name_2": "song-B", "edge_id_1": "u1-like-song-A", "edge_id_2": "u2-like-song-A", "edge_id_3": "u2-like-song-B" } ret = self.g.exec_dsl(dsl, bindings).result().next() print(ret) def run(self): # 找到与 marko 有共同兴趣的人还喜欢哪些 marko 没喜欢的歌曲 dsl = """ g.V(uid_1).out('like').aggregate('x'). in('like').out('like'). where(without('x')). values('name') """ bindings = {"uid_1": "u1"} self.g.exec_dsl(dsl, bindings) Common.get_instance().show_graph()