Neo4j 简单构建掘金人物关系

1,952 阅读4分钟

先可视化的看一下 掘金酱 有没有关注你。。。

graph (2).png

简介

Neo4j

Neo是一个网络——面向网络的数据库——也就是说,它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络上而不是表中。网络(从数学角度叫做图)是一个灵活的数据结构,可以应用更加敏捷和快速的开发模式。

  • 开源,支持ACID,具有用于企业部署的高可用性集群。
  • 附带基于Web的管理工具,包括完整事务支持和可视节点链接图浏览器;
  • 内置的REST Web API接口从大多数编程语言访问,以及使用官方驱动程序的专有Bolt协议;

Neo4j 安装

推荐 Docker 安装 Docker Hub 地址

Docker 安装的优势有:

  • 不依赖宿主机任何语言环境,只需要安装 docker。
  • 部署方便,一行命令即可实现部署。
  • 配置简单,不需要配置 环境变量、资源参数等莪皮质。
  • 随时重启恢复,遇到问题可以快速恢复。
# 在装有 docker 环境的电脑上直接启动
docker run -p 7474:7474 -p 7687:7687 -v /d/docker/neo4j:/data --restart=always neo4j

安装成功后浏览器访问 http://localhost:7474/ 进行初始化设置:

  • 输入默认的用户名密码 neo4j/neo4j
  • 修改密码为 admin
  • 再次登录进系统

image.png

Cypher 查询

Cypher 类似 Mysql 数据库具有查询语言 SQL,Neo4j 具有 CQL 作为查询语言。

这里只演示简单的语句,详细的语句见 Neo4j 文档

创建对象

# 创建一个名称为张三的 Person 对象
CREATE (:Person {name:"张三"});

# 建立张三关注李四的关系 
MATCH (a:Person {name: "张三"}) MATCH (b:Person {name: "李四"}) MERGE (a)-[:Follower]->(b);

查询对象

# 返回所有 Person 对象
MATCH (p:Person) RETURN p;

# 查询 name="张三" 的 Person 对象
MATCH (p:Person) where p.name="张三" RETURN p;

# 查询两个节点之间关系为 Follower 的所有 Person 对象
MATCH(p1:Person) - [:Follower]->(p2:Person)  return p1,p2;

删除对象

# 删除所有 Person 对象
MATCH(p:Person) DETACH DELETE p;

修改对象

# name 为张三 的 Person 对象新增 age 属性且替换 name属性
MATCH (p:Person{name:"张三"}) set p={name:"张三"} return p;

# name 为张三 的 Person 对象新增 age 属性
MATCH (p:Person{name:"张三"}) set p+={name:"张三"} return p;

创建索引

# 为Person 对象 name 属性创建索引
CREATE INDEX ON :Person(name);

Python 构建数据

数据准备

这里采用的数据为掘金的关注数据,所以先封装掘金获取关注者的接口

import requests

class JueJin(object):
    followers_url = "https://api.juejin.cn/user_api/v1/follow/followers"
    followees_url = "https://api.juejin.cn/user_api/v1/follow/followees"

    def __init__(self):
        self.session = requests.session()

    def get_followers(self, user_id, cursor, limit):
        params = {
            "user_id": user_id,
            "cursor": cursor,
            "limit": limit
        }
        return self.session.request("get", self.followers_url, params=params).json()

    def get_followees(self, user_id, cursor, limit):
        params = {
            "user_id": user_id,
            "cursor": cursor,
            "limit": limit
        }
        return self.session.request("get", self.followees_url, params=params).json()

封装查询语句

为了操作简单这里封装基本的查询语言:


from neo4j import GraphDatabase

class App(object):

    def __init__(self, uri, username, password):
        self.driver = GraphDatabase.driver(uri, auth=(username, password))

    def close(self):
        self.driver.close()

    @classmethod
    def create_person(cls, tx, name):
        tx.run("CREATE (:Person {name: $name})", name=name)

    @classmethod
    def create_friendship(cls, tx, name_a, name_b):
        tx.run("MATCH (a:Person {name: $name_a}) "
               "MATCH (b:Person {name: $name_b}) "
               "MERGE (a)-[:Follower]->(b)",
               name_a=name_a, name_b=name_b)

    @classmethod
    def delete_person(cls, tx):
        tx.run("MATCH(p:Person) DETACH DELETE p;", )

    @staticmethod
    def _find_and_return_person(tx, name):
        query = (
            "MATCH (p:Person) "
            "WHERE p.name = name "
            "RETURN p.name AS name"
        )
        result = tx.run(query, name=name)
        return [record["name"] for record in result]

批量创建节点

def main():
    # Connecting to Aura, use the "neo4j+s" URI scheme
    scheme = "neo4j"
    host_name = "deepin"
    port = 7687
    url = "{scheme}://{host_name}:{port}".format(scheme=scheme, host_name=host_name, port=port)
    user = "neo4j"
    # 这里输入你设置的密码
    password = "admin"
    app = App(url, user, password)

    juejin = JueJin()
    # 你想看哪位掘友的就替换为对应掘友的信息
    user_id, user_name = "993614678985085", "西红柿蛋炒饭"
    cursor, limit = 0, 20
    followees, followers = [], []

    has_more = True
    while has_more:
        result = juejin.get_followees(user_id, cursor, limit)
        data = result['data']['data']
        followees += data
        has_more = result['data']['hasMore']
        cursor = result['data']['cursor']

    cursor, limit = 0, 20
    has_more = True
    while has_more:
        result = juejin.get_followers(user_id, cursor, limit)
        data = result['data']['data']
        followers += data
        has_more = result['data']['hasMore']
        cursor = result['data']['cursor']

    names = {f["user_name"] for f in followees + followers}

    with app.driver.session() as session:

        session.write_transaction(app.delete_person)

        session.write_transaction(
            app.create_person, user_name)

        for name in names:
            session.write_transaction(
                app.create_person, name)

        for person in followees:
            session.write_transaction(
                app.create_friendship, user_name, person['user_name'])

        for person in followers:
            session.write_transaction(
                app.create_friendship, person['user_name'], user_name)

    app.close()

查看结果

所有节点数据 MATCH(p:Person) return p;

graph (1).png

互相关注节点数据 MATCH(p1:Person) - [:Follower]->(p2:Person) - [:Follower]->(p1:Person) return p1,p2;

graph.png

最后

这里只是演示了最简单的使用,实际上关于 Neo4j 的用处有很多,非常值得探索,下面分享一下我异想天开的想法:

    1. 构建掘金用户的关系图,看看你与我之间到底隔了几个掘友。
    1. 可以用来做搜索推荐,推荐你关注的掘友关注的掘友喜欢的文章。
    1. 可以可视化的显示你关注的掘友关注的掘友,顺便去关注这位掘友。

当然这些想法都是基于海量的掘友数据完成了,这又是个体力活。emm 就这样吧。

如果你觉得我的项目对你有帮助,欢迎一键三连❤️❤️❤️。此项目代码见 GitHub ,也欢迎 star fork。