知识图谱项目——红色文化之张学良人物知识图谱(Neo4j+vue+flask+mysql实现)

张学良人物简史知识图谱_说明文档

本项目为人工智能专业大三知识图谱课程期末作业。意在完成一个以张学良为背景的红色文化类知识图谱。文末放上本项目的代码地址。

文章目录

  • 张学良人物简史知识图谱_说明文档
      • :rocket:前端
      • :rocket:后端
      • :rocket:中间件
      • :rocket:数据库
      • :rocket:服务器
    • :book:1、数据采集
    • :rabbit2:2、数据预处理
    • :rabbit:3、Neo4j数据库导入
    • :racehorse:4、前端展示
    • :dog:5、项目总体展示
    • :page_facing_up:6、论文知识抽取

🚀前端

  • Vue.js
  • d3.js
  • jQuery
  • html/css/js

🚀后端

  • Flask

🚀中间件

🅰️axios

🅱️neo4j-driver

🚀数据库

  • MySQL
  • Neo4j

🚀服务器

  • 腾讯云轻量应用服务器

📖1、数据采集

互联网上搜集数据,本项目基于百度百科的数据,进行搜集并绘制初始的知识图谱,并搜集到了十种关系类别。并建立 second.csv

idname
1property
2relatives
3biography
4ally
5politicalViewPoint
6Subordinate
7Superior
8Enemy
9Everywhere he goes
10Someone who knew him

由于采集了100条真实数据,为了测试数据量大的情况。使用Faker库来进行张学良去过的地方以及认识张学良的人数据

from faker import Faker
import pandas as pd

fake = Faker(['zh_CN', 'en_US'])

# 生成第一列数据
country1_cities = {fake.city_name() + '市' for i in range(2000)}
column1 = list(country1_cities) + [fake.state()]*2000
print(len(column1))

# 生成第二列数据
names = {fake.name() for j in range(4000)}
column2 = list(names)
print(len(column2))

# 计算每列数据的长度
len1 = len(column1)
len2 = len(column2)

# 如果列的长度不一致,则新建一个DataFrame来保证列的长度一致
if len1 != len2:
    max_len = max(len1, len2)
    dummy_df = pd.DataFrame()
    if len1 < max_len:
        dummy_df['国家或地区'] = ['']*(max_len - len1)
        column1.extend(dummy_df['国家或地区'].tolist())
    elif len2 < max_len:
        dummy_df['人名'] = ['']*(max_len - len2)
        column2.extend(dummy_df['人名'].tolist())

# 将数据转化为DataFrame
df = pd.concat([pd.DataFrame(column1, columns=['国家或地区']), pd.DataFrame(column2, columns=['人名'])], axis=1)

# 保存到csv文件中
df.to_csv('地名与人名不重复.csv', index=False)

使用实体识别技术将网络文本中的实体抽取

import jieba.posseg as pseg
import textract
import csv
file_path = '数据.docx'
text = textract.process(file_path).decode('utf-8')
with open('实体数据结果.csv', 'w', newline='', encoding='utf-8') as csvfile:
    writer = csv.writer(csvfile)
    shiti = pseg.cut(text)
    # 找出所有组成的 'nt'(机构团体)和 'nz'(其他专有名词)类型的词汇
    for word, flag in shiti:
        if flag in ['nt', 'nz']:
            writer.writerow([word, flag])

🐇2、数据预处理

将所有类别采集到的数据放入 third.csv

