Neo4j图数据库应用开发之一:Neo4j Java 工具包

1 应用开发概述

基于数据传输效率以及接口自定义等特殊性需求,我们暂时放弃使用Neo4j服务器版本,而是在Neo4j嵌入式版本的基础上进行一些封装性的开发。封装的重点,是解决Neo4j嵌入式版本EmbeddedGraphDatabase中不能同时创建多个实例指向同一个数据库的问题。如果开发人员使用Neo4j嵌入式版本作为数据库,要想实现多个程序共享一个数据库,这将是一个不可回避的问题。本手册给出的解决方案是“构建一个中间服务层,提供各种接口方法,指向同一个数据库实例;其他客户端程序通过中间服务层与Neo4j嵌入式数据库进行通信”。因为我们已经从Neo4j官方声明中得知:Neo4j嵌入式实例可以在多个线程中共享。

系统框架如下图所示:

  • Neo4j Java 工具包

Neo4j Java 工具包是对Neo4j嵌入式版本Java API的二次封装,根据业务类型划分为Node(Relationship)、Index、Path和Cypher等四种工具集。

  • 管理工具Server端

之所以称其为Server端,是因为其中包含了对RMI Server的管理。此管理工具的主要功能包括图数据库信息管理(包括新建、删除、统计图数据库等)、图数据库数据管理(包括Node数据管理、Relationship数据管理等)、数据导入导出(包括Neo4j与oracle、mysql和excel等之间的数据转换)、RMI Server监控管理等。

管理工具Server端只能部署在Neo4j数据库服务器上,并且只能部署一套程序,否则将违背Neo4j图数据库单例的原则。

  • RMI Service(服务)

RMI Server(服务),是在Neo4j Java 工具包的基础上,设计的一套接口服务,分为Server端和Client端。Server端用于接口方法的实现和监控管理,Client端用于接口方法的定义和分发(供其他外部系统使用)。总体设计思路,是将Neo4j中的关键对象(Node、Relationship、Path、Direction等)进行可序列化的封装,通过远程调用服务返回给客户端使用。

  • 管理工具Client端

管理工具Client端,是基于RMI Client设计的Neo4j数据管理工具,主要功能包括图数据库信息查看功能、图数据库数据管理功能、数据导入导出功能等。管理工具Client端可以部署多套。

2 Neo4j Java 工具包

以上所有功能(工具包、RMI Service以及管理工具)都包含在两个Java项目中,项目结构如下图所示:

hnepri-neo4j-common为工具包项目,包括Neo4j Java 工具包、RMI Server端和管理工具Server端;hnepri-neo4j-client为客户端项目,包括RMI Client端和管理工具Client端。

下面主要介绍Neo4j Java 工具包的几个封装关键点,其中,下图为各个工具类之间的关联效果图。

2.1 Node操作工具类(GraphNodeUtil)

Node操作工具类的主要功能包括Node节点和Relationship关系的创建、编辑、删除、查询,以及Label和Property的管理等。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:

2.2 Index操作工具类(GraphIndexUtil)

Index操作工具类的主要功能包括Node和Relationship相关索引信息的创建、编辑、删除、查询,以及基于索引查询Node节点和Relationship关系等。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:

2.3 Path操作工具类(GraphPathUtil)

Path操作工具类的主要功能包括针对Path的检索操作,包括路径深度遍历、两点之间路径寻址等接口方法。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:

2.4 Cypher操作工具类(GraphCypherUtil)

Cypher操作工具类是对Cypher查询语言的封装,主要包括针对Node、Relationship和Path的自定义查询操作。另外,也包括了多种方式的分页查询。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。

