知识图谱、图数据库神器——Grakn
-
介绍什么是grakn
可用于创建知识图谱或图数据库。里边会存节点数据 和 节点之间的关系。并且是支持分布式的。官方提供了java、node、python的三种语言的封装包。是基于gRPC 的方式调用
-
安装grakn
支持linux、mac os x、windows平台、docker安装
-
由于这个数据库数据存储用的是cassandra数据库,所以需要先安装Apache Cassandra 3.11.x and untar it
我个人用的是docker部署
docker pull graknlabs/grakn:latest docker run \ --name grakn \ -d \ --restart=always \ -v /opt/grakn/db/:/grakn-core-all-linux/server/db/ \ -p 48555:48555 \ graknlabs 做了数据库文件的映射 ,其实是映射的cassandra的db位置。docker里自带cassandra服务 docker exec -ti grakn bash -c '/grakn-core-all-linux/grakn console' 或者 docker exec -it grakn bash cd grakn-core-all-linux ./grakn console -k xxx
-
创建表结构。数据库肯定要先定义表结构。当然官方支持的java等语言都有创建的步骤。但是感觉很繁琐而且不实用。没想到谁会频繁的去修改表结构。所以这里介绍的graql的写法。就是相当于sql的写法
-
创建表结构第一步 了解表结构
实体名 就是表名 entity 属性 就是字段 attribute 主键 就是把属性设置成唯一键 key name 实体有一个角色的概念 这个主要是为了统一设置关系的 例如一部分实体有个角色是消费者 一部分实体的角色是生产者 那可能定义一种关系由生产者指向消费者 这就是role 还有实体之间的关系 relation 连线就是根据这个关系链接的
-
了解实体
比较牛的是他们的实体是可以继承的 跟java里的继承理解一样 post sub entity, ## entity这是个基类 实体都继承在这 plays replied-to, plays tagged-in, plays reacted-to; comment sub post, has content, plays attached-to; media sub post, has caption, has file, plays attached; video sub media; photo sub media; 更牛是的还有抽象类 post sub entity, abstract;
-
-
了解关系relation
可以有多个关系 就是会有多个连线 define friendship sub relation, relates friend, plays requested-friendship; friend-request sub relation, relates requested-friendship, relates friendship-requester, relates friendship-respondent; person sub entity, plays friend, plays friendship-requester, plays friendship-respondent; relation也是有属性的 friend-request sub relation, has approved-date,
-
了解语法.直接上例子
依次定义 属性 实体 关系即可
efine ## 先定义属性 identifier sub attribute, value string; naptan-id sub attribute, value string; name sub attribute, value string; lat sub attribute, value double; lon sub attribute, value double; duration sub attribute, value double; distance sub attribute, value double; ## 在定义实体 因为实体会用到上边定义的属性 station sub entity, has naptan-id, has name, has lat, has lon, plays stop, plays beginning, plays end, plays origin, plays destination, plays contained-station; tube-line sub entity, has name, plays route-operator; route-section sub entity, has identifier, has duration, plays section, plays service; ## 定义关系 关系里包括了属性 和 角色之间的联系,这个角色是在定时实体时候定义的 route sub relation, has identifier, relates section, relates stop, relates origin as stop, relates destination as stop, relates route-operator; tunnel sub relation, has identifier, has distance, relates beginning, relates end, relates service; zone sub relation, has name, relates contained-station;
-
上边把表结构写好之后就要导入到数据库中了
导入的语句是: test是表名 后边是你写的数据表结构的文件 当然如果是在docker里要做个映射进来 或者通过docker cp拷贝进来 ./grakn console --keyspace test --file path/to/the/schema.gql
-
表结构创建完了,接下来就是给表里写输入了 增、删、改、查
增加
isa 是实体的时候写 $p
insert $p isa person, $p就是自己的定义的变量可以随便起名字$aaa isa表明是实体 必须用isa has full-name "John Parkson", has 属性名 具体的值 has gender "male", has email "john.parkson@gmail.com", has phone-number "+44-1234=567890"; 插入就这样写
删除
match $p isa person, has email "raphael.santos@gmail.com"; match是查找的意思 意识是删除先查找出一个实体的变量$p,根据条件 email=“raphael.santos@gmail.com” delete $p isa person; 然后再删掉
修改 其实是先删除再添加
## 先根据条件查找 match $org isa organisation, has name "Medicely", has registration-number $rn; ## 根据查找到的那条数据删掉属性的值 delete $org has registration-number $rn; ##再找到那条数据 match $org isa organisation, has name "Medicely"; ## 给那个属性插入新的值 insert $org has registration-number "81726354";
查找
match $p isa person; get; limit 1; 查找person表的所有数据,但是返回的内容里只有id,如果要先都返回需要加上返回的属性 这一点比较麻烦,但是估计考虑的是性能
三、客户端java的封装
-
maven引入依赖
<!-- 他们自己管理的没有放到maven库 所以需要指定一下--> <repositories> <repository> <id>repo.grakn.ai</id> <url>https://repo.grakn.ai/repository/maven/</url> </repository> </repositories> <!--以下这两个可以访问上边的地址找最新的版本配置以下,我目前用的都是最新的--> <!-- 操作gql的依赖--> <dependency> <groupId>io.graql</groupId> <artifactId>graql-lang</artifactId> <version>1.0.7</version> </dependency> <!--grpc连接和执行的封装--> <dependency> <groupId>io.grakn.client</groupId> <artifactId>grakn-client</artifactId> <version>1.8.1</version> </dependency>
-
加载schema,当然通过上边gql导入也是可以的,这里主要介绍java的导入方式
GraknClient client = new GraknClient("http://192.168.1.111:48555"); GraknClient.Session session = client.session("test"); GraknClient.Transaction transaction = session.transaction().write(); try { byte[] encoded = Files.readAllBytes(Paths.get("schemas/test.gql")); String query = new String(encoded, StandardCharsets.UTF_8); transaction.execute((GraqlDefine) Graql.parse(query)); transaction.commit(); System.out.println("Loaded the " + graknClientServer.getKeyspaceName() + " schema"); } catch (IOException e) { transaction.close(); session.close(); client.close();; e.printStackTrace(); } //注意关闭连接 否则会造成连接数过多,并且jvm里的资源也无法释放 肯定会崩 transaction.close(); session.close(); client.close();;
-
然后也是增删改查
增加
//entity 这个参数是定义的实体 map参数是实体里的属性和要添加的值 StatementInstance hasSql = var("p").isa(entity); for (Map.Entry<String, String> entry : map.entrySet()) { hasSql = hasSql.has(entry.getKey(), entry.getValue()); } GraqlInsert query = Graql.insert(hasSql); GraknClient.Transaction.QueryFuture<List<ConceptMap>> execute = transaction.execute(query); List<ConceptMap> conceptMaps = execute.get(); insertId = conceptMaps.get(0).get("p").id().toString(); transaction.commit();
删除
//参数为id id即数据库的自己的 ‘VXXXX’ GraqlDelete query = Graql.match( var("p").id(id) ).delete(var("p")); transaction.execute(query); transaction.commit();
修改
//参数id 是要修改的那条数据的id 是“VXXX”。 参数map是要修改的字段和字段的值 //1。 删除属性的值 for (Map.Entry<String, String> entry : map.entrySet()) { GraqlDelete delete_query = Graql.match( var("m").id(id).has(entry.getKey(), var("rn")) ).delete(var("rn")); transaction.execute(delete_query); } //2. 添加属性 StatementInstance has = null; for (Map.Entry<String, String> entry : map.entrySet()) { if (null == has) { has = var("m").has(entry.getKey(), entry.getValue()); } else { has = has.has(entry.getKey(), entry.getValue()); } } GraqlInsert insert_query = Graql.match( var("m").id(id) ).insert( has ); transaction.execute(insert_query); transaction.commit();
查
//参数为entity 实体名 参数params为hashmap "name"=>["like","测试"] 参数order为排序方式 String queryEntity = " $" + entity + " isa " + entity; //显示的值 for(Map.Entry<String, List<String>> entry: params.entrySet()) { queryEntity = queryEntity + ", has " + entry.getKey()+ " $" + entry.getKey(); } queryEntity += ";"; for(Map.Entry<String, List<String>> entry: params.entrySet()) { if(entry.getValue().size() > 0) { queryEntity = queryEntity + " $" + entry.getKey() + " " + queryMap.get(entry.getValue().get(0)) + " '" + entry.getValue().get(1) + "';"; } } List<String> queryAsList = Arrays.asList( "match ", queryEntity, "get;sort $"+order+" asc;" ); System.out.println("\nQuery:\n" + String.join("\n", queryAsList)); String query = String.join("", queryAsList); List<Map<String, String>> result = new ArrayList<>(); GraknClient.Transaction.QueryFuture<List<ConceptMap>> execute = transaction.execute((GraqlGet) parse(query)); List<ConceptMap> answers = execute.get();
当然最基本的节点操作就是以上的这些方法。基本的入门应该没问题了
后续如果有需要大的话
会将优化好的代码和关系的操作开源到github上