idnamedescribe
49联俄、联共、扶助农工,“三大政策”张学良提出的“三大政策”,即联俄、联共、扶助农工,是其治理东北时所推行的主要政策,也是他对于中国革命和现代化建设问题的一种思考。
50中华民族统一和国家现代化张学良认为,实现中华民族统一和国家现代化是中国现代化建设事业的最终目标。他反对分裂主义和帝国主义侵略,主张通过改革和现代化建设提升中国国家实力和综合竞争力。
51民主、法制和教育改革张学良提倡以民主、法制和教育改革为核心的中国现代化进程,认为这是推进社会进步和国家发展的重要保障。他主张发扬民主,建设法治,推进教育改革,促进中国社会的和谐发展。
52统一战线和减轻民众负担张学良主张建立广泛统一战线,积极团结各界人士,推进以减轻民众负担为核心的经济和社会改革。他认为,这是实现中华民族伟大复兴和国家现代化的必经之路。
53杨虎城曾任东北军第一军军长,是张学良手下最得力的将领之一。
54万福麟曾任东北军第二十七师师长,是张学良的心腹之一,后因支持抗日战争而遭到逮捕。
55刘骥曾任东北军副总司令、沈阳市等职,被认为是张学良的得力助手之一。
56谭道源曾任东北军第十三路军军长,是张学良的部属之一。
57傅作义曾任东北军第三军军长、华北政务委员会等职,与张学良关系密切,在1935年“九一八事变”后加入了中国党。
58马步芳曾任东北军第八师师长、奉天等职,是张学良手下的一位著名将领。
59张作霖是张学良的父亲,也是东北军的创始人之一。张学良在东北军的初期时期曾担任他的副手,后继任东北军总司令。
60孙传芳曾是张学良的上级长官,掌管了奉天和陆军第三师等职。
61马步芳曾是张学良的上级长官,任命他为东北军第八师师长。
62蒋介石是中国的创始人和领袖,曾与张学良有过密切合作关系。在国共合作时期,两人曾携手抵抗日本侵略,但在中国内战中,两人成为敌对方。
63汪精卫是中国国内党人以外最早提出“联共”口号的家之一。

建立关系表

third_idsecond_idrole
11sex
21alias
31nationality
41nation
51birthdate

🐰3、Neo4j数据库导入

建约束条件

在导入数据之前,需要先创建节点类型的约束条件,以确保不会出现重复的节点。

Neo4j 1.5版本

CREATE CONSTRAINT FOR (s:second) REQUIRE s.id IS UNIQUE;
CREATE CONSTRAINT FOR (t:third ) REQUIRE t.id IS UNIQUE;

Neo4j 1.4版本

CREATE CONSTRAINT ON (s:second) ASSERT s.id IS UNIQUE;
CREATE CONSTRAINT ON (t:third ) ASSERT t.id IS UNIQUE;

在准备好数据文件和创建约束条件之后,可以使用Cypher导入语句进行数据导入。

#Third.csv

LOAD CSV WITH HEADERS FROM 'file:///second.csv' AS line
CREATE (s:second{id: toInteger(line.id), name: line.name, year: toInteger(line.year)});
LOAD CSV WITH HEADERS FROM "file:///third.csv" AS line
CREATE (t:third {id: toInteger(line.id), name: line.name, gender: line.gender});
LOAD CSV WITH HEADERS FROM "file:///third_role.csv" AS line
MATCH (s:second{id: toInteger(line.second_id)})
MATCH (t:third {id: toInteger(line.third_id)})
CREATE (s)-[:role {name: line.role}]->(t);

创建节点

//创建节点
create (n:person{name:"张学良"})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIWpOjHs-1687009471889)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617211726846.png)]

建立节点之间的关系

//建立节点之间的关系
match(n:person),(s:second) where n.name="张学良" and s.name="property" create(n)-[r:属性]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="biography" create(n)-[r:传记]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="relatives" create(n)-[r:亲属]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="politicalViewPoint" create(n)-[r:政治观点]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="ally" create(n)-[r:盟友]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="Subordinate" create(n)-[r:下属]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="Superior" create(n)-[r:上司]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="Enemy" create(n)-[r:敌人]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="Everywhere he goes" create(n)-[r:去过的地方]- >(s);

match(n:person),(s:second) where n.name="张学良" and s.name="Someone who knew him" create(n)-[r:认识他的人]- >(s);

敌人

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YpKcDJXu-1687009471893)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617211805402.png)]

上司

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQNI6zTw-1687009471894)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617211840837.png)]

