• 坦克世界WOT知识图谱之知识图谱篇


    关于Neo4j

      Neo4j是一个高性能的,NOSQL图形数据库。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。是构建知识图谱最常用的图数据库之一。

      知识图谱部署在Linux服务器上,具体版本信息为:
      Ubuntu 22.04.2
      Java 17.0.8
      Neo4j 5.12.0

    在这里插入图片描述

    1. neo4j安装及配置:

      Neo4j依赖Java引擎,因此需要安装Java

      Java17官方地址:https://www.oracle.com/java/technologies/downloads/#java17

    在这里插入图片描述

      Neo4j官方地址:https://neo4j.com/deployment-center/#community

    在这里插入图片描述
      安装流程:

    # 下载java17
    wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
    # 下载neo4j
    https://dist.neo4j.org/neo4j-community-5.12.0-unix.tar.gz
    
    # 解压到/usr/local
    sudo tar -zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/
    sudo tar -zxvf neo4j-community-5.12.0-unix.tar.gz -C /usr/local/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

      配置流程:

    # 配置neo4j
    vim /usr/local/neo4j-community-5.12.0/conf/neo4j.conf
    # line 65 设置远程访问
    server.default_listen_address=0.0.0.0
    # line 86, 91 设置端口
    server.bolt.listen_address=:7687
    server.http.listen_address=:7474
    # 7687是bolt端口,Bolt协议是neo4j的应用层协议
    # 7474和7473分别是http和https端口,可以通过浏览器来访问可视化界面
    
    # 配置环境变量
    vim ~/.bashrc
    # >>> setting neo4j >>>
    JAVA_HOME=/usr/local/jdk-17.0.8
    NEO4J_HOME=/usr/local/neo4j-community-5.12.0
    export PATH=$JAVA_HOME/bin:$NEO4J_HOME/bin:$PATH
    # <<< setting neo4j <<<
    
    # 使配置生效
    source ~/.bashrc
    
    # 查看版本
    java --version
    neo4j --version
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

      版本信息如下:

    在这里插入图片描述

      以下是neo4j常用的几个指令:

    # 启动neo4j
    neo4j start
    # 查看neo4j的状态
    neo4j status
    # 停止neo4j
    neo4j stop
    # 重启neo4j
    neo4j restart 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

      ps: 如果因权限问题启动失败,则需要给予一定的权限:
      bash sudo chmod 777 -R neo4j-community-5.12.0 jdk-17.0.8

      浏览器访问可视化界面http://localhost:7474(可以修改为数据库的ip),初始账户及密码均为neo4j

    在这里插入图片描述
      登录后会自动跳转让修改初始密码,修改完毕后进入可视化界面:

    在这里插入图片描述

    2. 确定三元组

      关于知识图谱中三元组的相关知识,这里也不再进行概述,感兴趣的可以查阅相关资料。
      本来计划按照如下方式进行构造知识图谱,但后来实现的过程中发现,不太好构造(其实还不太熟练哈哈哈哈😅),所以就构造简单了些,比如坦克的火力/机动性/防护/侦察这些属性直接展开了。

    在这里插入图片描述
      展开后的关系如下:

    # (实体, 关系, 实体)
    Tank:
        系别:
        类型:
        等级:
        角色:
        性质:
        历史背景:
        
        银币:
        经验:
        
        损伤:
        装甲穿透力:
        火炮装填时间:
        最小弹震持续时间:
        最大弹震持续时间:
        射速:
        平均每分钟损伤:
        瞄准时间:
        00米精度:
        弹药容量:
        
        重量/最大载重量:
        发动机功率:
        单位功率:
        最大速度:
        旋转速度:
        炮塔旋转速度:
        
        生命值:
        车体装甲:
        炮塔装甲:
        悬挂装置维修时间:
        
        观察范围:
        通信距离:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    3. 代码实现

      根据上篇博客爬取到的坦克数据,构造知识图谱:

    # -*- coding: utf-8 -*-
    # Author  : xiayouran
    # Email   : youran.xia@foxmail.com
    # Datetime: 2023/10/1 20:29
    # Filename: build_kg.py
    import os
    import json
    from py2neo import Graph, Node, Relationship, NodeMatcher
    
    
    class WOTKG(object):
        def __init__(self, clean_kg=True):
            self.clean_kg = clean_kg
            self.entity_tank = []
            self.entity_price = []
            self.entity_firepower = []
            self.entity_mobility = []
            self.entity_survivability = []
            self.entity_spotting = []
            self.all_entity = []
            self.data_path = '../data/tank_list_detail.json'
    
            self.graph = Graph('neo4j://172.20.203.172:7687', auth=('neo4j', 'lyp123456'))  # use your ip 172.20.197.99
            self.matcher = NodeMatcher(self.graph)
            if self.clean_kg:
                self.graph.delete_all()
    
        def build_KG(self):
            self.collect_entity()
            self.create_all_node()
            self.create_relation()
    
        def check_zero(self, v_str):
            if not v_str:
                return True
            elif len(v_str) == 2 and v_str[0] == '0' and v_str[1] in ['秒', '米', '%', '度']:
                return True
            else:
                return False
    
        def add_entity(self, tank_name, entity_name, v_item: dict):
            for k_, v_ in v_item.items():
                if self.check_zero(v_):
                    continue
                if entity_name == 'Price':
                    self.entity_price.append(('Price', k_, v_))
                elif entity_name == 'Firepower':
                    self.entity_firepower.append(('Firepower', k_, v_))
                elif entity_name == 'Mobility':
                    self.entity_mobility.append(('Mobility', k_, v_))
                elif entity_name == 'Survivability':
                    self.entity_survivability.append(('Survivability', k_, v_))
                elif entity_name == 'Spotting':
                    self.entity_spotting.append(('Spotting', k_, v_))
                self.all_entity.append((tank_name, entity_name, k_, v_))
    
        def collect_entity(self):
            with open(self.data_path, 'r', encoding='utf-8') as f:
                data_json = json.load(f)
            for tank_item in data_json.values():
                tank_name = tank_item['tank_name']
                for k, v in tank_item.items():
                    if k[0] == 't' or not v:
                        continue
                    if k == '价格':
                        if isinstance(v, str):
                            self.entity_price.append(('Price', '金币', v))
                            self.all_entity.append((tank_name, 'Price', '金币', v))
                        else:
                            self.add_entity(tank_name, 'Price', v)
                    elif k == '火力':
                        self.add_entity(tank_name, 'Firepower', v)
                    elif k == '机动性':
                        self.add_entity(tank_name, 'Mobility', v)
                    elif k == '防护':
                        self.add_entity(tank_name, 'Survivability', v)
                    elif k == '侦察':
                        self.add_entity(tank_name, 'Spotting', v)
                    else:
                        self.entity_tank.append((tank_name, k, v))
                        self.all_entity.append((tank_name, 'Tank', k, v))
    
        def create_node(self, entity_list, entity_name='Tank'):
            head_nodes = []
            tail_nodes = []
    
            for (head, rela, tail) in entity_list:
                if head not in head_nodes and head not in ['Price', 'Firepower', 'Mobility', 'Survivability', 'Spotting']:
                    head_nodes.append(head)
                    node = Node(entity_name, name=head)
                    self.graph.create(node)
                if tail not in tail_nodes:
                    tail_nodes.append(tail)
                    node = Node("{}Value".format(entity_name), name=tail)
                    self.graph.create(node)
    
        def create_all_node(self):
            self.create_node(self.entity_tank, entity_name='Tank')
            self.create_node(self.entity_price, entity_name='Price')
            self.create_node(self.entity_firepower, entity_name='Firepower')
            self.create_node(self.entity_mobility, entity_name='Mobility')
            self.create_node(self.entity_survivability, entity_name='Survivability')
            self.create_node(self.entity_spotting, entity_name='Spotting')
    
        def create_relation(self):
            for (head, flag_str, rela, tail) in self.all_entity:
                node_head = self.matcher.match('Tank').where(name=head).first()
                node_tail = self.matcher.match('{}Value'.format(flag_str)).where(name=tail).first()
                rela_node = Relationship(node_head, rela, node_tail)
                self.graph.create(rela_node)
    
    
    if __name__ == '__main__':
        wot_kg = WOTKG(clean_kg=True)
        wot_kg.build_KG()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

      构造后的知识图谱可视化效果如下:
      单辆坦克:

    在这里插入图片描述
      知识图谱局部:

    在这里插入图片描述

    结束语

      本篇的代码已经同步到仓库中,感兴趣的话可以拉取一下,下一篇文章就基于这个知识图谱来构造一个关于坦克百科的智能问答机器人。

    开源代码仓库


      如果喜欢的话记得给我的GitHub仓库WOT点个Star哦!ヾ(≧∇≦*)ヾ


      公众号已开通:夏小悠,关注以获取更多关于Python文章、AI领域最新技术、LLM大模型相关论文及内部PPT等资料^_^

  • 相关阅读:
    锅炉智能制造工厂工业物联数字孪生平台,推进制造业数字化转型
    抖音快速涨粉的方法,快速涨粉软件的实操分享与心得分享
    MySQL主从复制与读写分离
    Excel VBA高级编程-微信群发(支持发送文件)
    去除网页滚动条方法以及内外边距
    Python 调硬件参数速度加快
    java代码审计-SSRF
    lammps教程:CNA晶体结构分析命令
    内核内存管理
    查询优化_单表使用索引及常见索引失效
  • 原文地址:https://blog.csdn.net/qq_42730750/article/details/134023753