[toc]
简介
图数据库是NoSQL类数据库的一大典型代表,在国内图数据库属于新兴事物,其优异的复杂关系解决方案引起了国内众多大型互联网公司及IT开发者的关注,而Neo4j是目前图形化数据库中最为出色、最为成熟的产品。
应用场景
现实社会织起了一个庞大而复杂的关系网,比如天天有人给你打电话要你买房子,他们是通过什么技术来找到你的呢?就是通过一些关系运算。
如果使用传统的数据库会很难处理,而采用图数据库来处理它,会更高效、更方便。
在科技领域里有一个六度空间理论,简单地说,就是世界上任何两个人最多只需通过6个关系就一定能够找到对方。
用图数据库就可以把这个理论变成现实。它能支持海量、复杂、多变数据的关系运算,而且运算性能非常高。
和传统数据库比起来,图数据库的优势在哪儿呢?
- 效率更高
- 可扩展性更强
- 落地更方便
- 更直观、浅显、简单,更易理解
总之,图数据库能高效地处理各种复杂的关系网络,在许多领域有着广泛的应用。它是基于图论而实现的新型数据库系统,擅长处理大量的、复杂的、互联的、多变的网状数据,其效率远远高于传统的关系数据库。
特点
- 完整的ACID支持
- 高可用性
- 轻易扩展到上亿级别的节点和关系
- 通过遍历工具高速检索数据
基本概念
- 图数据库:图数据库的叫法多少有借鉴数学中的“图论”的思想,其实在软件开发领域更加通俗的可以称之为“网状数据库”,现实生活中的事务(实体)往往都不是独立存在,或多或少和其他事务(对象)有一定的关系和联系,就像朋友的朋友就是朋友。这种关系如果用图纸画出来,就是一个个实体连线其他的实体,中间的线可能是不同的关系。
- 实体:拥有一些相同特征的事务,某一类数据,某一个领域,某一个业务表示等等
- 关系:类比一下,就类似关系性数据库中的关系模式了,只不过在图数据库中更加强调个体与个体的关系模式
- 在neo4j中实体就是节点,节点可以有自己的属性,不同的节点通过关系关联起来
模块
Neo4j最初是一个图形数据库,现在已经发展成为一个拥有众多工具,应用程序和库的丰富生态系统。
- Neo4j Graph Database:核心模块,一个完整的数据库系统,可以存储、检索数据。有两个版本:社区版和企业版
- Neo4j Aura:封装成服务的云产品
- Neo4j Graph Data Science:提供数据分析和算法支持,可用于大数据分析
- Neo4j Tools:提供了一系列工具,旨在让开发人员更简单方便的学习、操作、开发、运维Neo4j生态的产品。这些工具包括:Neo4j Desktop,Neo4j Browser,Neo4j Operations Manager,Data Importer,Neo4j Bloom
- Cypher query language:数据库查询语言,类似于sql
安装
以centos下安装为例
下载
下载中心地址:https://neo4j.com/download-center/
建议下载 4.x 的版本,4.x需要jdk11,5.x需要jdk17
本文下载的是 Linux / Mac ExecutableNeo4j 4.4.23 (tar)
解压之后目录如下(/opt/neo4j-community-4.4.23):
- bin
- certificates
- conf
- data
- import
- labs
- lib
- licenses
- LICENSES.txt
- LICENSE.txt
- logs
- NOTICE.txt
- plugins
- README.txt
- run
- UPGRADE.txt
改配置
打开 conf/neo4j.conf,并修改dbms.default_listen_address为实际地址,默认的是localhost,外部机器无法访问。
dbms.default_listen_address=192.168.1.x
启动
- 启动:sh bin/neo4j start
- 重启:sh bin/neo4j restart
访问
- 默认访问端口:7474
- 默认账号密码是:neo4j
http://192.168.1.x:7474
改密码
初次登录会强制改密码,改完密码将进入主面板页面
Cypher query language基本使用
在谢谢你下载页面有一个 importData 的超链接,点开之后是开发者文档,此文档以关系型数据库数据导入neo4j为主题,深入浅出的介绍了关系型数据库和neo4j的相同和不同,neo4j的应用场景和优势,如何执行简单的 Cypher query language 。。。。。。
文档地址:https://neo4j.com/developer/guide-importing-data-and-etl/
Cypher Query Language 用法举例
//查询节点
MATCH (n) RETURN n LIMIT 100
// Create orders
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/orders.csv' AS row
MERGE (order:Order {orderID: row.OrderID})
ON CREATE SET order.shipName = row.ShipName;
//query order
MATCH (o:Order) return o LIMIT 5;
数据呈现视图:Graph ,Table , Text
// Create products
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/products.csv' AS row
MERGE (product:Product {productID: row.ProductID})
ON CREATE SET product.productName = row.ProductName, product.unitPrice = toFloat(row.UnitPrice);
//QUERY product
MATCH (p:Product) return p LIMIT 5;
// Create suppliers
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/suppliers.csv' AS row
MERGE (supplier:Supplier {supplierID: row.SupplierID})
ON CREATE SET supplier.companyName = row.CompanyName;
//query Supplier
MATCH (s:Supplier) return s LIMIT 5;
// Create employees
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/employees.csv' AS row
MERGE (e:Employee {employeeID:row.EmployeeID})
ON CREATE SET e.firstName = row.FirstName, e.lastName = row.LastName, e.title = row.Title;
// Create categories
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/categories.csv' AS row
MERGE (c:Category {categoryID: row.CategoryID})
ON CREATE SET c.categoryName = row.CategoryName, c.description = row.Description;
//创建索引和约束
CREATE INDEX product_id FOR (p:Product) ON (p.productID);
CREATE INDEX product_name FOR (p:Product) ON (p.productName);
CREATE INDEX supplier_id FOR (s:Supplier) ON (s.supplierID);
CREATE INDEX employee_id FOR (e:Employee) ON (e.employeeID);
CREATE INDEX category_id FOR (c:Category) ON (c.categoryID);
CREATE CONSTRAINT order_id ON (o:Order) ASSERT o.orderID IS UNIQUE;
CALL db.awaitIndexes();
//查询索引
CALL db.indexes();
// Create relationships between orders and products
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/orders.csv' AS row
MATCH (order:Order {orderID: row.OrderID})
MATCH (product:Product {productID: row.ProductID})
MERGE (order)-[op:CONTAINS]->(product)
ON CREATE SET op.unitPrice = toFloat(row.UnitPrice), op.quantity = toFloat(row.Quantity);
//查询订单和商品的关系
MATCH (o:Order)-[]-(p:Product)
RETURN o,p LIMIT 10;
// Create relationships between orders and employees
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/orders.csv' AS row
MATCH (order:Order {orderID: row.OrderID})
MATCH (employee:Employee {employeeID: row.EmployeeID})
MERGE (employee)-[:SOLD]->(order);
//查询订单和员工之间的关系
MATCH (o:Order)-[]-(e:Employee)
RETURN o,e LIMIT 10;
// Create relationships between products and suppliers
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/products.csv
' AS row
MATCH (product:Product {productID: row.ProductID})
MATCH (supplier:Supplier {supplierID: row.SupplierID})
MERGE (supplier)-[:SUPPLIES]->(product);
//查询供应商、产品之间的关系
MATCH (s:Supplier)-[]-(p:Product)
RETURN s,p LIMIT 10;
// Create relationships between products and categories
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/products.csv
' AS row
MATCH (product:Product {productID: row.ProductID})
MATCH (category:Category {categoryID: row.CategoryID})
MERGE (product)-[:PART_OF]->(category);
MATCH (c:Category)-[]-(p:Product)
RETURN c,p LIMIT 10;
// Create relationships between employees (reporting hierarchy)
LOAD CSV WITH HEADERS FROM 'https://gist.githubusercontent.com/jexp/054bc6baf36604061bf407aa8cd08608/raw/8bdd36dfc88381995e6823ff3f419b5a0cb8ac4f/employees.csv' AS row
MATCH (employee:Employee {employeeID: row.EmployeeID})
MATCH (manager:Employee {employeeID: row.ReportsTo})
MERGE (employee)-[:REPORTS_TO]->(manager
MATCH (e1:Employee)-[]-(e2:Employee)
RETURN e1,e2 LIMIT 10;
//find a sample of employees who sold orders with their ordered products
MATCH (e:Employee)-[rel:SOLD]->(o:Order)-[rel2:CONTAINS]->(p:Product)
RETURN e, rel, o, rel2, p LIMIT 25;
//find the supplier and category for a specific product
MATCH (s:Supplier)-[r1:SUPPLIES]->(p:Product {productName: 'Chocolade'})-[r2:PART_OF]->(c:Category)
RETURN s, r1, p, r2, c;
//find the supplier and category for a specific product
MATCH (s:Supplier)-[r1:SUPPLIES]->(p:Product {productName: 'Chocolade'})-[r2:PART_OF]->(c:Category)
RETURN s, r1, p, r2, c;
SpringBoot集成Neo4j
得益于 SpringData 的封装,SpringBoot 中集成Neo4j 将非常的简单,并且核心思路和关键字还是 jpa 那一套
pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
yml
spring:
neo4j:
uri: bolt://192.168.1.x:7687
authentication:
username: neo4j
password: neo4j.
logging:
level:
org.springframework.data.neo4j: debug
- bolt:一种通过数据库查询语言执行数据库查询的应用程序协议,Neo4j-server 的默认端口是 7687
- 开启日志可以打印 Cypher query language 查询语句
entity
package com.neo4j.neo4j.entity;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
@Node("Person")
public class PersonEntity {
@Id
private final String name;
private final Integer born;
public PersonEntity(Integer born, String name) {
this.born = born;
this.name = name;
}
public Integer getBorn() {
return born;
}
public String getName() {
return name;
}
}
- Node:实体对应哪个节点
- Id:主键
repository
package com.neo4j.neo4j.repository;
import com.neo4j.neo4j.entity.PersonEntity;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PersonRepository extends
Neo4jRepository<PersonEntity, String> {
List<PersonEntity> findByNameLike(String word);
@Query(value = "MATCH (n:Person) RETURN n limit 5")
List<PersonEntity> findList(String name, Integer born);
}
- Neo4jRepository:实现Neo4jRepository接口,集成基本的CURD
- findByNameLike:无需编写查询语句,SpringData帮助生成
- Query:编写自定义查询语句
controller
package com.neo4j.neo4j.controller;
import com.neo4j.neo4j.entity.PersonEntity;
import com.neo4j.neo4j.repository.PersonRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/test")
public class TestController {
private PersonRepository personRepository;
@GetMapping("/person")
public List<PersonEntity> findAllPerson() {
List<PersonEntity> persons = personRepository.findByNameLike("K");
List<PersonEntity> list = personRepository.findList("", 0);
return personRepository.findAll();
}
}
输出的日志:
2023-07-19 17:04:08.301 DEBUG 44492 --- [nio-9009-exec-3] org.springframework.data.neo4j.cypher : Executing:
MATCH (personEntity:`Person`) WHERE personEntity.name =~ (('.*' + $word) + '.*') RETURN personEntity{.born, .name, __nodeLabels__: labels(personEntity), __internalNeo4jId__: id(personEntity)}
2023-07-19 17:04:09.195 DEBUG 44492 --- [nio-9009-exec-3] org.springframework.data.neo4j.cypher : Executing:
MATCH (n:Person) RETURN n limit 5
2023-07-19 17:04:09.350 DEBUG 44492 --- [nio-9009-exec-3] o.s.d.n.c.t.Neo4jTransactionManager : Creating new transaction with name [org.springframework.data.neo4j.repository.support.SimpleNeo4jRepository.findAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2023-07-19 17:04:09.372 DEBUG 44492 --- [nio-9009-exec-3] org.springframework.data.neo4j.cypher : Executing:
MATCH (personEntity:`Person`) RETURN personEntity{.born, .name, __nodeLabels__: labels(personEntity), __internalNeo4jId__: id(personEntity)}
2023-07-19 17:04:09.587 DEBUG 44492 --- [nio-9009-exec-3] o.s.d.n.c.t.Neo4jTransactionManager : Initiating transaction commit