认识他的人(显示达到上限)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qiI8RcGQ-1687009471895)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617211956800.png)]

🐎4、前端展示

由于neo4j数据库中最多只能显示300个节点,我就是想看所有节点,想炫酷地一起展示几千个节点。

所以使用d3、neo4j-driver进行数据库连接、读取和前端展示

<!--APP.vue-->
<template>
<div id="graph-container"></div>
</template>

<script>
import neo4j from "neo4j-driver";
import * as d3 from 'd3';
import * as d3Force from 'd3-force';

let driver = neo4j.driver(
  "bolt://localhost:7687",
  neo4j.auth.basic("neo4j", "1234")
);

export default {
  name: "app",
  data() {
    return {
      graphData: [],
      nodes: [],
      relationships: [],
    };
  },
  props: {},
  created() {
    this.fetchData();
  },
  methods: {
    setupNeo4j() {
      this.driver = neo4j.driver(
        'bolt://localhost:7687',
        neo4j.auth.basic('neo4j', '1234'),
        { encrypted: false }
      );
      this.session = this.driver.session();
    },
    async getData() {
      const result = await this.session.run(
        `
        MATCH (n)-[r]->(p)
        RETURN n, r, p
        `
      );

      const nodes = [];
      const edges = [];

      result.records.forEach(record => {
        nodes.push({
          id: record.get('n').identity.toNumber(),
          name: record.get('n').properties.name,
          label: record.get('n').labels[0],
        });

        nodes.push({
          id: record.get('p').identity.toNumber(),
          name: record.get('p').properties.name,
          label: record.get('p').labels[0],
        });

        edges.push({
          source: record.get('n').identity.toNumber(),
          target: record.get('p').identity.toNumber(),
          type: record.get('r').type,
          properties: record.get('r').properties,
        });
      });

      return { nodes, edges };
    },
    async drawGraph() {
      const data = await this.getData();

      const svg = d3.select('#graph-container').append('svg');

      const width = window.innerWidth;
      const height = window.innerHeight;

      svg.attr('width', width).attr('height', height);

      const simulation = d3Force
        .forceSimulation()
        .force(
          'link',
          d3Force
            .forceLink()
            .id(d => d.id)
            .distance(100)
        )
        .force(
          'charge',
          d3Force.forceManyBody().strength(-500).distanceMax(500)
        )
        .force('center', d3Force.forceCenter(width / 2, height / 2));

      const link = svg
        .selectAll('line')
        .data(data.edges)
        .enter()
        .append('line')
        .attr('stroke', '#999')
        .attr('stroke-opacity', 0.6)
        .attr('stroke-width', d => Math.sqrt(d.properties.weight));

      const node = svg
        .selectAll('circle')
        .data(data.nodes)
        .enter()
        .append('circle')
        .attr('r', 10)
        .attr('fill', '#69b3a2')
        .call(
          d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended)
        );

      node.append('title').text(d => d.name);

      simulation.nodes(data.nodes).on('tick', ticked);
      simulation.force('link').links(data.edges);

      function ticked() {
        link
          .attr('x1', d => d.source.x)
          .attr('y1', d => d.source.y)
          .attr('x2', d => d.target.x)
          .attr('y2', d => d.target.y);

        node.attr('cx', d => d.x).attr('cy', d => d.y);
      }

      function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }

      function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    }
  },
  mounted() {
    this.setupNeo4j();
    this.drawGraph();
  },
};
</script>

<style scoped>
ul {
  list-style: none;
  padding: 0;
}
</style>

结果如图:和neo4j拥有一样的浮动效果,就是没有实现拖拽哈哈。

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n34VyRDZ-1687009471898)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617212827643.png)]

🐶5、项目总体展示

使用Flask框架连接mysql数据库实现了节点的动态存储

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ek4VePtb-1687009471898)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617213324015.png)]

由于需要操作数据库,所以实现了登录注册功能,来对能操作建立节点的用户设置权限。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkgOH9AW-1687009471899)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617213442350.png)]