其中,最基本的接口方法是executeQuery方法,执行Cypher查询语句,将查询结果以Properties的形式存在在List中,然后再由其他接口方法显式地转换为Node、Relationship、Path或者其他基本类型使用。

 1        /**
 2      * 执行Cypher查询语句,将检索结果封装进Properties列表中。
 3      * @param query cypher查询语句
 4      * @param params cypher查询语句参数集合
 5      * @return
 6      */
 7     public List<Properties> executeQuery(String query, Map<String,Object> params) {
 8         GraphTimerModel timer = GraphTimerModel.create();
 9         List<Properties> propertiesList = new ArrayList<Properties>();
10         if(StringUtils.isBlank(query)) {
11             return propertiesList;
12         }
13         ExecutionResult result = null;
14         if(params == null || params.size() == 0) {
15             result = this.getExecutionEngine().execute(query);
16         } else {
17             result = this.getExecutionEngine().execute(query, params);
18         }
19         LogInfoUtil.printLog(query);
20
21         for (Map<String, Object> row : result ) {
22             Properties properties = new Properties();
23             for ( Entry<String, Object> column : row.entrySet()){
24                 properties.put(column.getKey(), column.getValue());
25             }
26             propertiesList.add(properties);
27         }
28         timer.initEndTime();
29         timer.printTimeInfo();
30         return propertiesList;
31     }
32     举例如下所示:
33     String query = "START n=node(*) WHERE n.name=’tom’ RETURN n AS NODE_ENTRY";
34     List<Properties> list = this.executeQuery(query);
35     for(Properties properties : list) {
36         nodeList.add((Node)properties.get("NODE_ENTRY"));
37     }

相关接口方法截图如下所示:

2.5 动态生成RelationshipType(GraphRelTypeUtil)

动态生成RelationshipType是构建RMI服务必须首先要解决的一个关键点,因为RMI要求Server端与Client端之间的传输对象必须是可序列化的对象,而Neo4j API中的接口类和枚举是无法真正序列化的,这也是我们在RMI Service中对相关实体进行封装的根本原因。

