neo4j 图数据库 springboot

一.安装

文中安装的是neo4j 3.5.34版本
neo4j社区版在liunx安装部署

https://blog.csdn.net/u013946356/article/details/81736232

二.知识图数据导入

参考:https://notemi.cn/neo4j-import-csv-file-data.html

http://openkg.cn/dataset/ch4masterpieces
放在对应的import文件夹下面
在这里插入图片描述
导入数据

LOAD CSV  WITH HEADERS FROM "file:///xiyouji.csv" AS line
MERGE (p:person{name:line.head});


LOAD CSV WITH HEADERS FROM "file:///xiyouji.csv" AS line
MERGE (p:person{name:line.tail});


LOAD CSV WITH HEADERS FROM "file:///xiyouji.csv" AS line
match (from:person{name:line.tail}),(to:person{name:line.head})
merge (from)-[r:rel{label:line.label,relation:line.relation}]->(to)

在这里插入图片描述

三.neo4j 语法

sql转Cypher语法例子
https://neo4j.com/developer/cypher/guide-sql-to-cypher/

Cypher语法:
官网地址:https://neo4j.com/docs/cypher-manual/3.5/clauses/match/


创建节点(多次执行,会创建相同的多个节点)

CREATE (john:Person {name: 'John'})
CREATE (joe:Person {name: 'Joe'})
CREATE (steve:Person {name: 'Steve'})
CREATE (sara:Person {name: 'Sara'})
CREATE (maria:Person {name: 'Maria'})
CREATE (john)-[:FRIEND]->(joe)-[:FRIEND]->(steve)
CREATE (john)-[:FRIEND]->(sara)-[:FRIEND]->(maria)


CREATE (adam:User { name: 'Adam' }),(pernilla:User { name: 'Pernilla' }),(david:User { name: 'David'}),
  (adam)-[:FRIEND]->(pernilla),(pernilla)-[:FRIEND]->(david)


多个标签到节点
m:节点名
标签名称:Cinema,Film,Movie,Picture
CREATE (m:Movie:Cinema:Film:Picture)


MERGE 如果节点不存在,会创建,
      如果节点的属性没有跟现有节点匹配上,则会创建新节点
      

CREATE (N0:Person {chauffeurName: 'John Brown', name: 'Charlie Sheen', bornIn: 'New York'})

下面就会创建新的节点
MERGE (charlie { name: 'Charlie Sheen', age: 10 })
RETURN charlie

MERGE (charlie { name: 'Charlie Sheen', age: 20 })
RETURN charlie

下面不会创建新的节点
MERGE (charlie { name: 'Charlie Sheen',bornIn: 'New York'})
RETURN charlie


如果“keanu”节点不存在,则创建节点,设置属性created
如果存,则设置属性lastSeen,多个属性逗号分隔
MERGE (keanu:Person { name: 'Keanu Reeves' })
ON CREATE SET keanu.created = timestamp()
ON MATCH SET keanu.lastSeen = timestamp()
RETURN keanu.name, keanu.created, keanu.lastSeen


MATCH (p:Info) where id (p)=195  
MATCH (n:Info) where id (n)=196 
MERGE (p)-[r:HAVE]->(n)
RETURN r


查询

查询所有
MATCH (n)
RETURN n

符号 -- 表示与关系相关,而不考虑关系的类型或方向
MATCH (:Person { name: 'Oliver Stone' })--(movie:Movie)
RETURN movie.title

等价于返回节点和关系
MATCH p =(actor { name: 'Charlie Sheen' })-[:ACTED_IN*2]-(co_actor)
RETURN relationships(p)

查询两个点的单个最短路径
MATCH (start:Person {name: 'Charlie Sheen'}), (end:Person {name: 'Michael Douglas'})
MATCH path = shortestPath((start)-[*]-(end))
RETURN path

All shortest paths 所有最短路径
MATCH (martin:Person { name: 'Martin Sheen' }),(michael:Person { name: 'Michael Douglas' }), p = allShortestPaths((martin)-[*]-(michael))
RETURN p

查询多关系的
MATCH (wallstreet { title: 'Wall Street' })<-[:ACTED_IN|:DIRECTED]-(person)
RETURN person.name

