你的位置:首页 > 数据库

[数据库]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 relTypeName114    * @return115   */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 relTypeName126    * @return127   */128   public void remove(String relTypeName) {129     if(this.getRelationshipTypeList().containsKey(relTypeName)) {130       this.getRelationshipTypeList().remove(relTypeName);131     }132   }133   134   /**135    * 根据关系类型名称列表,初始化关系类型枚举列表。136    * @param relTypeNameList137   */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.0231 */232 enum RelationshipTypeEnum implements RelationshipType {233   NONE234 }

 

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 graphName106    * @return107   */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    * @return119   */120   public Transaction createTransaction() {121     return this.getGraphDBService().beginTx();122   }123   124   private GraphIndexUtil indexUtil = null;125   /**126    * 获取图数据库索引信息管理功能库。127    * @return128   */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    * @return140   */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    * @return152   */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    * @return164   */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    * @return176   */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    * @return108   */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    * @return144   */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 totalCount162   */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    * @return181   */182   public String getTimeIntervalByMilli() {183     return String.valueOf(this.endTime - this.startTime) + "毫秒";184   }185   /**186    * 获取秒格式的耗时信息187    * @return188   */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    * @return205   */206   public List<Node> getNodeList() {207     return nodeList;208   }209   /**210    * 获取Relationship检索结果列表211    * @return212   */213   public List<Relationship> getRelationshipList() {214     return relationshipList;215   }216 }

 

【未完待续】

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