所谓动态生成RelationshipType,就是可根据字符串类型的关系类型,生成符合Neo4j Java API要求的枚举类型RelationshipType。关键代码如下表所示:

  1 package com.hnepri.neo4j.common.util;
  2
  3 import java.lang.reflect.AccessibleObject;
  4 import java.lang.reflect.Array;
  5 import java.lang.reflect.Field;
  6 import java.lang.reflect.Modifier;
  7 import java.util.ArrayList;
  8 import java.util.Arrays;
  9 import java.util.HashMap;
 10 import java.util.Iterator;
 11 import java.util.List;
 12 import java.util.Map;
 13
 14 import org.apache.commons.lang3.StringUtils;
 15 import org.neo4j.graphdb.GraphDatabaseService;
 16 import org.neo4j.graphdb.RelationshipType;
 17 import org.neo4j.graphdb.Transaction;
 18
 19 import sun.reflect.ConstructorAccessor;
 20 import sun.reflect.FieldAccessor;
 21 import sun.reflect.ReflectionFactory;
 22
 23 /**
 24  * Description: 图数据库关系类型工具类。<br>
 25  * 1、可根据关系类型名称字符串动态生成关系类型枚举。<br>
 26  * 2、可管理动态生成的关系类型枚举列表。
 27  * Copyright: Copyright (c) 2015<br>
 28  * Company: 河南电力科学研究院智能电网所<br>
 29  * @author shangbingbing 2015-11-01编写
 30  * @version 1.0
 31  */
 32 public class GraphRelTypeUtil {
 33
 34     /**
 35      * 构造函数。<br>
 36      * 初始化对应的图数据库服务对象实例。
 37      * @param graphDBService
 38      */
 39     public GraphRelTypeUtil(GraphDatabaseService graphDBService) {
 40         this.graphDBService = graphDBService;
 41     }
 42
 43     private GraphDatabaseService graphDBService = null;
 44     /**
 45      * 获取对应的图数据库服务对象实例。
 46      * @return
 47      */
 48     public GraphDatabaseService getGraphDBService() {
 49         return this.graphDBService;
 50     }
 51
 52     /**
 53      * 构建事务。
 54      * @return
 55      */
 56     public Transaction createTransaction() {
 57         return this.getGraphDBService().beginTx();
 58     }
 59
 60     private GraphIndexUtil indexManager = null;
 61     /**
 62      * 获取图数据库索引信息管理器。
 63      * @return
 64      */
 65     public GraphIndexUtil getIndexManager() {
 66         if(this.indexManager == null) {
 67             this.indexManager = new GraphIndexUtil(this.getGraphDBService());
 68         }
 69         return this.indexManager;
 70     }
 71
 72     private Map<String,RelationshipType> relationshipTypeList = null;
 73     /**
 74      * 获取已动态生成的关系枚举类型列表。
 75      * @return
 76      */
 77     @SuppressWarnings("deprecation")
 78     public Map<String, RelationshipType> getRelationshipTypeList() {
 79         if(this.relationshipTypeList == null) {
 80             this.relationshipTypeList = new HashMap<String, RelationshipType>();
 81
 82             Iterator<RelationshipType> iterator = this.getGraphDBService().getRelationshipTypes().iterator();
 83             while(iterator.hasNext()) {
 84                 RelationshipType relType = iterator.next();
 85                 String relTypeName = relType.name();
 86                 this.relationshipTypeList.put(relTypeName, relType);
 87             }
 88         }
 89         return this.relationshipTypeList;
 90     }
 91
 92     /**
 93      * 根据关系类型名称动态生成图数据库关系枚举类型。
 94      * @param relTypeName
 95      * @return
 96      */
 97     public RelationshipType create(String relTypeName) {
 98         if(StringUtils.isBlank(relTypeName)) {
 99             return null;
100         }
101         if(this.getRelationshipTypeList().containsKey(relTypeName) == false) {
102             addEnum(relTypeName);
103             RelationshipType relType = RelationshipTypeEnum.valueOf(relTypeName);
104             this.getRelationshipTypeList().put(relTypeName, relType);
105             return relType;
106         } else {
107             return this.getRelationshipTypeList().get(relTypeName);
108         }
109     }
110
111     /**
112      * 根据关系类型名称,获取对应的关系枚举类型。
113      * @param relTypeName
114      * @return
115      */
116     public RelationshipType get(String relTypeName) {
117         if(StringUtils.isBlank(relTypeName)) {
118             return null;
119         }
120         return this.create(relTypeName);
121     }
122
123     /**
124      * 根据关系类型名称,删除对应的关系枚举类型。
125      * @param relTypeName
126      * @return
127      */
128     public void remove(String relTypeName) {
129         if(this.getRelationshipTypeList().containsKey(relTypeName)) {
130             this.getRelationshipTypeList().remove(relTypeName);
131         }
132     }
133
134     /**
135      * 根据关系类型名称列表,初始化关系类型枚举列表。
136      * @param relTypeNameList
137      */
138     public void init(List<String> relTypeNameList) {
139         if(relTypeNameList == null || relTypeNameList.size() == 0) {
140             return;
141         }
142         for(String relTypeName : relTypeNameList) {
143             create(relTypeName);
144         }
145     }
146
147     private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
148
149     private static void setFailsafeFieldValue(Field field, Object target, Object value) throws NoSuchFieldException,IllegalAccessException {
150         field.setAccessible(true);
151         Field modifiersField = Field.class.getDeclaredField("modifiers");
152         modifiersField.setAccessible(true);
153         int modifiers = modifiersField.getInt(field);
154
155         modifiers &= ~Modifier.FINAL;
156         modifiersField.setInt(field, modifiers);
157
158         FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
159         fa.set(target, value);
160     }
161
162      private static void blankField(Class<?> enumClass, String fieldName) throws NoSuchFieldException, IllegalAccessException {
163          for (Field field : Class.class.getDeclaredFields()) {
164              if (field.getName().contains(fieldName)) {
165                  AccessibleObject.setAccessible(new Field[] { field }, true);
166                  setFailsafeFieldValue(field, enumClass, null);
167                  break;
168              }
169         }
170     }
171
172     private static void cleanEnumCache(Class<?> enumClass) throws NoSuchFieldException, IllegalAccessException {
173         blankField(enumClass, "enumConstantDirectory");
174         blankField(enumClass, "enumConstants");
175     }
176
177     private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes) throws NoSuchMethodException {
178         Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
179         parameterTypes[0] = String.class;
180         parameterTypes[1] = int.class;
181         System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
182         return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));
183     }
184
185     private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception {
186         Object[] parms = new Object[additionalValues.length + 2];
187         parms[0] = value;
188         parms[1] = Integer.valueOf(ordinal);
189         System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
190         return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
191     }
192
193     @SuppressWarnings("unchecked")
194     private static <T extends Enum<?>> void addEnum(String enumName) {
195          if (!Enum.class.isAssignableFrom(RelationshipTypeEnum.class)) {
196              throw new RuntimeException("class " + RelationshipTypeEnum.class + " is not an instance of Enum");
197          }
198
199          Field valuesField = null;
200          Field[] fields = RelationshipTypeEnum.class.getDeclaredFields();
201          for (Field field : fields) {
202              if (field.getName().contains("$VALUES")) {
203                  valuesField = field;
204                  break;
205              }
206          }
207          AccessibleObject.setAccessible(new Field[] { valuesField }, true);
208
209          try {
210
211              T[] previousValues = (T[]) valuesField.get(RelationshipTypeEnum.class);
212              List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
213
214              T newValue = (T) makeEnum(RelationshipTypeEnum.class, enumName, values.size(), new Class<?>[] {}, new Object[] {});
215              values.add(newValue);
216              setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(RelationshipTypeEnum.class, 0)));
217              cleanEnumCache(RelationshipTypeEnum.class);
218          } catch (Exception e) {
219              e.printStackTrace();
220              throw new RuntimeException(e.getMessage(), e);
221          }
222     }
223 }
224
225 /**
226  * Description: 图数据库关系类型枚举。
227  * Copyright: Copyright (c) 2015<br>
228  * Company: 河南电力科学研究院智能电网所<br>
229  * @author shangbingbing 2015-11-01编写
230  * @version 1.0
231  */
232 enum RelationshipTypeEnum implements RelationshipType {
233     NONE
234 }