查朋友的朋友
MATCH (john {name: 'John'})-[:FRIEND]->()-[:FRIEND]->(fof)
RETURN john.name, fof.name


匹配他们的朋友,并仅返回那些具有以“S”开头的“name”属性的关注用户
MATCH (user)-[:FRIEND]->(follower)
WHERE user.name IN ['Joe', 'John', 'Sara', 'Maria', 'Steve'] AND follower.name =~ 'S.*'
RETURN user.name, follower.name


找到朋友数大于1的
MATCH (n {name: 'John'})-[:FRIEND]-(friend)
WITH n, count(friend) AS friendsCount
WHERE friendsCount > 1
RETURN n, friendsCount



查询叫Maria的人是哪一层关系
MATCH (me:Person {name: 'John'})-[:FRIEND*1..3]-(friend:Person {name: 'Maria'})
RETURN CASE
  WHEN size((me)-[:FRIEND]-(friend)) > 0 THEN 'Friend'
  WHEN size((me)-[:FRIEND]-()-[:FRIEND]-(friend)) > 0 THEN 'Friend of Friend'
  WHEN size((me)-[:FRIEND]-()-[:FRIEND]-()-[:FRIEND]-(friend)) > 0 THEN 'Friend of Friend of Friend'
  ELSE 'Not Connected'
END AS relationship


拼接属性[]来查询,过滤动态计算的节点属性
CREATE (a:Restaurant { name: 'Hungry Jo', rating_hygiene: 10, rating_food: 7 }),(b:Restaurant { name: 'Buttercup Tea Rooms', rating_hygiene: 5, rating_food: 6 }),(c1:Category { name: 'hygiene' }),(c2:Category { name: 'food' })
WITH a, b, c1, c2
MATCH (restaurant:Restaurant),(category:Category)
WHERE restaurant["rating_" + category.name]> 6
RETURN DISTINCT restaurant.name


UNWIND关键字用于展开列表或集合中的元素
WITH关键字用于将查询结果传递给下一个查询子句,它类似于SQL中的SELECT子句,可以用于选择和重命名列、聚合、排序等操作

WITH ['John', 'Mark', 'Jonathan', 'Bill'] AS somenames
UNWIND somenames AS names
WITH names AS candidate
WHERE candidate STARTS WITH 'Jo'
RETURN candidate


方括号将从起始索引 1 提取元素,直到(但不包括)结束索引 3
WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[1..3] AS result


从'Anders'开始,找到所有匹配的节点,按名称降序排列并获得顶部结果,
然后找到与该顶部结果连接的所有节点,并返回它们的名称。
MATCH (n { name: 'Anders' })--(m)
WITH m
ORDER BY m.name DESC LIMIT 1
MATCH (m)--(o)
RETURN o.name


使用 exists() 函数仅包含存在属性的节点或关系。
MATCH (n)
WHERE exists(n.belt)
RETURN n.name, n.belt


使用 STARTS WITH 进行前缀字符串搜索
使用 ENDS WITH 进行后缀字符串搜索
使用 CONTAINS 进行子字符串搜索
MATCH (n)
WHERE n.name STARTS WITH 'Pet'
RETURN n.name, n.age

不以'y'结尾
MATCH (n)
WHERE NOT n.name ENDS WITH 'y'
RETURN n.name, n.age

使用正则表达式进行匹配
不区分大小写的正则表达式
MATCH (n)
WHERE n.name =~ '(?i)Tim.*'
RETURN n.name, n.age


排序,跳过,限制
MATCH (n)
RETURN n.name
ORDER BY n.name desc
SKIP 1
LIMIT 2

MATCH (e:Employee) 
WHERE e.id IS NOT NULL
RETURN e.id,e.name,e.sal,e.deptno


MATCH (e:Employee) 
WHERE e.id IN [123,124]
RETURN e.id,SUBSTRING(e.name,0,4),e.sal,e.deptno

MATCH (e:Employee) 
RETURN SUM(e.sal),AVG(e.sal)


关系
最小长度为 3,最大长度为 5。它描述了 4 个节点和 3 个关系、5 个节点和 4 个关系或 6 个节点和 5 个关系的图,所有这些都在一条路径中连接在一起。
(a)-[*3..5]->(b)

