`
weitao1026
  • 浏览: 1048624 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

首先简单介绍下Neo4j,Neo4j是一个高性能的NOSQL图形数据库,它将结构化数据存储在网络上而不是表中,它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)而不是表中。Neo4j也可以被看做是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。

Neo4j中涉及到几个关键的实体对象,分别是Node(节点)、Relationship(关系)、Path(路径)、Direction(关系方向)、RelationshipType(关系类型)。朋友们可以将Relationship(关系)看做是连接线,一条连接线每端只能连接一个Node(节点),并且连接线两端必须同时都连接有Node(节点);Relationship(关系)具有方向和类型特性。Node(节点)可以通过多Relationship(关系)与其他多个Node(节点)关联,而且Node(节点)也可以是没有任何连接的孤立节点。Path(路径)包含多个Node和Relationship,是节点和关系的集合。下图就是笔者本人利用Neo4j构建的一个“射雕英雄谱”局部关系图:

neo4j_graph

 

3.1. Neo4j数据分页检索类型

Neo4j数据分页检索接口采用自身的Cypher检索语句,通过构建Cypher分页检索语句,实现分页处理。

Neo4j数据库中不存在传统的表的概念,一个数据库可以视作一张图。数据分页检索将针对Node和Relationship分别进行,不针对Path进行分页检索,因为基本上没有什么意义。按照检索条件区分检索类型,可以细分为以下几种。

3.1.1 Node(节点)分页检索

1) 无条件检索Cypher语句

--不根据属性排序
START n=node(*) RETURN n SKIP 0 LIMIT 20

--根据属性排序
START n=node(*) RETURN n ORDER BY n.NAME DESC SKIP 0 LIMIT 20

2) 根据Property属性检索Cypher语句

--根据属性NAME值进行模糊检索
START n=node(*) WHERE n.NAME=~'.*tom*' RETURN n SKIP 0 LIMIT 20

--根据属性NAME值进行精确检索
START n=node(*) WHERE n.NAME='tom' RETURN n SKIP 0 LIMIT 20

3) 根据Index索引检索Cypher语句

复制代码
--说明:N_INDEX为索引名称,USER_NAME为索引Key名称

--根据索引值进行模糊检索
--模糊检索的多种格式。
--1、*tom*表示USER_NAME中包含tom字符串的
--2、*tom表示USER_NAME右侧匹配tom字符串的
--3、tom*表示USER_NAME左侧匹配tom字符串的
START n=node:N_INDEX('USER_NAME:*tom*') RETURN n SKIP 0 LIMIT 20

--根据索引值进行精确检索
START n=node:N_INDEX (USER_NAME='tom') RETURN n SKIP 0 LIMIT 20
复制代码

4) 根据Index索引和Property属性检索Cypher语句

复制代码
--根据索引(模糊)和属性(模糊)检索
START n=node:N_INDEX('USER_NAME:*tom*') WHERE n.USER_TYPE=~'.*sys*' RETURN n SKIP 0 LIMIT 20

--根据索引(模糊)和属性(精确)检索
START n=node:N_INDEX('USER_NAME:*tom*') WHERE n.USER_TYPE ='system' RETURN n SKIP 0 LIMIT 20

--根据索引(精确)和属性(模糊)检索
START n=node:N_INDEX(USER_NAME='tom') WHERE n.USER_TYPE=~'.*sys*' RETURN n SKIP 0 LIMIT 20

--根据索引(精确)和属性(精确)检索
START n=node:N_INDEX(USER_NAME='tom') WHERE n.USER_TYPE ='system' RETURN n SKIP 0 LIMIT 20
复制代码

5) 根据Label标签检索Cypher语句

--标签内容为”中国”
START n=node(*) MATCH (n:中国) RETURN n SKIP 0 LIMIT 20

6) 根据Label标签和Property属性检索Cypher语句

START n=node(*) MATCH (n:中国) WHERE n.USER_TYPE=’system’ RETURN n SKIP 0 LIMIT 20
 
 
3.1.2 Relationship(关系)分页检索

1) 无条件分页检索Cypher语句

--不根据属性排序
START r=relationship(*) RETURN DISTINCT(r) SKIP 0 LIMIT 20

--根据属性排序
START r=relationship(*) RETURN DISTINCT(r) ORDER BY r.NAME ASC SKIP 0 LIMIT 20

2) 根据Property属性检索Cypher语句

--根据属性NAME值进行模糊检索
START r=relationship(*) WHERE r.NAME=~'.*tom*' RETURN r SKIP 0 LIMIT 20

--根据属性NAME值进行精确检索
START r=relationship(*) WHERE r.NAME='tom' RETURN r SKIP 0 LIMIT 20

3) 根据Index索引检索Cypher语句

复制代码
--说明:R_INDEX为索引名称,USER_NAME为索引Key名称

--根据索引值进行模糊检索
--模糊检索的多种格式。
--1、*tom*表示USER_NAME中包含tom字符串的
--2、*tom表示USER_NAME右侧匹配tom字符串的
--3、tom*表示USER_NAME左侧匹配tom字符串的
START r=relationship(*):R_INDEX('USER_NAME:*tom*') RETURN r SKIP 0 LIMIT 20

--根据索引值进行精确检索
START r=relationship(*):R_INDEX (USER_NAME='tom') RETURN r SKIP 0 LIMIT 20
复制代码

4) 根据Index索引和Property属性检索Cypher语句

复制代码
--根据索引(模糊)和属性(模糊)检索
START r=relationship(*):R_INDEX('USER_NAME:*tom*') WHERE r.USER_TYPE=~'.*sys*' RETURN r SKIP 0 LIMIT 20

--根据索引(模糊)和属性(精确)检索
START r=relationship(*):R_INDEX('USER_NAME:*tom*') WHERE r.USER_TYPE ='system' RETURN r SKIP 0 LIMIT 20

--根据索引(精确)和属性(模糊)检索
START r=relationship(*):R_INDEX(USER_NAME='tom') WHERE r.USER_TYPE=~'.*sys*' RETURN r SKIP 0 LIMIT 20

--根据索引(精确)和属性(精确)检索
START r=relationship(*):R_INDEX(USER_NAME='tom') WHERE r.USER_TYPE ='system' RETURN r SKIP 0 LIMIT 20
复制代码

5) 根据RelationshipType关系类型检索Cypher语句

--FRIEND为关系类型字符串
START n=node(*) MATCH n-[r:FRIEND]-() RETURN DISTINCT(r) SKIP 0 LIMIT 20

 

3.2. Neo4j数据分页模型类

复制代码
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import com.hnepri.common.util.LogInfoUtil;
/**
 * Description: 图数据库数据分页模型类。<br>
 * 利用此类可分页管理Node数据和Relationship数据等。
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GraphPageModel implements Serializable {
    private static final long serialVersionUID = 330410716100946538L;
    private int pageSize = 10;
    private int pageIndex = 1;
    private int prevPageIndex = 1;
    private int nextPageIndex = 1;
    private int pageCount = 0;
    private int pageFirstRowIndex = 1;
    private boolean hasNextPage = true;
    private int totalCount = 0;
    private long startTime = System.currentTimeMillis();
    private long endTime = System.currentTimeMillis();
    private List<Node> nodeList = new ArrayList<Node>();
    private List<Relationship> relationshipList = new ArrayList<Relationship>();
    /**
     * 分页对象构造函数
     * @param pageSize 每页记录数
     */
    public GraphPageModel(int pageSize) {
        this.pageSize = pageSize;
    }
    /**
     * 获取分页记录数量
     * @return
     */
    public int getPageSize() {
        return pageSize;
    }
    /**
     * 获取当前页序号
     * @return
     */
    public int getPageIndex() {
        return pageIndex;
    }
    /**
     * 设置当前页序号
     * @param pageIndex
     */
    public void setPageIndex(int pageIndex) {
        if(pageIndex <= 0) {
            pageIndex = 1;
        }
        this.pageIndex = pageIndex;
    }
    /**
     * 获取分页总数
     * @return
     */
    public int getPageCount() {
        if(this.getTotalCount() == 0) {
            this.pageCount = 0;
        } else {
            int shang = this.getTotalCount() / this.getPageSize();
            int yu = this.getTotalCount() % this.getPageSize();
            if(yu > 0) {
                shang += 1;
            }
            this.pageCount = shang;
        }
        return pageCount;
    }
    /**
     * 获取每页的第一行序号
     * @return
     */
    public int getPageFirstRowIndex() {
        this.pageFirstRowIndex = (this.pageIndex - 1) * this.getPageSize() + 1;
        return pageFirstRowIndex;
    }
    /**
     * 获取上一页序号
     * @return
     */
    public int getPrevPageIndex() {
        if(this.pageIndex > 1) {
            this.prevPageIndex = this.pageIndex - 1;
        } else {
            this.prevPageIndex = 1;
        }
        return prevPageIndex;
    }
    /**
     * 获取下一页序号
     * @return
     */
    public int getNextPageIndex() {
        if(this.pageIndex < this.pageCount) {
            this.nextPageIndex = this.pageIndex + 1;    
        } else {
            this.nextPageIndex = this.pageCount;
        }
        return nextPageIndex;
    }
    /**
     * 跳转到下一页
     */
    public void nextPage() {
        if(this.totalCount == 0 || this.getPageCount() == 0) {
            this.pageIndex = 1;
        } else {
            if(this.pageIndex < this.pageCount) {
                this.pageIndex = this.pageIndex + 1;    
            } else {
                this.pageIndex = this.pageCount;
            }
        }
    }
    /**
     * 跳转到上一页
     */
    public void prevPage() {
        if(this.pageIndex > 1) {
            this.pageIndex = this.pageIndex - 1;
        } else {
            this.pageIndex = 1;
        }
    }
    /**
     * 获取是否有下一页
     * @return
     */
    public boolean isHasNextPage() {
        if(this.pageIndex < this.getPageCount()) {
            this.hasNextPage = true;
        } else {
            this.hasNextPage = false;
        }
        return hasNextPage;
    }
    /**
     * 获取总记录数    
     */
    public int getTotalCount() {
        return totalCount;
    }
    /**
     * 获取总记录数    
     * @param totalCount
     */
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
    /**
     * 初始化起始时间(毫秒)
     */
    public void initStartTime() {
        this.startTime = System.currentTimeMillis();
    }
    /**
     * 初始化截止时间(毫秒)
     */
    public void initEndTime() {
        this.endTime = System.currentTimeMillis();
    }
    /**
     * 获取毫秒格式的耗时信息
     * @return
     */
    public String getTimeIntervalByMilli() {
        return String.valueOf(this.endTime - this.startTime) + "毫秒";
    }
    /**
     * 获取秒格式的耗时信息
     * @return
     */
    public String getTimeIntervalBySecond() {
        double interval = (this.endTime - this.startTime)/1000.0;
        DecimalFormat df = new DecimalFormat("#.##");
        return df.format(interval) + "秒";
    }
    /**
     * 打印时间信息
     */
    public void printTimeInfo() {
        LogInfoUtil.printLog("起始时间:" + this.startTime);
        LogInfoUtil.printLog("截止时间:" + this.endTime);
        LogInfoUtil.printLog("耗费时间:" + this.getTimeIntervalBySecond());
    }
    /**
     * 获取Node检索结果列表
     * @return
     */
    public List<Node> getNodeList() {
        return nodeList;
    }
    /**
     * 获取Relationship检索结果列表
     * @return
     */
    public List<Relationship> getRelationshipList() {
        return relationshipList;
    }
}
复制代码

模型类中,nodeList和relationshipList分别用来存放Node和Relationship;分页检索Node时,就通过getNodeList()读取Node信息;分页检索Relationship时,就通过getRelationshipList()读取Relationship信息。

 

 

 

 

 

 

 

 

 

3.3. Neo4j数据分页接口方法

首先,我们先设计一个通用的执行Cypher检索语句的接口方法,将检索结果(主要指Node、Relationship和Path对象)封转进Propertyies列表中。

复制代码
/**
 * 执行Cypher检索语句,将检索结果封装进Properties列表中。
 * @param query cypher检索语句
 * @param params cypher检索语句参数集合
 * @return
 */
public List<Properties> executeQuery(String query, Map<String,Object> params) {
    List<Properties> propertiesList = new ArrayList<Properties>();
    if(StringUtils.isBlank(query)) {
        return propertiesList;
    }
    ExecutionEngine executionEngine = new ExecutionEngine(this.getGraphDatabaseService());
    ExecutionResult result = null;
    if(params == null || params.size() == 0) {
        result = executionEngine.execute(query);
    } else {
        result = executionEngine.execute(query, params);
    }
    for (Map<String, Object> row : result ) {
        Properties properties = new Properties();
        for ( Entry<String, Object> column : row.entrySet()){
            properties.put(column.getKey(), column.getValue());
        }
        propertiesList.add(properties);
    }
    return propertiesList;
}
复制代码

下面以无条件分页检索Node信息为例,讲述下接口方法的设计思路。具体代码如下:

复制代码
/**
 * 分页检索Node信息。
 * @param pageModel 分页模型对象,不能为空。
 * @param orders 排序属性字段。
 * @return
 */
public GraphPageModel queryNodes(GraphPageModel pageModel, GOrderBy ... orders) {
    if(pageModel == null) {
        pageModel = new GraphPageModel(10);
    }
    pageModel.getNodeList().clear();
    pageModel.getRelationshipList().clear();
    
    //计算总行数
    String query = "START n=node(*) RETURN count(*) AS NODE_COUNT";
    List<Properties> resultList = this.executeQuery(query);
    if(resultList == null || resultList.size() == 0) {
        return pageModel;
    }
    for(Properties properties : resultList) {
        int nodeCount = Integer.valueOf(properties.get("NODE_COUNT").toString());
        pageModel.setTotalCount(nodeCount);
    }
    
    //组织排序字段信息
    String strGOrderBy = "";
    if(orders != null && orders.length > 0) {
        strGOrderBy = "ORDER BY";
        for(GOrderBy order : orders) {
            strGOrderBy += String.format(" n.%s %s,", order.getPropertyName(), order.getOrderType().toUpperCase());
        }
        strGOrderBy = strGOrderBy.substring(0, strGOrderBy.length() - 1);
    }
    
    int skipCount = (pageModel.getPageIndex() - 1) * pageModel.getPageSize();
    int limitCount = pageModel.getPageSize();
    query = String.format("START n=node(*) RETURN n AS NODE_ENTRY %s SKIP %s LIMIT %s", strGOrderBy, skipCount, limitCount);
    List<Properties> list = this.executeQuery(query);
    for(Properties properties : list) {
        pageModel.getNodeList().add((Node)properties.get("NODE_ENTRY"));
    }
    
    return pageModel;
}
复制代码
分享到:
评论

相关推荐

    neo4j学习资料汇总(各种优质博文和neo4j教程整理)

    neo4j api neo4j学习资料 neo4j教程 │ neo4j官方API(官方各种API的文档整理).7z │ neo4j数据迁移--初探(一).htm ... │ 数据分页处理系列之三:Neo4j图数据分页处理.html │ 暖暖动听.html │ 飘涯 - 简书.html

    Neo4j Ogm Manual 2.0

    - **排序与分页**:支持查询结果的排序和分页功能,以便更好地处理大量数据。 - **HA环境下的配置**:描述了如何在高可用环境中配置Neo4j OGM,以实现故障转移和负载均衡。 #### 十、兼容性和多驱动支持 - **兼容性...

    Neo4j+springboot+vue+d3.js知识图谱构建和可视化

    Neo4j提供Cypher查询语言,便于查询和操作图数据,同时其ACID事务保证数据一致性。 **2. SpringBoot - 后端开发框架** SpringBoot是基于Spring框架的快速开发工具,简化了Java应用程序的搭建和配置。在知识图谱项目...

    Excle通过JDBC插入Neo4j数据库后Echars展示(初版)

    在实际应用中,为了提高性能和用户体验,可能还需要考虑数据分页加载、异步处理、错误处理以及用户界面设计等因素。同时,优化数据库查询和数据结构设计也是提升系统效率的关键。总的来说,这个项目结合了数据处理、...

    SpringBoot整合mybatis-plus实现多数据源的动态切换且支持分页查询.pdf

    在SpringBoot项目中,整合Mybatis-Plus并实现多数据源的动态切换,同时支持分页查询是一项常见的需求。以下将详细阐述这个过程中的关键步骤和技术要点。 首先,我们需要引入必要的Maven依赖。这里提到了四个关键...

    mybatis 集成图数据库neo4j功能实现

    在当前的大数据时代,图数据库因其独特的数据模型和高效的数据处理能力,在许多领域展现出巨大的优势。Neo4j 作为一款知名的图数据库产品,被广泛应用于社交网络分析、推荐系统、知识图谱等领域。而 MyBatis 作为一...

    人工智能-项目实践-信息检索-标注系统的后端python代码,主要是针对mongdb和neo4j的一些基本操作,检索和返回数据格

    这可能涉及到查询优化、相关性排序以及分页处理等技术。例如,使用MongoDB的`aggregate()`函数进行聚合操作,对查询结果进行过滤、排序和分组。在图数据库中,利用Neo4j的短路径查找算法(如Floyd-Warshall或...

    neo4j-cypher-refcard-2.1.4

    Cypher设计用于直观地表达图形数据的模式,并高效地处理图形结构的查询。通过Cypher,开发者可以使用简明的语法来创建、读取、更新和删除图形数据库中的节点(Nodes)、关系(Relationships)、标签(Labels)和属性...

    mybatis基础分页,高级查询

    在描述中提到了简单的 Servlet,这可能意味着项目使用了传统的 MVC 架构,Servlet 用于接收和处理客户端请求,并调用 MyBatis 进行数据操作。 高级查询是 MyBatis 的一大亮点。通过动态 SQL,开发者可以在映射文件...

    毕业设计 基于springboot知识图谱(Neo4j)的科技政策管理系统源码+详细文档+全部数据资料(高分项目).zip

    Redis统一缓存处理,提高系统性能和用户满意度,Hanlp文本处理并构建科技政策知识图谱网络图。 系统架构分为四个层次,分别为用户访问层、业务应用层、服务支撑层和数据存储层。用户层按用户的权限将用户分为三类,...

    mysql的建立连接,读取数据

    事务处理和错误处理也是数据库开发中不可忽视的部分,它们确保数据的一致性和安全性。 总的来说,通过理解如何在MySQL中建立连接、执行查询和处理结果,你可以开始进行更复杂的数据库操作。`SqlTest`可能是这样一个...

    NoSQL深入分析

    NoSQL,全称为Not Only SQL,是一种非关系型数据库,其设计目的是为了处理现代互联网应用中的大规模数据存储和高并发访问需求。随着Web2.0时代的到来,传统的SQL关系数据库在处理这些问题上显得力不从心,从而催生了...

    Laravel开发-neoeloquent

    Neo4J是一款领先的图形数据库,它的核心特性在于通过节点、关系和属性来存储和查询数据,特别适合处理复杂的数据关联和网络结构。相比传统的关系型数据库,如MySQL或PostgreSQL,Neo4J在处理社交网络、推荐系统、...

    浅谈Spring Data如何简化数据操作的方法

    首先,Spring Data支持多种NoSQL数据库,例如MongoDB(文档数据库)、Neo4j(图形数据库)、Redis(键/值存储)和Hbase(列族数据库),同时也支持关系数据存储技术,如JDBC和JPA。对于JPA支持,Spring Data JPA提供...

    SpringData数据层全栈方案高级应用Java代码.zip

    在处理大数据量时,SpringData提供了分页和排序功能。只需在查询方法中添加Pageable参数,即可实现分页查询,同时支持自定义排序规则。 7. **事件监听**: SpringData支持实体级别的生命周期事件监听,如`@...

    基于springboot+知识图谱的数字图书馆系统.zip

    在数字图书馆系统中,SpringBoot扮演了基础架构的角色,负责处理请求、数据持久化、服务层逻辑等。它的优点包括自动配置、内置Tomcat服务器、简化Maven配置等,使得开发过程更为高效和简洁。 二、知识图谱技术 知识...

    SpringData的使用

    SpringData是Spring框架的一个重要模块,它为各种数据存储提供了统一的访问接口,极大地简化了数据...结合快速分页功能,使得在处理大量数据时更加高效。在实际开发中,善用SpringData可以提高代码质量,降低维护成本。

    Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页示例

    2. 在SpringMVC中创建控制器(Controller),定义处理请求的方法,并使用Spring Data JPA的Repository接口来获取分页数据。 3. 使用Jquery.pagination.js插件,并通过Ajax请求从后端获取分页数据,动态更新页面上的...

    SpringData入门到精通

    它支持JPA(Java Persistence API)、MongoDB、Neo4j等数据存储,降低了学习和使用不同数据库系统的难度。在“HelloWorld”阶段,你将了解如何配置SpringData项目,创建Repository接口,并实现简单的数据查询功能。 ...

    Spring Data实战

    Spring Data可以同时处理多个数据源,这对于分布式系统和微服务架构非常有用。 13. **Spring Data JDBC** Spring Data JDBC提供了对传统JDBC的封装,使得使用JDBC进行数据库操作也能享受到Spring Data带来的便利...

Global site tag (gtag.js) - Google Analytics