2.6 图数据库操作模板工具类(GraphTemplateUtil)

图数据库操作模板工具类,主要负责对以上工具集的组织和调用管理,以保证开发人员在调用习惯上遵循Neo4j嵌入式图数据库单例服务的原则。关键代码如下表所示:

  1 package com.hnepri.neo4j.common.util;
  2
  3 import java.io.File;
  4 import java.util.HashMap;
  5 import java.util.Map;
  6
  7 import org.apache.commons.lang3.StringUtils;
  8 import org.neo4j.graphdb.GraphDatabaseService;
  9 import org.neo4j.graphdb.Transaction;
 10 import org.neo4j.graphdb.factory.GraphDatabaseFactory;
 11 import org.neo4j.io.fs.FileUtils;
 12
 13 import com.hnepri.neo4j.client.form.graph.bean.GraphConfigOption;
 14 import com.hnepri.neo4j.form.graph.util.GraphManageUtil;
 15
 16 /**
 17  * Description: Neo4j图数据库操作模板类。<br>
 18  * Copyright: Copyright (c) 2015<br>
 19  * Company: 河南电力科学研究院智能电网所<br>
 20  * @author shangbingbing 2015-11-01 编写
 21  * @version 1.0
 22  */
 23 public class GraphTemplate {
 24
 25     private String graphDBPath = "";
 26     /**
 27      * 获取图数据库路径。
 28      * @return
 29      */
 30     public String getGraphDBPath() {
 31         return graphDBPath;
 32     }
 33     private GraphDatabaseService graphDBService = null;
 34     /**
 35      * 获取图数据库服务实例对象。
 36      * @return
 37      */
 38     public GraphDatabaseService getGraphDBService() {
 39         if(StringUtils.isBlank(this.getGraphDBPath())) {
 40             try {
 41                 throw new Exception("警告:没有配置图数据库路径信息!");
 42             } catch (Exception e) {
 43                 e.printStackTrace();
 44             }
 45         }
 46         if(this.graphDBService == null) {
 47             this.graphDBService = new GraphDatabaseFactory().newEmbeddedDatabase(this.getGraphDBPath());
 48             registerShutdownHook();
 49         }
 50         return this.graphDBService;
 51     }
 52
 53     /**
 54      * 清除图数据库数据文件信息。
 55      */
 56     public void clearGraphDB() {
 57         try {
 58             FileUtils.deleteRecursively(new File(this.getGraphDBPath()));
 59             if(graphTemplateList.containsKey(this.getGraphDBPath())) {
 60                 graphTemplateList.remove(this.getGraphDBPath());
 61             }
 62         } catch (Exception ex) {
 63             ex.printStackTrace();
 64         }
 65     }
 66
 67     /**
 68      * 注册图数据库关闭钩子。
 69      */
 70     public void registerShutdownHook() {
 71         Runtime.getRuntime().addShutdownHook(new Thread(){
 72             @Override
 73             public void run(){
 74                 getGraphDBService().shutdown();
 75             }
 76         });
 77     }
 78
 79     /**
 80      * 构造函数。初始化图数据库路径。
 81      * @param graphDBPath
 82      */
 83     private GraphTemplate(String graphDBPath) {
 84         this.graphDBPath = graphDBPath;
 85     }
 86
 87     private static Map<String, GraphTemplate> graphTemplateList = new HashMap<String, GraphTemplate>();
 88     /**
 89      * 根据图数据库路径信息,获取对应的GraphTemplate对象实例。<br>
 90      * 目的是采用GraphTemplate的单例模式。
 91      * @param graphPath
 92      * @return
 93      */
 94     public static GraphTemplate getInstance(String graphPath) {
 95         if(graphTemplateList.containsKey(graphPath) == false) {
 96             GraphTemplate template = new GraphTemplate(graphPath);
 97             graphTemplateList.put(graphPath, template);
 98         }
 99         return graphTemplateList.get(graphPath);
100     }
101
102     /**
103      * 根据图数据库名称标示信息,获取对应的GraphTemplate对象实例。<br>
104      * 目的是采用GraphTemplate的单例模式。
105      * @param graphName
106      * @return
107      */
108     public static GraphTemplate getInstanceByName(String graphName) {
109         if(GraphManageUtil.getGraphConfigOptionList().containsKey(graphName) == false) {
110             return null;
111         }
112         GraphConfigOption option = GraphManageUtil.getGraphConfigOptionList().get(graphName);
113         return getInstance(option.getPath());
114     }
115
116     /**
117      * 构建事务。
118      * @return
119      */
120     public Transaction createTransaction() {
121         return this.getGraphDBService().beginTx();
122     }
123
124     private GraphIndexUtil indexUtil = null;
125     /**
126      * 获取图数据库索引信息管理功能库。
127      * @return
128      */
129     public GraphIndexUtil getIndexUtil() {
130         if(this.indexUtil == null) {
131             this.indexUtil = new GraphIndexUtil(this.getGraphDBService());
132         }
133         return this.indexUtil;
134     }
135
136     private GraphNodeUtil nodeUtil = null;
137     /**
138      * 获取图数据库节点信息管理功能库。
139      * @return
140      */
141     public GraphNodeUtil getNodeUtil() {
142         if(this.nodeUtil == null) {
143             this.nodeUtil = new GraphNodeUtil(this.getGraphDBService());
144         }
145         return this.nodeUtil;
146     }
147
148     private GraphCypherUtil cypherUtil = null;
149     /**
150      * 获取图数据库Cypher查询语言功能库。
151      * @return
152      */
153     public GraphCypherUtil getCypherUtil() {
154         if(this.cypherUtil == null) {
155             this.cypherUtil = new GraphCypherUtil(this.getGraphDBService());
156         }
157         return this.cypherUtil;
158     }
159
160     private GraphPathUtil pathUtil = null;
161     /**
162      * 获取图数据库Path信息功能库。
163      * @return
164      */
165     public GraphPathUtil getPathUtil() {
166         if(this.pathUtil == null) {
167             this.pathUtil = new GraphPathUtil(this.getGraphDBService());
168         }
169         return this.pathUtil;
170     }
171
172     private GraphRelTypeUtil relTypeUtil = null;
173     /**
174      * 获取图数据库关系类型信息功能库。
175      * @return
176      */
177     public GraphRelTypeUtil getRelTypeUtil() {
178         if(this.relTypeUtil == null) {
179             this.relTypeUtil = new GraphRelTypeUtil(this.getGraphDBService());
180         }
181         return this.relTypeUtil;
182     }
183 }