(a)-[*3..]->(b)
(a)-[*..5]->(b)
任意长度的路径
(a)-[*]->(b)

MATCH (e:Customer),(cc:CreditCard) 
CREATE (e)-[r:DO_SHOPPING_WITH ]->(cc)


如果节点之间没有KNOWS关系则创建
MATCH (charlie:Person { name: 'Charlie Sheen' }),(oliver:Person { name: 'Oliver Stone' })
MERGE (charlie)-[r:KNOWS]-(oliver)
RETURN r


存在的点,创建带属性的关系
MATCH (cust:Info),(cc:OneId) 
where Id(cust)=152 and Id(cc)= 98
CREATE (cust)-[r:one_with{createTime:"2023-08-14",priority:1,uid:"111",delete:0}]->(cc) 
RETURN r



复制节点关系,删除原有节点关系
MATCH (a:Info)-[r:one_with]->(b:OneId)
WHERE Id(a)=152 and Id(b)= 98
WITH a, b, r
MATCH (c:OneId)
WHERE Id(c)= 170
CREATE (a)-[newR:one_with]->(c)
SET newR = r
DELETE r
RETURN a, c,newR


双向关联
MATCH (a:Node {name: 'A'})
MATCH (b:Node {name: 'B'})
CREATE (a)-[:RELATIONSHIP_TYPE]->(b), (b)-[:RELATIONSHIP_TYPE]->(a)

新增节点和关系

MATCH (fb1:FaceBookProfile1)-[like:LIKES]->(fb2:FaceBookProfile2) 
RETURN like

CREATE (video1:YoutubeVideo1{title:"Action Movie1",updated_by:"Abc",uploaded_date:"10/10/2010"})
-[movie:ACTION_MOVIES{rating:1}]->
(video2:YoutubeVideo2{title:"Action Movie2",updated_by:"Xyz",uploaded_date:"12/12/2012"}) 


查询关系

MATCH (cust)-[r:DO_SHOPPING_WITH]->(cc) 
RETURN cust,cc



删除所有节点和关系
MATCH (n)
DETACH DELETE n

DELETE操作用于删除节点和关联关系
删除节点

MATCH (start)-[r:HAVE]->(end) where id(r)=152 DELETE r

删除关系和节点(多条关键全删)
MATCH (cc: CreditCard)-[rel]-(c:Customer) 
DELETE rel,cc,c


REMOVE操作用于删除标签和属性。
删除属性
match(c:Book) where c.id=122 REMOVE c.price  return c

删除标签
MATCH (n { name: 'David' })
REMOVE  n:person:gay
RETURN n.name, labels(n) AS labels



set添加属性和修改属性值

MATCH (book:Book)
SET book.title = 'superstar',book.price=100
RETURN book

+= 增加修改属性
CREATE (a:Person { name: 'Jane', age: 20 })
WITH a
MATCH (p:Person { name: 'Jane' })
SET p += { name: 'Ellen', livesIn: 'London' }
RETURN p.name, p.age, p.livesIn

MATCH (n {name: 'John'})-[:FRIEND]-(friend)
WITH n, count(friend) AS friendsCount
SET n.friendsCount = friendsCount
RETURN n.friendsCount

增加多个标签
MATCH (n { name: 'David' })
SET n:person:gay
RETURN n.name, labels(n) AS labels

FOREACH
从A节点到D节点的路径上都增加一个属性
MATCH p =(begin)-[*]->(END )
WHERE begin.name = 'A' AND END .name = 'D'
FOREACH (n IN nodes(p)| SET n.marked = TRUE )

UNION合并
需要加 as 别名 保持一致,不然报错

MATCH (cc:CreditCard) RETURN cc.id as id,cc.number as number
UNION
MATCH (dc:DebitCard) RETURN dc.id as id ,dc.number as number



ID和TYPE关系函数来检索关系的Id和类型详细信息。
MATCH (a)-[movie:ACTION_MOVIES]->(b) 
RETURN ID(movie),TYPE(movie)


它用于知道关系的开始节点。
MATCH (a)-[movie:ACTION_MOVIES]->(b) 
RETURN STARTNODE(movie)

