
# 使用Cypher JDBC Driver访问GES
#### 功能介绍
GES Cypher JDBC Driver是专为GES编写的JDBC驱动，基于Neo4j JDBC Driver中的接口，提供了使用JDBC访问GES并进行cypher查询的一种方法。
尤其是当cypher请求返回数据量较大、并发数高、JVM缓存完整请求体有困难的场景下，该组件内置了一种可以流式解析响应body体的方法，与获得整个body体再解析相比，极大地降低了cpu和内存的占用。
#### 依赖配置
1. 下载相应的SDK和驱动，具体操作请参考[连接管理](https://support.huaweicloud.com/usermanual-ges/ges_01_0104.html)章节。
2. 若Maven源可用（有配置maven源，且maven源可以从开源仓库下载jar包），则解压huaweicloud-ges-sdk-java-xxx.zip，进入maven-install目录中，执行ges-sdk-java-maven-install.bat文件或ges-sdk-java-maven-install.sh文件，将graph-sdk-xxx.jar、cypher-jdbc-driver-xxx.jar安装到本地maven仓库，即可在maven工程中配置pom依赖以使用Cypher JDBC Driver。
   ```
   <dependency> 
         <groupId>com.huawei.ges</groupId> 
         <artifactId>cypher-jdbc-driver</artifactId> 
         <version>xxx</version> //此处需要输入当前cypher jdbc驱动的版本号
    </dependency>
   <dependency>
       <groupId>org.neo4j</groupId>
       <artifactId>neo4j-jdbc</artifactId>
       <version>xxx</version>
   </dependency>
   <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>xxx</version>
   </dependency>
   ```
   
3. 若Maven源不可用（没有配置maven源或者maven源不能从开源仓库下载jar包），则解压huaweicloud-ges-sdk-java-xxx.zip，将jars目录下的cypher-jdbc-driver-xxx-with-dependencies.jar导入工程或者将cypher-jdbc-driver-xxx.jar以及cypher-jdbc-lib目录下所有包导入工程皆可。
 
#### 参数说明
表1JDBC getConnection参数说明 
|  参数  |                                                                 参数说明                                                                 |
|---|---|
| url  | "jdbc:ges:"前缀拼接GES Cypher API的URL。 在GES控制台的"连接管理"页面，"可用图实例名称"下拉选择待访问的图名称，"JDBC连接字符串"即为Cypher API的URL。 |
| prop | Properties对象，包含连接GES API所需的各项配置，详见[表2]。                                                           |
   
 表2Properties参数说明 
|        参数         |                                                                                                                                               参数说明                                                                                                                                                |
|---|---|
| X-Auth-Token      | 通过IAM鉴权接口获取到的token。                                                                                                                                                                                                                                                                               |
| parse-json        | 是否转换点边对象，默认值为"false"。 - 取值为false时，cypher返回体中的点和边将以map形式返回。  - 为true时，以GesElement对象的形式返回。            |
| deserializer-type | 解析cypher响应的策略，可选项为lazy和eager，默认为lazy。 - 取值为lazy时，采用流式解析cypher的策略，cypher返回体不常驻内存。  - 取值为eager时为获取整个json后解析。   |
| limit             | 流速控制，默认值100000，内核以批的形式返回给server侧的webapp，由webapp整理成流返回给前端。limit的含义为内核返回给webapp时的批的大小。对同一条查询，limit越小时，GES内核侧交互次数增多，jdbc client拿到第一条记录的时间越快，整体查询时间变长。                                                                                                                                                |
   
#### 鉴权方法
GES Cypher JDBC Driver支持Token和AK/SK两种鉴权。
1. Token鉴权代码示例：
   ```
   import com.huawei.ges.jdbc.io.model.GesElement;
   import java.sql.Connection;
   import java.sql.DriverManager;
   import java.sql.PreparedStatement;
   import java.sql.ResultSet;
   import java.sql.SQLException;
   import java.util.Properties;
   public class CypherJDBCClient {
       public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
           String token = "";  // 调用IAM服务API获取
           String url = "";  // 值为“jdbc:ges:JDBC连接字符串”，其中“JDBC连接字符串”从GES控制台“连接管理”界面获取
           Class.forName("com.huawei.ges.jdbc.Driver").newInstance();
           Properties prop = new Properties();
           prop.setProperty("X-Auth-Token", token);
           prop.setProperty("deserializer-type", "lazy");
           prop.setProperty("parse-json", "true");
           prop.setProperty("limit", "10000");
           try (Connection conn = DriverManager.getConnection(url, prop)) {
               String query = "match (m) return m limit 1";
               try (PreparedStatement stmt = conn.prepareStatement(query)) {
                   try (ResultSet rs = stmt.executeQuery()) {
                       while (rs.next()) {
                           GesElement.GesVertex vertex = (GesElement.GesVertex) rs.getObject("m");
                           System.out.println(vertex.getId());
                           System.out.println(vertex.getLabels());
                           System.out.println(vertex.getProperties());
                       }
                   }
               }
           } catch (SQLException e) {
               System.out.println("Execute SQL query error.");
           }
       }
   }
   ```
   
2. AK/SK鉴权可以使用GES业务面SDK提供的方法生成签名，导入业务面SDK依赖详见[下载与安装](https://support.huaweicloud.com/devg-ges/ges_05_0004.html)。
   AK/SK鉴权代码示例如下，ak，sk和regionCode参数获取请参考[初始化参数获取](https://support.huaweicloud.com/devg-ges/ges_05_0005.html)章节。
   ```
   import com.huawei.ges.graph.v1.auth.aksk.HttpRestClient;
   import com.huawei.ges.jdbc.io.model.GesElement;
   import java.sql.Connection;
   import java.sql.DriverManager;
   import java.sql.PreparedStatement;
   import java.sql.ResultSet;
   import java.sql.SQLException;
   import java.util.Map;
   import java.util.Properties;
   public class CypherJDBCClientByAKSK {
       public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
           // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全
           // 本示例以ak和sk保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK
           String ak = System.getenv("HUAWEICLOUD_SDK_AK");
           String sk = System.getenv("HUAWEICLOUD_SDK_SK");
           String regionCode = "";
           String url = "";  // 值为“jdbc:ges:JDBC连接字符串”，其中“JDBC连接字符串”从GES控制台“连接管理”界面获取
           Map<String, String> iamHeader = HttpRestClient.getIamSignHeaders(ak, sk, regionCode);  // 业务面SDK的方法，生成签名
           Class.forName("com.huawei.ges.jdbc.Driver").newInstance();
           doCypherQuery(url, iamHeader);
       }
       public static void doCypherQuery(String url, Map<String, String> iamHeaders) {
           Properties prop = new Properties();
           for (Map.Entry<String, String> pair : iamHeaders.entrySet()) {
               prop.setProperty(pair.getKey(), pair.getValue());
           }
           prop.setProperty("deserializer-type", "lazy");
           prop.setProperty("parse-json", "true");
           prop.setProperty("limit", "10000");
           try (Connection conn = DriverManager.getConnection(url, prop)) {
               String query = "match (m) return m limit 1";
               try (PreparedStatement stmt = conn.prepareStatement(query)) {
                   try (ResultSet rs = stmt.executeQuery()) {
                       while (rs.next()) {
                           GesElement.GesVertex vertex = (GesElement.GesVertex) rs.getObject("m");
                           System.out.println(vertex.getId());
                           System.out.println(vertex.getLabels());
                           System.out.println(vertex.getProperties());
                       }
                   }
               }
           } catch (SQLException e) {
               System.out.println("Execute SQL query error.");
           }
       }
   }
   ```
   
 
