neo4j 开发记录

docker搭建

拉取镜像

docker pull neo4j

启动

docker run -d --name myneo4j \
-p 7474:7474 -p 7687:7687 \
-v /home/neo4j/data:/data \
-v /home/neo4j/logs:/logs \
-v /home/neo4j/conf:/var/lib/neo4j/conf \
-v /home/neo4j/import:/var/lib/neo4j/import \
--env NEO4J_AUTH=neo4j/meiya \
neo4j

如果不设置密码,那么默认密码是 neo4j/neo4j
而,不需要验证,则是配置--env NEO4J_AUTH=none

使用docker-compose进行启动

version: "3"
services:
	my-neo4j:
  	image: neo4j:latest
    ports:
    	- 7474:7474
      - 7687:7687
    volumes:
    	- /home/neo4j/data:/data
      - /home/neo4j/logs:/logs
      - /home/neo4j/conf:/var/lib/neo4j/conf
      - /home/neo4j/import:/var/lib/neo4j/import
    environment:
    	NEO4J_AUTH: neo4j/meiya@neo4j
     

DockerFile 重新打包

感觉启动后还要配置,是挺麻烦的,重新打包

Springboot 使用

  1. pom
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

首先neo4j的事务和mysql的不一样,需要手动配置:
比如下面这个(只是比如,下面的例子在某种程度上是对的,还是不对)

@Configuration
@EnableNeo4jRepositories("com.lry.jps.repository.neo4j")
public class Neo4jConfig {
    
    

    @Autowired
    private SessionFactory sessionFactory;

    @Bean("transactionManager")
    public Neo4jTransactionManager neo4jTransactionManager() {
    
    
        return new Neo4jTransactionManager(sessionFactory);
    }
}

注意:这有一个问题
经过测试,它这个配置支持neo4j 和 mysql,不过在项目中确实遇到了,事务的问题,发生场景是:
在spring的调度框架schedule中,出现数据库数据不能持久化到数据库,MongoDB的可以,但是mysql的就失效了,这也是某天突然发现的问题,测试了好多次才确认的。

具体原因是neo4j使用的事务管理器和spring默认的事务管理器是的,都是继承于AbstractPlatformTransactionManager,所以才会出现上面代码中的bean名称为:transactionManager,而且这个名称也是默认的事务管理器名称;
那么spring针对这种多事务管理器也提供了ChainedTransactionManager,它支持多个事务管理器,并且,在这种模式下,需要指定默认的事务管理器,这里我们就默认mysql的:(下面这个是对的,将两个事务管理进行合并)

@Configuration
@EnableNeo4jRepositories("com.lry.jps.repository.neo4j")
public class Neo4jConfig {
    
    

    public static final String MULTI_TRANSACTION_MANAGER = "multiTansactionManager";

    @Autowired
    private SessionFactory sessionFactory;

    @Bean("transactionManager")
    @Primary
    public JpaTransactionManager jpaTransactionManager(EntityManagerFactory emf) {
    
    
        return new JpaTransactionManager(emf);
    }

    @Bean("neo4jTransactionManager")
    public Neo4jTransactionManager neo4jTransactionManager() {
    
    
        return new Neo4jTransactionManager(sessionFactory);
    }

    @Bean(MULTI_TRANSACTION_MANAGER)
    public PlatformTransactionManager platformTransactionManager(EntityManagerFactory emf) {
    
    
        return new ChainedTransactionManager(jpaTransactionManager(emf), neo4jTransactionManager());
    }
}

如上配置好后,使用方式还是和之前一样,但是有使用neo4j的,需要加上事务管理的名称:@Transactional**(value = Neo4jConfig.MULTI_TRANSACTION_MANAGER)**

在进行更新操作使用spring 的jpa方式,但查询,如复杂查询,需要手动编写cql。

neo4j语法

() 括住的是节点,{} 括住的是属性 : 开头的是标签 []括住的是关系

创建节点

create(:enter{name:"6"});

创建关系

# 查询出节点name为3和4的,别名a和b,建立a到b的关系;
match(a:enter{name:"3"}),(b:tt{name:"1"}) create (a)-[c:test]->(b) return a,b,c;

删除

match(a) where a.name = '' delete a

修改

# 修改节点id=27的节点
# 注意,where条件再set语句前面,并且节点id通过ID()必须方法获取
match (a)  where ID(a)=27 set a.name='溶解乙炔' return a

查询

查询标签对应的节点关系图:

match(a:enter) return a;

查询指定标签的节点关系:

match(a:enter)-[]->(b:enter) return a,b;

match(a:enter)-[:test]->(b:enter) return a,b;

match(a:tt)-[]->(b:enter) return a,b;