2.7 数据分页模型GraphPageModel

数据分页模型主要是基于Cypher查询语言中的SKIP和LIMIT而设计的针对Node和Relationship的分页处理模型。关键代码如下表所示:

  1 package com.hnepri.neo4j.common.model;
  2
  3 import java.io.Serializable;
  4 import java.text.DecimalFormat;
  5 import java.util.ArrayList;
  6 import java.util.List;
  7
  8 import org.neo4j.graphdb.Node;
  9 import org.neo4j.graphdb.Relationship;
 10
 11 import com.hnepri.common.util.LogInfoUtil;
 12
 13 /**
 14  * Description: 图数据库数据分页模型类。<br>
 15  * 利用此类可分页管理Node数据和Relationship数据等。
 16  * Copyright: Copyright (c) 2015<br>
 17  * Company: 河南电力科学研究院智能电网所<br>
 18  * @author shangbingbing 2015-11-01编写
 19  * @version 1.0
 20  */
 21 public class GraphPageModel implements Serializable {
 22     private static final long serialVersionUID = 330410716100946538L;
 23     private int pageSize = 10;
 24     private int pageIndex = 1;
 25     private int prevPageIndex = 1;
 26     private int nextPageIndex = 1;
 27     private int pageCount = 0;
 28     private int pageFirstRowIndex = 1;
 29     private boolean hasNextPage = true;
 30     private int totalCount = 0;
 31     private long startTime = System.currentTimeMillis();
 32     private long endTime = System.currentTimeMillis();
 33     private List<Node> nodeList = new ArrayList<Node>();
 34     private List<Relationship> relationshipList = new ArrayList<Relationship>();
 35
 36     /**
 37      * 分页对象构造函数
 38      * @param pageSize 每页记录数
 39      */
 40     public GraphPageModel(int pageSize) {
 41         this.pageSize = pageSize;
 42     }
 43
 44     /**
 45      * 获取分页记录数量
 46      * @return
 47      */
 48     public int getPageSize() {
 49         return pageSize;
 50     }
 51     /**
 52      * 获取当前页序号
 53      * @return
 54      */
 55     public int getPageIndex() {
 56         return pageIndex;
 57     }
 58     /**
 59      * 设置当前页序号
 60      * @param pageIndex
 61      */
 62     public void setPageIndex(int pageIndex) {
 63         if(pageIndex <= 0) {
 64             pageIndex = 1;
 65         }
 66         this.pageIndex = pageIndex;
 67     }
 68     /**
 69      * 获取分页总数
 70      * @return
 71      */
 72     public int getPageCount() {
 73         if(this.getTotalCount() == 0) {
 74             this.pageCount = 0;
 75         } else {
 76             int shang = this.getTotalCount() / this.getPageSize();
 77             int yu = this.getTotalCount() % this.getPageSize();
 78             if(yu > 0) {
 79                 shang += 1;
 80             }
 81             this.pageCount = shang;
 82         }
 83         return pageCount;
 84     }
 85     /**
 86      * 获取每页的第一行序号
 87      * @return
 88      */
 89     public int getPageFirstRowIndex() {
 90         this.pageFirstRowIndex = (this.pageIndex - 1) * this.getPageSize() + 1;
 91         return pageFirstRowIndex;
 92     }
 93     /**
 94      * 获取上一页序号
 95      * @return
 96      */
 97     public int getPrevPageIndex() {
 98         if(this.pageIndex > 1) {
 99             this.prevPageIndex = this.pageIndex - 1;
100         } else {
101             this.prevPageIndex = 1;
102         }
103         return prevPageIndex;
104     }
105     /**
106      * 获取下一页序号
107      * @return
108      */
109     public int getNextPageIndex() {
110         if(this.pageIndex < this.pageCount) {
111             this.nextPageIndex = this.pageIndex + 1;
112         } else {
113             this.nextPageIndex = this.pageCount;
114         }
115         return nextPageIndex;
116     }
117     /**
118      * 跳转到下一页
119      */
120     public void nextPage() {
121         if(this.totalCount == 0 || this.getPageCount() == 0) {
122             this.pageIndex = 1;
123         } else {
124             if(this.pageIndex < this.pageCount) {
125                 this.pageIndex = this.pageIndex + 1;
126             } else {
127                 this.pageIndex = this.pageCount;
128             }
129         }
130     }
131     /**
132      * 跳转到上一页
133      */
134     public void prevPage() {
135         if(this.pageIndex > 1) {
136             this.pageIndex = this.pageIndex - 1;
137         } else {
138             this.pageIndex = 1;
139         }
140     }
141     /**
142      * 获取是否有下一页
143      * @return
144      */
145     public boolean isHasNextPage() {
146         if(this.pageIndex < this.getPageCount()) {
147             this.hasNextPage = true;
148         } else {
149             this.hasNextPage = false;
150         }
151         return hasNextPage;
152     }
153     /**
154      * 获取总记录数
155      */
156     public int getTotalCount() {
157         return totalCount;
158     }
159     /**
160      * 获取总记录数
161      * @param totalCount
162      */
163     public void setTotalCount(int totalCount) {
164         this.totalCount = totalCount;
165     }
166     /**
167      * 初始化起始时间(毫秒)
168      */
169     public void initStartTime() {
170         this.startTime = System.currentTimeMillis();
171     }
172     /**
173      * 初始化截止时间(毫秒)
174      */
175     public void initEndTime() {
176         this.endTime = System.currentTimeMillis();
177     }
178     /**
179      * 获取毫秒格式的耗时信息
180      * @return
181      */
182     public String getTimeIntervalByMilli() {
183         return String.valueOf(this.endTime - this.startTime) + "毫秒";
184     }
185     /**
186      * 获取秒格式的耗时信息
187      * @return
188      */
189     public String getTimeIntervalBySecond() {
190         double interval = (this.endTime - this.startTime)/1000.0;
191         DecimalFormat df = new DecimalFormat("#.##");
192         return df.format(interval) + "秒";
193     }
194     /**
195      * 打印时间信息
196      */
197     public void printTimeInfo() {
198         LogInfoUtil.printLog("起始时间:" + this.startTime);
199         LogInfoUtil.printLog("截止时间:" + this.endTime);
200         LogInfoUtil.printLog("耗费时间:" + this.getTimeIntervalBySecond());
201     }
202     /**
203      * 获取Node检索结果列表
204      * @return
205      */
206     public List<Node> getNodeList() {
207         return nodeList;
208     }
209     /**
210      * 获取Relationship检索结果列表
211      * @return
212      */
213     public List<Relationship> getRelationshipList() {
214         return relationshipList;
215     }
216 }