它用于知道关系的结束节点。
MATCH (a)-[movie:ACTION_MOVIES]->(b) 
RETURN ENDNODE(movie)



创建索引(相同标签名称的所有节点的属性创建索引)
CREATE INDEX ON :Customer (name)


删除索引

DROP INDEX ON :Customer (name)



唯一索引
CREATE CONSTRAINT ON (cc:CreditCard)
ASSERT cc.number IS UNIQUE


删除唯一索引

DROP CONSTRAINT ON (cc:CreditCard)
ASSERT cc.number IS UNIQUE



UNWIND [{key: 'key1', val: 'val1', insert: true, priority: 'priority1'}, {key: 'key2', val: 'val2', insert: true, priority: 'priority2'}] AS data
MERGE (n:Label {key: data.key, val: data.val})
ON CREATE SET n.insert = data.insert, n.priority = data.priority
RETURN n

WITH ['John', 'Mark', 'Jonathan', 'Bill'] AS names
WITH names AS candidate
WHERE candidate STARTS WITH 'Jo'
RETURN candidate


返回路径中从A到B的所有节点的 age 属性大于为“30”。
ALL 所有
any 任何

MATCH p =(a)-[*1..3]->(b)
WHERE a.name = 'Alice' AND b.name = 'Daniel' AND ALL (x IN nodes(p) WHERE x.age > 30)
RETURN p


返回路径中没有节点的 age 属性设置为“25”。
MATCH p =(n)-[*1..3]->(b)
WHERE n.name = 'Alice' AND NONE (x IN nodes(p) WHERE x.age = 25)
RETURN p

每个返回路径中只有一个节点的 eyes 属性设置为“蓝色”。
MATCH p =(n)-->(b)
WHERE n.name = 'Alice' AND SINGLE (var IN nodes(p) WHERE var.eyes = 'blue')
RETURN p


coalesce() 返回给定表达式列表中的第一个非 null 值。

如果头发有值,则返回hairColor,以此类推
MATCH (a)
WHERE a.name = 'Alice'
RETURN coalesce(a.hairColor, a.eyes)



endNode结束节点 返回关系的结束节点。
startNode返回关系的起始节点。
MATCH (x:Developer)-[r]-()
RETURN endNode(r)



head()返回属性中list中的第一个元素
last() 返回列表中的最后一个元素。
MATCH (a)
WHERE a.name = 'Eskil'
RETURN a.array, head(a.array)


length() 返回路径的长度
从Alice点出发,每条路径长度2
MATCH p =(a)-->(b)-->(c)
WHERE a.name = 'Alice'
RETURN length(p)

获取节点的属性
MATCH (a)
WHERE a.name = 'Alice'
RETURN properties(a)

uuId
RETURN randomUUID() AS uuid
时间戳
RETURN timestamp()

字符串长度
MATCH (a)
WHERE size(a.name)> 6
RETURN size(a.name)

返回与模式表达式匹配的路径数
MATCH (a)
WHERE a.name = 'Alice'
RETURN size((a)-->()-->()) AS fof


类型转换
RETURN toBoolean('TRUE')
RETURN toFloat('11.5')
RETURN toInteger('42')

返回 r 的关系类型
MATCH (n)-[r]->()
WHERE n.name = 'Alice'
RETURN type(r)


平均
MATCH (n:Person)
RETURN avg(n.age)

收集所有年纪[13,33,44]
MATCH (n:Person)
RETURN collect(n.age)


返回关系类型及其组计数
MATCH (n { name: 'A' })-[r]->()
RETURN type(r), count(*)

age 中所有值的总和
MATCH (n:Person)
RETURN sum(n.age)


导入数据
LOAD CSV  WITH HEADERS FROM "file:///xiyouji.csv" AS line
MERGE (p:person{name:line.head});


LOAD CSV WITH HEADERS FROM "file:///xiyouji.csv" AS line
MERGE (p:person{name:line.tail});


LOAD CSV WITH HEADERS FROM "file:///xiyouji.csv" AS line
match (from:person{name:line.tail}),(to:person{name:line.head})
merge (from)-[r:rel{label:line.label,relation:line.relation}]->(to)


UNWIND $rows as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId WITH row,startNode 
										MATCH (endNode) WHERE ID(endNode) = row.endNodeId 