使用简单的get请求来传到url上,仅供学习。

点击建立节点页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fCoBriXh-1687009471899)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617213619129.png)]

我们可以输入主节点的名称、主节点的关系和指向节点的名称,注意节点名在数据库中只能存在一个。

此外还可以新增节点来建立多个节点之间的关系。比如我们要将右侧的案例复现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A8zlPyYE-1687009471899)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617213917726.png)]

提交后结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywX9cxRo-1687009471900)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230617213943061.png)]

Flask后端实现代码如下:

from kgview import kg_view
import json
from flask import Flask, render_template, request
# 导入pymysql模块
import pymysql

# 连接database
conn = pymysql.connect(host="localhost", user="root", password="1234", port=3306, database="test", charset="utf8",
                       autocommit=True)
# 得到一个可以执行SQL语句的光标对象
cursor = conn.cursor()
class saveData():
    idData = None
data = saveData()
app = Flask(__name__)


# 装饰器  给函数新增功能
@app.route('/')  # 路由
def index():
    return render_template('Z.html')


@app.route('/s')
def search():
    keyword = request.args.get('search')
    kg_view(keyword)
    links = kg_view(keyword)
    for i in range(len(links)):
        links[i] = links[i].replace("source", '"source"').replace("target", '"target"').replace("type",
                                                                                                '"type"').replace("'",
                                                                                                                  '"')
        links[i] = json.loads(links[i])
    return render_template('index.html', result_json=links)


@app.errorhandler(404)
# 当发生404错误时,会被该路由匹配
def handle_404_error(err_msg):
    """自定义的异常处理函数"""
    # 这个函数的返回值就是前端用户看到的最终结果 (404错误页面)
    return u"出现了404错误, 错误信息:%s" % err_msg


@app.route('/dl')
def dl():
    return render_template('dl.html')


@app.route('/dltj')
def dltj():
    """登录"""
    pwd = request.args.get('password')
    id = request.args.get('username')
    data.idData = id
    try:
        sql = """
        SELECT pwd FROM users WHERE pwd=%s;
        """
        # 执行SQL语句
        # 判断是否查询到结果1为有0为无
        judge = cursor.execute(sql, id)
        conn.commit()
        desc = cursor.description
        data_dict = [dict(zip([col[0] for col in desc], row)) for row in cursor.fetchall()]  # 列表表达式把数据组装起来
        print(data_dict)
        # 真实密码
        zm = data_dict[0].get('pwd')
        print(zm)
        if judge == 0:
            return "没有这个用户!"
        else:
            if zm == pwd:
                return render_template('Z.html')
            else:
                return "密码错误"
    except:
        return "用户不存在"
    return render_template('Z.html')


@app.route('/zc')
def zc():
    return render_template('zc.html')


@app.route('/zctj')
def zctj():
    """注册"""
    zcpwd = request.args.get('zcpassword')
    zcid = request.args.get('zcid')
    try:
        sql = """
        INSERT INTO users (id,pwd) VALUES (%s,%s);
        """
        # 执行SQL语句
        cursor.execute(sql, [zcid, zcpwd])
        conn.commit()
    except:
        return "用户名重复"
    # 关闭光标对象
    # cursor.close()
    return render_template('dl.html')


@app.route('/myNode')
def returnMyNode():
    id = data.idData
    """取出我的节点"""
    try:
        sql = """
        SELECT nodeData FROM users WHERE id=%s;
        """
        # 执行SQL语句
        # 判断是否查询到结果1为有0为无
        cursor.execute(sql, id)
        conn.commit()
        desc = cursor.description
        data_dict = [dict(zip([col[0] for col in desc], row)) for row in cursor.fetchall()]  # 列表表达式把数据组装起来
        # 节点数据
        nd = data_dict[0].get('nodeData')
    except:
        return "您还尚未登录"
    links = nd
    return render_template('index.html', result_json=links)


@app.route('/createNode')
def createMyNode():
    return render_template('createNode.html')