【未完待续】

下一篇  Neo4j图数据库应用开发之二:RMI Service开发

时间: 2024-08-02 06:59:11

Neo4j图数据库应用开发之一:Neo4j Java 工具包的相关文章

Neo4j图数据库管理系统开发笔记之二:嵌入式服务端系统界面一览

最近在neo4j java api和rmi的基础上,设计了一套neo4j管理工具,分为server端和client端,中间用rmi进行通信.基本功能包括图数据库基本信息维护管理(创建.编辑.删除.统计等),图数据库数据维护管理(创建节点和关系.编辑节点和关系属性信息.节点标签管理.索引管理.删除管理.路径深度遍历.两点之间路径寻址等),RMI服务管理等功能. 先把部分功能界面贴出来,希望能对别人有所帮助,如果有需要代码的话,给我留言.

Neo4j图数据库管理系统开发笔记之三:构建安全的RMI Service(Server)

RMI Server(服务端)主要包括以下功能:远程用户权限验证管理.远程服务接口实现类.Neo4j实体映射转换等.项目目录结构如下图所示: 3.2.1 远程用户权限验证管理 3.2.1.1 用户权限验证机制 用户权限验证机制分为三个层级. 第一级,远程主机IP地址验证.检查是否允许远程主机IP地址访问RMI服务. 第二级,远程用户信息验证.检查用户名称和密码是否正确,用户是否启用等. 第三级,远程服务及接口方法验证.检查用户是否有权访问某个RMI服务以及服务下的指定接口方法. 3.2.1.2

