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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Spring Boot和Neo4j开发知识图谱的步骤: 1. 在项目中添加Spring Boot和Neo4j的依赖,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency> <dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j-ogm-http-driver</artifactId> <version>3.2.11</version> </dependency> ``` 2. 配置Neo4j数据库连接信息,可以在application.properties文件中添加以下配置: ``` spring.data.neo4j.uri=bolt://localhost:7687 spring.data.neo4j.username=neo4j spring.data.neo4j.password=123456 ``` 3. 创建实体类,可以使用@NodeEntity注解将Java类映射为Neo4j中的节点,例如: ```java @NodeEntity(label = "Person") public class Person { @Id @GeneratedValue private Long id; private String name; private int age; // 省略getter和setter方法 } ``` 4. 创建Repository接口,可以继承Neo4jRepository接口,例如: ```java public interface PersonRepository extends Neo4jRepository<Person, Long> { List<Person> findByName(String name); } ``` 5. 在Service中编写业务逻辑,例如: ```java @Service public class PersonService { @Autowired private PersonRepository personRepository; public List<Person> findByName(String name) { return personRepository.findByName(name); } public Person save(Person person) { return personRepository.save(person); } } ``` 6. 在Controller中编写接口,例如: ```java @RestController @RequestMapping("/person") public class PersonController { @Autowired private PersonService personService; @GetMapping("/findByName") public List<Person> findByName(String name) { return personService.findByName(name); } @PostMapping("/save") public Person save(@RequestBody Person person) { return personService.save(person); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值