@app.route('/add')
def addnode():
    print(data.idData)
    id = data.idData
    i = request.args.get('nodeNum')
    i = int(i)
    insideDict={}
    links = []
    links1 = []
    for j in range(1, i + 1):
        node = request.args.get('mainnode' + str(j))  # 节点
        target = request.args.get('point' + str(j))  # 指向
        rela = request.args.get('rela' + str(j))  # 关系
        insideDict = {'source': node,'target': target,'type':'resolved',  'rela': rela,}
        links.append(insideDict)
        links1.append(node)
        links1.append(target)
        links1.append(rela)
    link = str(links)
    """节点存入数据库"""
    print(insideDict.values())
    sql = """
    insert into node (node,relation,target,id) values (%s,%s,%s,%s)
    """

    cursor.execute(sql, [links1[0],links1[1],links1[2],id])
    conn.commit()
    return render_template('index.html',result_json=links)


if __name__ == '__main__':
    # debug调试模式=true自动重启
    app.run(debug=True)

📄6、论文知识抽取

我们根据已有的内容总结出了论文——docx文档

随后,对论文进行了知识抽取功能

  • 1、读取文档内容
  • 2、去停用词、分词
  • 3、实体识别
  • 4、词性标注
  • 5、依存句法分析
  • 6、词频统计
  • 7、词云展示
  • 8、关系抽取
import jieba
from collections import Counter
from wordcloud import WordCloud
import textract
import pytesseract
from PIL import Image
import numpy as np
import cv2
import csv
import textract
import jieba.posseg as pseg
import nltk
from nltk.parse import stanford
from nltk.corpus import stopwords
from stanfordcorenlp import StanfordCoreNLP
import spacy
nlp = spacy.load('en_core_web_sm')


# 读取文档内容
file_path = '知识图谱论文.docx'
text = textract.process(file_path).decode('utf-8')


# 去停用词、分词
baidu_stopwords = [line.strip() for line in open('baidu_stopwords.txt', 'r', encoding='utf-8').readlines()]
words = [word for word in jieba.cut(text) if word not in baidu_stopwords and len(word) > 1]
print(words)


# 实体识别
shiti = pseg.cut(text)
# 找出所有组成的 'nt'(机构团体)和 'nz'(其他专有名词)类型的词汇
for word, flag in shiti:
    if flag in ['nt', 'nz']:
        print(word, flag)



# 词性标注
# 对每个列表元素进行词性标注
for word, flag in pseg.cut(" ".join(words)):
    print(word, flag)
with open("词性标注.txt", "w", encoding="utf-8") as f:
    for word, flag in pseg.cut(" ".join(words)):
        f.write(word + " " + flag + "\n")


# 查看句子的依存关系
doc = nlp(' '.join(words))

for token in doc:
    print(token.text, token.dep_, token.head.text, token.head.pos_,
            [child for child in token.children])
# 其中,token.dep_表示词性依存关系,例如nsubj表示主语,amod表示形容词修饰语,dobj表示直接宾语等等;token.head表示当前单词的父节点;token.children表示当前单词的子节点。
with open("依存关系.txt", "w") as f:
    for token in doc:
        f.write(f"{token.text}\t{token.dep_}\t{token.head.text}\t{token.head.pos_}\t"
                f"{[child for child in token.children]}\n")



# 词频统计
word_count = Counter(words)

# 词云展示
wordcloud = WordCloud(font_path='simkai.ttf', background_color='white', width=1000,
                      height=800).generate_from_frequencies(word_count)
wordcloud.to_file('wordcloud.png')