Neo4j视频教程 Neo4j 图数据库视频教程

课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,<Neo4j权威指南>副主编.<Neo4j 3.x 入门经典>翻译 邮箱:[email protected] QQ:1143815700 Neo4j技术讨论QQ群:547190638 Neo4j中文社区:http://neo4j.com.cn 面向人群 Neo4j初学者:已掌握一定Neo4j技术的开发人

Neo4j教程 Neo4j视频教程 Neo4j 图数据库视频教程

课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,<Neo4j权威指南>副主编.<Neo4j 3.x 入门经典>翻译 邮箱:[email protected] QQ:1143815700 Neo4j技术讨论QQ群:547190638 Neo4j中文社区:http://neo4j.com.cn 面向人群 Neo4j初学者:已掌握一定Neo4j技术的开发人

Neo4j图数据库从入门到精通

目录 第一章:介绍 Neo4j是什么 Neo4j的特点 Neo4j的优点 第二章:安装 1.环境 2.下载 3.开启远程访问 4.启动 第三章:CQL 1.CQL简介 2.Neo4j CQL命令/条款 3.Neo4j CQL 函数 4.Neo4j CQL数据类型 第四章:命令 1.CREATE创建 2.MATCH查询 3.RETURN返回 4.关系基础 5.WHERE子句 6.DELETE删除 7.REMOVE删除 8.SET子句 9.ORDER BY排序 10.UNION子句 11.LIMIT