# 还有这种赋值返回的
match p=(a:enter)-[:test]->(b:enter) return p;

复杂查询:

# 这里通过标签查的话,会把复合的标签的阶段的都查出来,所以,增加增加查询条件name
match p=(a:enter{name:"1"})-[*1..2]->(b:enter) return p;

# 最短路劲 看下面的,这个语句有问题
# match p=shortestpath((a:enter{name:"1"})-[*1..2]->(b:enter)) return p;

# 查询两个节点间的最短,不能同一种标签的查询
# 所有路径使用*号
match (a:enter{name:"1"}),(b:enter{name:"3"}),path=shortestpath((a)-[*]->(b)) return a,b,path;


# 最长路径
# length 是计算 路径长度,所以我们按照这个长度进行排序,去第一个就是最长路径,那么相反就是最短路径
match p=((a:test)-[*1..]->(b:test)) return p order by length(p) desc limit 1

# 最短路径
# 需要排除开始节点 等于 结束节点
match p=((a:test)-[*1..]->(b:test)) where id(a)<>id(b) return p order by length(p) asc limit 1

# 多标签查询
# 标签查询也和条件查询一样,可以用and、or
match (a)
WHERE n:GraphNode OR n:Abstract
return a

# 模糊查询
match(emp) where emp.name =~'.*haha.*' return emp

# where条件句
# 和上面在的条件查询一样,不过where写法更顺手
match p=((n)-[*]->(b)) where n.mappingTaskId in ["72dd81ad-4fac-42e8-aa23-c8ebd2e149ae","sss"]  return p;

match p=((n)-[*]->(b)) where n.mappingTaskId = ("72dd81ad-4fac-42e8-aa23-c8ebd2e149ae")  return p;

# 查询没有关系的节点
# not()方法进行过滤,关系指向没有箭头表示所有指向
match (a:GraphNode) where not((a)-[]-()) return a

# 查询条件节点关系条数大于0的,单关系指出去的图
match p=((a)-[*0..]->()) where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a:`重大危险源` return p;

# 查询条件节点关系条数大于0(包含当个节点),单关系指向自己的图
match p=(()-[*0..]->(a)) where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a:`重大危险源` return p;

# 查询条件节点的指向出去和指向自己的图
match p=(()-[*0..]->(a)) ,p2=((a)-[*0..]->()) where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a.name = '溶解乙炔' return p,p2;

# 查询条件节点指向自己,和指向出去的图
# 这个查询是前面两条查询的总和,也就是前面两条查询=这条查询
match p=(()-[*0..]->(a)-[*0..]->()) where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a.name = '溶解乙炔' return p;

# 查询条件节点所有关联(直接关系和间接关系)的图
# 注意:这里的关系没有箭头,没有指向,则包含所有指向
#       这里关系是*0..而不是*,是因为使用*不会查询出单节点,也就是*表示的是有关系的,*0..表示的是没有关系和有关系的
match p=((a)-[*0..]-()) where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a.name = '溶解乙炔' return p;

# 指定路径后,关系别名设置应该是像这样
# relationships() 方法获取到的是一个list的关系,所有这里要使用all(r in relationships(p) where r.xx=xxx)的子查询
match p=((a)-[*0..]->()) with *,relationships(p) as c  where a.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d' and a:`重大危险源` and all(r in c where r.mappingTaskId='a606980a-e887-4446-bb72-3956b0c5f14d') return p

# 类似group by 的查询:按a.neme 分组统计关系个数
match p=((a)->[*1]-(b)) with a,count(*) as count return a.name,count order by count desc

测试例子:

 List<Record> list = neo4jSession.run("match p=(a:enter{name:\"3\"})-[*1]->(b:tt) return p;").list();
        Map<String,List<Object>> resultObj = new HashMap<>();
        for (Record record : list){
    
    
            List<String> keys = record.keys();
            for (int i=0;i<keys.size();i++) {
    
    
                Value value = record.get(keys.get(i));
                if(resultObj.containsKey(keys.get(i))){
    
    
                    resultObj.get(keys.get(i)).add(value.asObject());
                }else {
    
    
                    List<Object> s = new ArrayList<>();
                    s.add(value.asObject());
                    resultObj.put(keys.get(i),s);
                }
            }
        }

开发注意点:

  1. 使用cql查询得到的结果和语句中return返回的一样,比如:match(a)-[c]->(b) return a,b,c 那么,结果中,就是按照这个顺序返回结果,如果是match p=((a)-[c]->(b)) return p ; 那么p就包含了a b c

猜你喜欢

转载自blog.csdn.net/qq_28911061/article/details/120470779
今日推荐