CREATE (startNode)-[rel:`one_with`]->(endNode) SET rel += row.props RETURN row.relRef as ref, ID(rel) as id, $type as type with params {type=rel, rows=[{startNodeId=177, relRef=-12, endNodeId=176, props={uid=646257b2-cfed-4e14-aa43-88e2af0d0ea5, createTime=2023-08-17 09 59 53, priority=0, delete=0}}]}

四.举例

UNWIND 将列表里的值展开
在这里插入图片描述

在这里插入图片描述

CREATE (N0:Person {name: 'Anders'})
CREATE (N1:Person {name: 'Becky'})
CREATE (N2:Person {name: 'Cesar'})
CREATE (N3:Person {name: 'Dilshad'})
CREATE (N4:Person {name: 'George'})
CREATE (N5:Person {name: 'Filipa'})

CREATE (N0)-[:KNOWS]->(N3)
CREATE (N0)-[:KNOWS]->(N2)
CREATE (N0)-[:KNOWS]->(N1)
CREATE (N1)-[:KNOWS]->(N4)
CREATE (N2)-[:KNOWS]->(N4)
CREATE (N3)-[:KNOWS]->(N5)

在这里插入图片描述

MATCH (me)-[:KNOWS*1..2]-(remote_friend)
WHERE me.name = 'Filipa'
RETURN remote_friend.name

在这里插入图片描述
请注意,可变长度关系不能与 CREATE 和 MERGE 一起使用

五. 执行计划

Cypher查询前加上EXPLAIN关键字 不会执行

PROFILE关键字 会执行

profile MATCH (n) where n.value='wmRWuoCQAA'  RETURN n ;

runtime:interpreted 是社区版neo4j 在执行Cypher query默认的运行选项

执行计划从下往上看,+AllNodesScan 代表扫描所有的节点,Rows列,扫描了339510,DB Hits 339510

在这里插入图片描述
标签查询避免全表扫描

profile MATCH (n:Info) where n.value='wmRWuoCQAAj'  RETURN n ;

在这里插入图片描述

增加了索引

CREATE INDEX ON :Info(value);

可以看到加了索引后,查询rows变成了1,查询时间减少到了60
在这里插入图片描述

neo4j 4.3版本以上才支持在关系上创新索引
如果要根据关系上的属性查询,最好按照4.3以上 或者使用全文索引来处理

在这里插入图片描述

六 全文搜索索引

https://neo4j.com/docs/cypher-manual/3.5/schema/indexes/#schema-index-fulltext-search

类似ES打分,可以模糊查询

创建关系one_with上属性为uid的索引

CALL db.index.fulltext.createRelationshipIndex('one_with_uid_index', ['one_with'], ['uid'])

使用全文索引搜索

CALL db.index.fulltext.queryRelationships("one_with_uid_index", 'xxxxx') YIELD relationship
with startNode(relationship) as startnode,type(relationship) as r,endNode(relationship) as endnode
return startnode,labels(startnode) as startlabel,r,endnode,labels(endnode) as endlabel

七. 与springboot 整合

下面实现了Neo4j Spring动态起始节点类型

https://www.codeleading.com/article/35872569441/

举例:
自定义Cypher语句

public interface OneDynamicRepository extends Neo4jRepository<OneDynamic, Long> {

    @Query("MATCH (startNode:Info) where Id(startNode)=$startId  MATCH (endNode:OneId) where Id(endNode)=$endId  MERGE (startNode)-[r:one_with{ priority: $priority, type:$type ,uid:$uid , delete:0 } ]->(endNode) RETURN r,startNode,endNode ")
    List<OneDynamic> mergeRelationship(@Param("startId") Long startId, @Param("endId") Long endId , @Param("priority") Integer priority,@Param("type") String type,@Param("uid") String uid);
}

 @Query("CALL db.index.fulltext.queryRelationships('one_with_uid_index', 'xxxxx') YIELD relationship with startNode(relationship) as startNode,relationship as r,endNode(relationship) as endNode return startNode,r,endNode")
    List<OneDynamic> selectFullIndex();

八.优化:

通过下面的命令来确定内存分配

./neo4j-admin memrec --database=graph.db

在这里插入图片描述

举例
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值