I 安装Neo4J
1 准备工作
1.1 下载安装包--bin--Neo4J-ce.exe,执行Start
1 准备工作
删除节点
MATCH(n:City) DETACH DELETE n
MATCH(n:City {name="Wuhan"}) DETACH DELETE n
START n = node(1) DELETE n
删除关系、节点关系
match (n)-[r:created]-() detach delete r
match(o:Organ {organId:"1000"})-[r:ORGAN_ACCOUNT]->(c:Account
{countId:"1"})detach delete r
match(o:Organ {organId:"1000"})-[r:ORGAN_ACCOUNT]->(c:Account
{countId:"1"})detach delete r,o,c
查看节点
MATCH(n:City) DETACH RETURN n
查看关系
match (n)-[r:created]-() RETURN r
创建结点:create (:Person {name:"张三"}),创建一个名为张三的节点;
create (a:Equip{equipSn:'SC1',equipStatus:'1'})
create (c:Account{countId:'1',Name:'CJ1',userName:'CJ去名称'})
创建结点
关系:
create (n:Equip {equipSn:"SC1"})-[r:equip_Customer {bindStatus:"1"}]->(c:Customer {Id:"adminId",Name:"chenJ"}) return n,r,c;
条件查询:
MATCH (n:BdEquipmentInfo)-[r:ISERVER_CUSTOMER]->(c:CfCustomer )
WHERE 1 = 1 and n.equipmentSn= "SC1" And c.customerName =~ '.*nJAdmin.*' and r.bindStatus = '1' RETURN c ;
修改属性值,
给默认的根节点添加name,ID属性,便于查询
start a = node(*) where a.name="a" set a.name="A" return a,a.name ; start n=node(0) set n.name="Root",n.ID="001"
创建多个节点数据,多个元素间用逗号或者用create分开:
create (a:Person {name:"jiaj",born:2003})-[r:ACTED_IN {roles:["student"]}]->(m:School {name:"CDLG",address:"chengdu"})
create (d:Person {name:"weiw",born:2001})-[:DIRECTED]->(m)
return a,d,r,m;
创建关系【在id=1和2的2个节点间】
CREATE (a:node(1))-[:ACTED_IN { roles: "Forrest"}]->(b:node(2))
官网:
http://neo4j.com/docs/developer-manual/current/cypher/clauses/match/
III 项目中的集成应用
**************************************
III 项目中的集成应用
1 定义结点、关系(
@NodeEntity、@RelationshipEntity)
结点关系图:
package com.domain.entity;
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@NodeEntity
public class BdApp{
@GraphId
private Long id;
private String appId;
private String appName;
private String appType;
private String appClassId;
//
}
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@NodeEntity
public class BdAppVer{
@GraphId
private Long id;
private String appVerId;
private String appVerNum;
//
}
package com.domain.relationship;
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@RelationshipEntity(type = "APP_VER")
public class AppVerRelationship {
@GraphId
private Long id;
@StartNode
private BdApp bdApp;
@EndNode
private BdAppVer bdAppVer;
private String memo;
//
}
**************************************
2 定义结点、关系持久化层
2.1 APP 结点 Code:
package com.mapper.entity;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BdAppRepository extends GraphRepository<BdApp> {
//1 可自动继承neo4j.repository.GraphRepository父类封装的各方法
//2自定义方法
BdApp findByAppId(String appId);
}
附:结点
持久化层的 继承关系图
2.2 AppVer结点Code
package com.mapper.relationship
@Repository
public interface BdAppVerRepository extends GraphRepository<BdAppVer> {
//3Query自定义属性模糊与精确查询,appVerName= ".*XXX.*"
@Query("MATCH (bdAppVer:BdAppVer) " +
"WHERE bdAppVer.appId={appId} AND bdAppVer.appVerName =~ {appVerName} " +
"RETURN bdAppVer ORDER BY bdAppVer.appVerNum DESC ")
List<BdAppVer> queryBdAppVer(String appId, String appVerName);
}
2.3 关系AppVerRepository Code
@Repository
public interfaceAppVerRepositoryextendsGraphRepository<AppVerRelationship> {
//同结点原理一致
}
3 定义结点、关系Service层
3.1 BdAppService:
public interface BdAppService {
/**
* 创建BdApp
*/
BdApp createBdApp(BdApp bdApp);
/**
* 创建BdAppVer 和 关系AppVerRelationship
*/
BdAppVer createBdAppVer(String appId,BdAppVer bdAppVer);
}
Impl:
@Service
@Transactional
public class BdAppServiceImpl implements BdAppService {
@Autowired
private BdAppRepository bdAppRepository;
@Autowired
private BdAppVerRepository bdAppVerRepository;
@Autowired
private AppVerRepository appVerRepository;//关系Repository
@Override
public BdApp createBdApp(BdApp bdApp) {
//bdApp.setAppId(UUID.randomUUID().toString());
bdAppRepository.save(bdApp);
return bdApp;
}
@Override
public BdAppVer createBdAppVer(String appId, BdAppVer bdAppVer) {
BdApp bdApp = bdAppRepository.findByAppId(appId);
bdAppVer.setAppId(appId);
bdAppVerRepository.save(bdAppVer);
//建立关系
AppVerRelationship appVerRelationship = new AppVerRelationship();
appVerRelationship.setBdApp(bdApp);
appVerRelationship.setBdAppVer(bdAppVer);
appVerRelationship.setMemo("");
appVerRepository.save(appVerRelationship);
}
3.2 BdAppVerService&BdAppVerServiceImpl同上
4 SpringJUnit4
测试 结点/结点关系的CURD
4.1 定义环境(
ComponentScan、Configuration和初始化
neo4j Jdbc
)
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableAutoConfiguration
@EnableNeo4jRepositories(basePackages = {"com.mapper.entity.",
"com.mapper.relationship."})
@EntityScan(basePackages = {"com.domain."})
@EnableTransactionManagement
@ComponentScan
@Configuration
public class CoreConfig{
@Bean
public org.neo4j.ogm.config.Configuration getConfiguration(){
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config.driverConfiguration()
.setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver")
.setURI("http://neo4j:neo4j@localhost:7474");
return config;
}
}
4.2 测试类:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//应用模块测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CoreConfig.class)
public class BdAppServiceTest {
@Autowired
public BdAppService bdAppService;
@Test
public void createBdAppTest(){
BdApp bdApp = new BdApp();
bdApp.setAppId("CJ1");
bdApp初始化值Set
bdAppService.createBdApp(bdApp);
}
@Test
public void createBdAppVerAndRelationshipTest(){
String appId = "CJ1";
BdAppVer appVer = new BdApp();
BdAppVer 初始化值Set
bdAppService.createBdAppVer(appId ,bdApp);
}
}
5 实现复杂查询(如多条件分页查询&结点、关系组合查询等
5.1 Match执行复杂语句方式,执行
@Query
实现
5.2 自定义持久层Dao实现
**********************************************************************************
5.1 Code:
**********************************************************************************
5.1 Code:
1 实体、关系定义:
实体:
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@NodeEntity
public class Packcode{
@GraphId
private Long id;
private String packcodeNo;//当前包编号
private String parentPackcodeNo;//父(上级)包编号
private String packName;
@Relationship(type= "Pc_LINK_Pc")
private Set<PackCodeLinkPackRship> packCodeLinkPacks;
}
关系
:
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@RelationshipEntity(type = "Pc_LINK_Pc")
@QueryResult
public class PackCodeLinkPackRship {
@StartNode
private Packcode bdPackcode;
@EndNode
private Packcode subBdPackcode;
@GraphId
private Long id;
private String bindStatus;
。。。
}
2 Cypher语句查询实现
//2.1 获取packcodeNo 包所有子包(即下属树结点信息)
@Query(" MATCH p=(p:Packcode)-[r:Pc_LINK_Pc*0..]->(subP:Packcode) " +
" WHERE p.packcodeNo = {packcodeNo} " +
" RETURN p")
List<Packcode> loadPackcodeSubTree(@Param("packcodeNo") String packcodeNo);
即:MATCH p=(p:Packcode)-[r:Pc_LINK_Pc*0..]->(subP:Packcode)
WHERE p.packcodeNo = '1' RETURN p;
*********************************************************
//2.2获取packcodeNo 包所有父包且关系bindStatus=1
@Query(" MATCH p=(s:Packcode)-[rp:Pc_LINK_Pc*0..]->(subP:Packcode) " +
" WHERE subP.packcodeNo = {packcodeNo} and all( x in rp where x.bindStatus= {bindStatus} ) "+
" RETURN p ")
List<Packcode> findAllParentPackcodeByPackcodeNoAndBindStatus(@Param("packcodeNo")String packcodeNo,
@Param("bindStatus") String bindStatus);
即:MATCH p=(s:Packcode)-[rp:Pc_LINK_Pc*0..]->(e:BdPackcode) WHERE e.packcodeNo = '3Sub' and all( x in rp where x.bindStatus='1' )
RETURN p;
***********************************************************************************
II)多条件分页查询(注意:雷同部分略)
I)
多条件查询(未分页)
1 定义App Dao接口
package com.mapper.neo4jdao.model;
public interface BdAppDao {
List<BdApp> queryBdAppByPerproty(BdApp bdApp);
}
2 实现App Dao实现层
package com.mapper.neo4jdao.model.Impl;
@Repository
public class BdAppDaoImpl implements BdAppDao {
@Autowired
Session session;
//查询前缀
private static final String QUERY_PREFFIX = "MATCH (bdApp:BdApp) ";
private static final String QUERY_WHERE = " WHERE 1 = 1 ";
@Override
public List<BdApp> queryBdAppByPerproty(BdApp bdApp) {
Map<String, String> params = new HashMap<>();
String cypher = this.getListCypher(bdApp, params);
if (StringUtils.isEmpty(cypher)) return null;
Iterable<BdApp> its = session.query(BdApp.class, cypher, params);
if (its == null) return null;
List<BdApp> results = new ArrayList<>();
its.forEach((v) -> results.add(v));
return results;
}
/**
* 构造查询型号的cypher语句
* @param queryParams 查询对象
* @return 返回cypher语句
*/
private String getListCypher(BdApp domain, Map<String, String> queryParams) {
StringBuffer stringBuffer = new StringBuffer(QUERY_PREFFIX);
stringBuffer.append(QUERY_WHERE);
stringBuffer.append(midCypher(stringBuffer, domain, queryParams));
stringBuffer.append(" RETURN bdApp");
stringBuffer.append(" ORDER BY bdApp.appType,bdApp.appClassName,bdApp.appId ASC ");//(默认按照 类型、分类 、appid排序)
return stringBuffer.toString();
}
/**
* @param queryParams
* @return
*/
private String midCypher(StringBuffer sb, BdApp domain, Map<String, String> queryParams) {
StringBuffer stringBuffer = new StringBuffer();
//多条件查询:类型APP_TYPE、分类 APP_CLASS_NAME、appid、名称APP_NAME、状态APP_STATUS
if (!StringUtils.isEmpty(domain.getAppType())) {
stringBuffer.append(" AND bdApp.appType = {aType}");
queryParams.put("aType", domain.getAppType());
}
if (!StringUtils.isEmpty(domain.getAppClassId())) {
stringBuffer.append(" AND bdApp.appClassId = {appCId}");
queryParams.put("appCId", domain.getAppClassId());
}
if (!StringUtils.isEmpty(domain.getAppId())) {
stringBuffer.append(" AND bdApp.appId = {aId}");
queryParams.put("aId", domain.getAppId());
}
if (!StringUtils.isEmpty(domain.getAppName())) {
stringBuffer.append(" AND bdApp.appName =~ {aName}");
queryParams.put("aName", ".*"+domain.getAppName()+"*.");
}
//状态APP_STATUS
if (!StringUtils.isEmpty(domain.getAppStatus())) {
stringBuffer.append(" AND bdApp.appStatus = {aStatus}");
queryParams.put("aStatus", domain.getAppStatus());
}
return stringBuffer.toString();
}
II)多条件分页查询(注意:雷同部分略)
1 Dao层
package com.mapper.neo4jdao.model;
public interface BdAppDao {
int getTotalBdApp(String cypher,Map<String,String> params);
PageResult getBdAppPage(BdApp domain,Integer currPage, Integer pagesize);
}
2 Dao 实现层
package com.mapper.neo4jdao.model.Impl;
@Repository
public class BdAppDaoImpl implements BdAppDao {
@Autowired
Session session;
//查询前缀
private static final String QUERY_PREFFIX = "MATCH (bdApp:BdApp) ";
private static final String QUERY_WHERE = " WHERE 1 = 1 ";
@Override
public int getTotalBdApp(String cypher,Map<String,String> params) {
return DaoUtil.getTotalNum(session,cypher,params);
}
@Override
public PageResult getBdAppPage(BdApp bdApp,Integer page, Integer pagesize) {
PageResult pr = new PageResult();
Map<String,String> params = new HashMap<>();
StringBuffer cypherbuf = new StringBuffer(this.midCypher(domain,params));//需要修改下
if(StringUtils.isEmpty(cypherbuf)){
return pr;
}
int totalnum = this.getTotalBdApp(cypherbuf+" RETURN count(c) as count",params);
pr.setToltalsize(totalnum);
pr.setPage(page);
pr.setPagesize(pagesize);
page = page==null|page<1?1:page;
pagesize = pagesize == null | pagesize <1 ? 10:pagesize;
int skip = (page-1)*(totalnum/pagesize);
int limit = pagesize;
cypherbuf.append(" RETURN c");
cypherbuf.append(" SKIP ");
cypherbuf.append(skip);
cypherbuf.append(" LIMIT ");
cypherbuf.append(limit);
Iterable<BdApp> its = session.query(BdApp.class,cypherbuf.toString(),params);
if(its==null)return pr;
List<BdApp> results = new ArrayList<>();
its.forEach((v)->results.add(v));
pr.addData(results);
return pr;
}
}
3 分页基础类-
DaoUtil,统计总记录数
public class DaoUtil {
private DaoUtil(){}
public static int getTotalNum(Session session,String cypher,Map<String,String> params){
Result result = session.query(cypher,params);
int totalnum = 0;
if(result==null)return totalnum;
Iterator<Map<String,Object>> its = result.iterator();
while (its.hasNext()){
Map<String,Object> ret = its.next();
if(ret!=null){
Object nums = ret.getOrDefault("count",0);
if( nums != null ){
totalnum = Integer.parseInt(nums.toString());
break;
}
}
}
return totalnum;
}
}