Neo4J 安裝&常見語句操作&項目中的集成應用&複雜查詢(@Query註解和自定義Match)

I 安裝Neo4J
1 準備工作
    1.1 下載安裝包--bin--Neo4J-ce.exe,執行Start
1.2 訪問 http://localhos:7474/browser/

II 常見語句操作
刪除節點
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 項目中的集成應用
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:
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;

***********************************************************************************
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;
    }
}




發佈了89 篇原創文章 · 獲贊 54 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章