# 关系抽取
img = cv2.imread('wordcloud.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    if w > 30 and h > 30:
        crop_img = img[y:y + h, x:x + w]
        cv2.imwrite('crop_img.png', crop_img)
        break

img = Image.open('crop_img.png')

print('去停用词、分词后的结果为:', words)
print('词频统计的结果为:', word_count)

词性标注结果:
在这里插入图片描述

依存关系:
在这里插入图片描述

词云:
在这里插入图片描述
这就是本项目的全部分享了,代码已开源,地址见评论或私信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/32277.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux常用命令——free命令

在线Linux命令查询工具 free 显示内存的使用情况 补充说明 free命令可以显示当前系统未使用的和已使用的内存数目&#xff0c;还可以显示被内核使用的内存缓冲区。 语法 free(选项)选项 -b # 以Byte为单位显示内存使用情况&#xff1b; -k # 以KB为单位显示内存使用情况…

【云原生】二进制部署k8s集群(中)搭建node节点

连接上文 在上文已经成功部署了etcd分布式数据库、master01节点&#xff0c; 本文将承接上文的内容&#xff0c;继续部署Kubernetes集群中的 worker node 节点和 CNI 网络插件 1. 部署 Worker Node 组件 1.1 work node 组件部署前需了解的节点注册机制 kubelet 采用 TLS Bo…

设计模式-05.01-行为型-观察者模板

观察者模式【常用】 我们常把 23 种经典的设计模式分为三类&#xff1a;创建型、结构型、行为型。前面我们已经学习了创建型和结构型&#xff0c;从今天起&#xff0c;我们开始学习行为型设计模式。我们知道&#xff0c;创建型设计模式主要解决“对象的创建”问题&#xff0c;…

JavaWeb之tomcarHTTP

1 DOM4j Xml解析 1.1 JAXP  JDK内置&#xff0c;不需要导入第三方jar包&#xff0c;简单工具优先选择。  支持两种解析方式&#xff1a;DOM、SAX 1.1.1 JAXP—DOM 加载xml 生成一个DOM树。获得整个文档的描述对象Document 解析 api 获得工厂 DocumentBuilderFactory –》 …

Android adb shell命令捕获systemtrace

Android adb shell命令捕获systemtrace (1)抓取trace文件&#xff1a; adb shell perfetto -o /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory -t 时长&#xff0c;20s&a…

通过使用Mybatis插件来实现数据的分页功能

目录 背景一、SpringBoot的后端1、手动拼接SQL来实现2、使用Mybatis插件来实现 二、Vue-cli的前端:请求响应跟踪 三、在使用Mybatis插件进行多表查询(表数大于2)出现的问题1. SQL解决2.后端查询方式改变成嵌套查询 四、 分页总结 背景 分页: 如果一次性的查询全部数据, 响应时…

高级数据结构——平衡二叉树(AVL树)

目录 1. 底层结构 2. AVL数的概念 3. AVL树节点的定义 4. 基本框架 5. AVL树的插入 6. AVL树的旋转 6.1 左单旋 6.2 右单旋 6.3 左右双旋 6.4 右左双旋 7. AVL树的验证 8. AVL树的查找 9. AVL树的删除 10. AVL树的性能 11. 总代码 11.1 AVLTree 11.2 Test.c…

SuperMap GIS基础产品移动GIS FAQ集锦(3)

SuperMap GIS基础产品移动GIS FAQ集锦&#xff08;3&#xff09; 【iMobile】网络分析中设置权值字段&#xff0c;如何添加多个权值字段&#xff1f; 【解决办法】通过权值字段集合类&#xff08;WeightFieldInfos&#xff09;设置&#xff0c;该类是权值字段信息对象&#x…

【AI】Stable-Diffusion-WebUI使用指南

注&#xff1a;csdn对图片有审核&#xff0c;审核还很奇葩&#xff0c;线稿都能违规&#xff0c;为保证完整的阅读体验建议移步至个人博客阅读 最近AI绘画实现了真人照片级绘画水准&#xff0c;导致AI绘画大火&#xff0c;公司也让我研究研究&#xff0c;借此机会正好了解一下…

django旅游推荐系统-计算机毕设 附源码82884

django旅游推荐系统 摘 要 随着社会的快速发展和人们生活水平的不断提高&#xff0c;旅游已逐渐成为人们生活的重要组成部分&#xff0c;用户能够获取旅游信息的渠道也随信息技术的广泛应用而增加。大量未经过滤的信息在展示给用户的同时&#xff0c;也淹没了用户真正感兴趣的信…

配置NIS服务器及客户端

在服务端安装所需软件包 设置主机名和NIS域名 编辑 NIS服务器主配置文件 最下面编辑访问控制 建立测试用户 配置NFS&#xff0c;否则客户端切换用户时&#xff0c;用户没有家目录 安装NFS所需软件包 Nfs-utils 给两个共享目录权限&#xff0c;编辑NFS配制文件 共享两个目录 重…

【从零开始学习C++ | 第二十一篇】C++新增特性 (上)

目录 前言&#xff1a; 委托构造函数&#xff1a; 类内初始化&#xff1a; 空指针&#xff1a; 枚举类&#xff1a; 总结&#xff1a; 前言&#xff1a; C的学习难度大&#xff0c;内容繁多。因此我们要及时掌握C的各种特性&#xff0c;因此我们更新本篇文章&#xff0c;向…

【数据管理架构】什么是 OLTP?

OLTP&#xff08;在线事务处理&#xff09;支持在 ATM 和在线银行、收银机和电子商务以及我们每天与之交互的许多其他服务背后进行快速、准确的数据处理。 什么是 OLTP&#xff1f; OLTP 或在线事务处理允许大量人员&#xff08;通常通过 Internet&#xff09;实时执行大量数据…

【SpringCloud-5】gateway网关

网关是干啥用的就不用再说了。 sringcloud中的网关&#xff0c;第一代是zuul&#xff0c;但是性能比较差&#xff08;1.x是阻塞式的&#xff0c;2.x是基于Netty的&#xff09;&#xff0c;然后有了第二代GateWay&#xff0c;基于Reactor模型 异步非阻塞。 springcloud网关就是一…

C++智能指针

RAII RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种利用对象生命周期来控制程序资源的技术 不需要显示的释放资源对象的资源在其生命周期类保持有效 通常控制的资源&#xff1a;动态申请的内存、文件描述符、互斥量、网络连接等 在对象构造时…

多线程/std::thread线程退出方式详解

文章目录 概述不 join 也不 detach执行了detach并不能万事大吉建议使用 join 函数 概述 这里默认你已经了解 std::thread 类的基本使用&#xff0c;和WinAPI多线程编程中 “如何优雅的退出线程” 等相关知识。阅读该文前&#xff0c;建议先看看《多线程 /C 11 std::thread 类深…

python、pyqt5实现人脸检测、性别和年龄预测

摘要&#xff1a;这篇博文介绍基于opencv&#xff1a;DNN模块自带的残差网络的人脸、性别、年龄识别系统&#xff0c;系统程序由OpenCv, PyQt5的库实现。如图系统可通过摄像头获取实时画面并识别其中的人脸表情&#xff0c;也可以通过读取图片识别&#xff0c;本文提供完整的程…

【IIS建站教程】windows本地搭建web服务,内网穿透发布公网访问

✨个人主页&#xff1a;bit me&#x1f447; 目 录 &#x1f43e;1.前言&#x1f490;2.Windows网页设置&#x1f338;2.1 Windows IIS功能设置&#x1f337;2.2 IIS网页访问测试 &#x1f340;3. Cpolar内网穿透&#x1f339;3.1 下载安装Cpolar&#x1f33b;3.2 Cpolar云端设…

【Leetcode60天带刷】day36——56. 合并区间,738.单调递增的数字

​ 题目&#xff1a; 56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a;…

菜鸡shader:L4三色环境光原理妙用并在ue4中实现

三色环境光的拓展运用 我的上一篇博客写了关于三色环境光的原理&#xff0c;这次就来简单拓展一下。最重要的核心思想其实就是取法线向量的第二个分量&#xff0c;因为它控制方法是指向xz平面的上或者下。 所以这次要用这个原来来单独摘出上层环境光&#xff0c;乘上菲涅尔&a…