# 商务智能项目文档
## 项目架构分析
本项目是一个知识图谱展示网站。
- 前端使用vue+D3框架实现前端基本逻辑、样式设定以及数据可视化;
- 后端采用springboot框架,实现分发逻辑、图算法等功能;
- 数据库方面使用Neo4j存储基本节点及关系数据;使用MongoDB作为检索结果的缓存;使用MySQL存储所有节点名称和其对于的ID、标签。
![项目架构](assets/项目架构.png)
### 类图
![](assets/类图.png)
### 前端
#### 介绍
在我们的项目中主要使用D3组件来对数据进行展示。D3是一款强大的用于数据可视化的JavaScript库,能够展示多种类型的数据,同时对数据进行操控。
![image-20190617011655024](assets/image-20190617011655024.png)
#### 导入
我们使用d3-network来展示网络状的图数据。
```
<d3-network :net-nodes="nodes" :net-links="links" :options="options" />
```
```
import D3Network from 'vue-d3-network'
components: {
D3Network
}
```
```
<style src="vue-d3-network/dist/vue-d3-network.css"></style>
```
#### 事件
- **node-click**: 单击爱节点时触发事件——**(event,node-object)**
- **link-click**:单击链接时触发 ——**(event, link-object)**
#### 节点对象
- **id**:节点ID。*如果没有提供使用数组索引*
- **name**:节点名称。*如果未提供使用:'node [node_id]'*
- **_color**:节点颜色,例如*红色*,*#aa00bb*,
- **_cssClass**:node css类名
- **_labelClass**:节点标签css类名
- **svgSym**:节点图标,svg文档(仅适用于svg渲染器)
- **_size**:节点大小*(仅限svg渲染器)*
- **_width**:节点宽度*(仅限svg渲染器)*
- **_height**:节点高度*(仅限svg渲染器)*
- **_svgAttrs**:Object,svg节点属性
由于项目节点属性与该component节点对象属性不太相符,所以需要修改component,
buildNode函数中将项目节点属性提取并填入节点对象属性。
#### 链接对象
- **id**:链接ID。*如果没有提供使用数组索引*
- **name**:节点名称。*如果未提供使用:'link [link_id]'*
- **tid**:目标节点的id
- **sid**:源节点的id
- **_color**:链接颜色,例如*红色*,*#aa00bb*,
- **_svgAttrs**:Object,svg行属性
同节点对象一样,由于项目链接属性与该component链接对象属性不太相符,所以修改component中buildLink函数,将项目节点属性提取并填入节点对象属性。
#### props
该component为我们提供了丰富的属性,以自定义我们的需求:
**net-nodes**: 节点对象的数组
**net-links**: [链接对象的](https://github.com/emiliorizzo/vue-d3-network#link-object)数组
**selection** : **选择**对象,链接和节点
- **links**: 将node.ids作为键,将节点对象作为值的对象
- **nodes**: 将link.ids作为键的对象,将对象链接为值
**nodeSym**: String,可设置svg doc 为node绘制图标
**nodeCb**: Function(node) -> node, 节点格式化
**linkCb**: Function(link) -> link, 链接格式化
**options**:
- **canvas**:Boolean,*render as canvas*,false = svg
- **size**:对象,*图形大小*。**默认值:**容器大小
- **w**:数字
- **h**:数字
- **offset**:对象,*图形中心偏移量*
- **x**:数字
- **y**:数字
- **force**:数量
- **force**对象:
- **中心**:*布尔值*,使用d3.forceCenter
- **X**:*强度*,使用d3.forceX
- **Y**:*力量*,使用d3.forceY
- **ManyBody**:*Boolean*,使用d3.forceManyBody,*取'force'选项的负值*
- **链接**:*布尔值*,使用d3.forceLink
- **nodeSize**: Number, node radius | 以px为单位
- **linkWidth**: Number, 链接厚度以px为单位
- **nodeLabels**: Boolean, 显示节点名称
- **linkLabels**: Boolean, 显示链接名称
- **fontSize**: Number,节点标签大小 px
- **strLinks**: Boolean, 是否将链接绘制成矩形线
## 各数据库介绍
### Neo4j
Neo4j是一种面向/基于图的数据库,以`图`的形式存储数据,而这种数据格式的结构特殊性使得其在复杂繁琐的关系处理上很高效。
本项目使用其存储路透社提供的公开金融数据集,其中包含各类金融相关实体以及多实体之间的关系。我们使用Neo4j为本项目构建了知识图谱模型,并在此基础上提供一些检索服务。
#### 配置
机器内存16G,Neo4j分配如下:
```bash
dbms.memory.heap.initial_size=1G
dbms.memory.heap.max_size=4G
dbms.memory.pagecache.size=4G
```
#### 数据量
图数据库中共存有27.34GB图数据,其中:
- 节点数:21993143
- 关系数:61066697
### MongoDB
因项目中MongoDB和MySQL存储量较少,因此都选择使用了配置较低的服务器。
使用MongoDB的目的是为了缓存检索结果,提高Query Server的响应速度。我们将特定检索关键词的字符串连接结果作为key,并创建一个包含检索时间和检索结果的value,以此构建key-value对存储MongoDB中。在下一次query动作产生时,会先检索MongoDB中是否包含该历史记录,若包含则修改该记录的time字段,并将其返回,若不包含则创建一个key-value对存入MongoDB中。
存储结构如下:
| Collections(集合名称) | 说明 |
| --------------------- | -------------------------------- |
| Single | 查询单节点周围的关系及节点的结果 |
| Double | 查询两节点间存在的多跳关系的结果 |
| MinPath | 查询两节点间的最短路径 |
每个集合的存储文档格式都相同:
| DocumentKey | 说明 |
| ----------- | ----------------------- |
| id | 根据检索参数构建的key值 |
| time | 检索的时间 |
| result | 检索结果(json类型数据) |
由于我们项目中图结构很大,对Neo4j的一次节点、关系检索通常是比较耗时的,而MongoDB的以key取值的操作确实很快的,因此使用MongoDB大大降低了用户的检索等待时间。
#### 数据量
MongoDB中主要用于存储用户检索的历史记录,数据的增加由用户的检索动作触发,当MongoDB中的数据量达到了预先设定的阈值(2G),会清理一次数据,即删除一半的记录。
### MySQL服务器配置
与MongoDB类似,MySQL的目的也是提高Query Server的响应速度。
在用户界面中,我们为其提供了一个搜索节点的功能,即根据实体的名称来搜索并返回相似的实体集合,并由用户选择一个(或两个,由选择的检索功能而定)特定的实体从而根据其返回对应的实体/关系结果集。
虽然Neo4j在处理关系上很高效,但是在独立实体上的查询就会很慢,因此我们使用关系型数据库MySQL存储所有节点的名称、ID、类型标签及其uri链接。
唯一一张表NeoCache的表结构:
| 字段名称 | 说明 | 备注 |
| -------- | ------------ | ------------------------------------------ |
| id | 节点id | 主键 |
| label | 节点所属类型 | 索引`labelIndex`、符合索引`labelNameIndex` |
| name | 节点名称 | 索引`nameIndex`、符合索引`labelNameIndex` |
| uri | 节点的链接 | 可直接跳转到官网介绍页面 |
## ETL
### 数据导入
在做数据清理的时候,我们有两种方案:
1. 原来使用数据清理 导出成csv
优点:清理完数据比较小,可以通过neo4j import直接导入
缺点:在清洗数据的过程中,会有一定的数据缺失
2. 使用neosemantics直接导入
优点:数据比较完整
缺点:数据较大,比较难导入
我们对于源数据进行了一定的分析,发现源数据采用rdf数据框架,其中URI作为语