neo4j 图数据库安装及介绍

neo4j 图数据库安装及介绍 一.neo4j图数据库介绍 图数据库,顾名思义就是利用了"图的数据结构来作为数据存储逻辑体现的一种数据库",所以要想学好图数据库当然需要了解一些关于图数据结构的算法!同样的作为图数据结构中很多常用的算法在图数据库中是默认提供支持的,对数据进行查询.计算的操作,比如常见的最短路径算法.pagerank算法等等这些算法,都是图数据结构中常见的算法!当然了neo4j作为一个图数据库当然也会提供这些算法的实现,方便使用者对数据进行操作! 那么图数据结构具体又包含

使用neo4j图数据库的import工具导入数据 -方法和注意事项

背景 最近我在尝试存储知识图谱的过程中,接触到了Neo4j图数据库,这里我摘取了一段Neo4j的简介: Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中.Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性.程序员工作在一个面向对象的.灵活的网络结构下而不是严格.静态的表中--但是他们可以享受到具备完全的事务

Neo4j:图数据库GraphDB(一)

图数据库的代表:Neo4j 官网:  http://neo4j.com/ 引言:为什么使用图数据库 在很多新型项目中,应用图数据库已经是势在必行的趋势了,因为图数据库可以很好的表示各种节点与关系的概念,并且可以很友好的可视化出来,大大方便了我们的数据管理和展示工作. 下面均以演员,导演和电影的图关系做介绍: 一 概念 节点: (a) //actors (m) //movies ( ) //some anonymous nod 关系: -[r]-> //a relationship referre

Neo4j图数据库介绍

图数据库在图中存储数据,图是最通用的数据结构.图中可以存储节点和关系,节点和关系都可以保存属性.这种存储图的数据模型被称为属性图. 图数据库中的基本元素 节点往往用来表示实体,节点可以被多个标签进行标记.最简单的一个属性图是只有一个节点的图,这个节点可以有多个键值对标记的属性.关系通过连接节点来组织节点,一个联系有两个节点,开始节点和结束节点.这一点说明关系是有方向的.利用关系可以将节点组织成链表,树,图等数据结构.标签用来赋予节点角色和类型.一个节点可以有多个标签. 图数据中的高级属性 一个遍