Getting Started
http://docs.janusgraph.org/latest/getting-started.html
JanusGraph 第三章 入门
本节中的例子展示了如何使用JanusGraph检索诸神关系图. 关系图如下图所示.抽象数据模型使用大家都熟知的Property Graph Model ,而且这个例子描述了罗马诸神中的人物和他们所在位置之间的联系.
Figure 3.1. 诸神关系图
虚拟元素 | 意义 |
---|---|
粗体的关键字 | 图的索引 |
粗体加星的关键字 | 图的索引, 必须唯一 |
下划线的关键字 | 顶点中心索引 |
空心箭头的边 | 功能或者唯一的边(不能重复) |
尾巴带横线的边 | 单向的边, 只能按照一个方向进行访问 |
3.1 下载JanusGraph和运行Gremlin命令行
JanusGraph的下载地址可以从最新的发布页面获得. 下载后解压, 就可以找到Gremlin命令行. Gremlin命令行是一种REPL, 与标准Groovy命令行的的微小区别, JanusGraph仅仅是一种预安装和预加载的包.
用户可以通过从中心仓库下载JanusGraph包, 在Gremlin命令行中安装后激活JanusGraph.在下列的例子中, 确保下载janusgraph.zip文件, 并解压了这个压缩包
Important | |
---|---|
JanusGraph需要Java8(标准版本) 推荐使用Oracle Java8. JanusGraph 的脚本需要$JAVA_HOME环境变量指向JRE或者JDK的安装目录 |
$ unzip janusgraph-0.2.0-hadoop2.zip Archive: janusgraph-0.2.0-hadoop2.zip creating: janusgraph-0.2.0-hadoop2/ ... $ cd janusgraph-0.2.0-hadoop2 $ bin/gremlin.sh \,,,/ (o o) -----oOOo-(3)-oOOo----- 09:12:24 INFO org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph - HADOOP_GREMLIN_LIBS is set to: /usr/local/janusgraph/lib plugin activated: tinkerpop.hadoop plugin activated: janusgraph.imports gremlin>
Gremlin命令行使用Groovy翻译用户输入的命令. Groovy是java的一个扩展, 设计了许多简短标记, 可以让交互性编程语言更容易使用. 同样Gremlin-Groovy是Groovy的一个扩展, 让图的遍历更加方便.以下基本例子展示了JanusGraph使用数字, 字符串和map的基本方法. 教程的其他部分要讨论图特有的结构.
gremlin> 100-10 ==>90 gremlin> "JanusGraph:" + " The Rise of Big Graph Data" ==>JanusGraph: The Rise of Big Graph Data gremlin> [name:'aurelius', vocation:['philosopher', 'emperor']] ==>name=aurelius ==>vocation=[philosopher, emperor]
Tip | |
---|---|
Refer to Apache TinkerPop, SQL2Gremlin, and Gremlin Recipes for more information about using Gremlin. |
3.2 读取诸神关系图到JanusGraph
以下例子创建了JanusGraph的实例, 后加载了诸神关系图. JanusGraphFactory提供一系列静态读取配置参数方法, 每个方法会根据配置参数的不同, 返回一个对应的实例. 这里的示例使用BerkeleyDB存储和Elasticsearch索引, 通过GraphOfTheGodsFactory类加载诸神关系图. 本章没有讨论配置的详细内容, 如果要查看存储、索引和配置的详细信息, 请跳到对应章节
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-berkeleyje-es.properties') ==>standardjanusgraph[berkeleyje:../db/berkeley] gremlin> GraphOfTheGodsFactory.load(graph) ==>null gremlin> g = graph.traversal() ==>graphtraversalsource[standardjanusgraph[berkeleyje:../db/berkeley], standard]
JanusGraphFactory.open() 和 GraphOfTheGodsFactory.load()创建了一个图对象, 主要分3步
1. 为图创建了一系列全局, 顶点中心索引2. 为图添加了顶点, 和顶点的属性3. 为图添加了边, 和边的属性
想要看更详细的信息, 可以查看对应
源码
这里使用的是JanusGraph/Cassandra, 确定加载了对应的配置文件conf/janusgraph-cassandra-es.properties, 执行了GraphOfTheGodsFactory.load()方法, 若使用HBase和es, 请读取conf/janusgraph-hbase-es.properties配置
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-cassandra-es.properties') ==>standardjanusgraph[cassandrathrift:[127.0.0.1]] gremlin> GraphOfTheGodsFactory.load(graph) ==>null gremlin> g = graph.traversal() ==>graphtraversalsource[standardjanusgraph[cassandrathrift:[127.0.0.1]], standard]
你可能不需要使用索引, 那就读取下边几种conf/janusgraph-cassandra.properties, conf/janusgraph-berkeleyje.properties, or conf/janusgraph-hbase.properties. 另一个方法GraphOfTheGodsFactory.loadWithoutMixedIndex()来加载数据
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-cassandra.properties') ==>standardjanusgraph[cassandrathrift:[127.0.0.1]] gremlin> GraphOfTheGodsFactory.loadWithoutMixedIndex(graph, true) ==>null gremlin> g = graph.traversal() ==>graphtraversalsource[standardjanusgraph[cassandrathrift:[127.0.0.1]], standard]
3.3. 全局索引
访问图数据库中的数据, 首先是根据图的索引定位到切入点. 切入点是一个元素(或者一组元素), 例如:一个顶点或者一个边. Gremlin路径描述了如何通过图的结构, 从切入点元素访问到其他元素.
根据图, name属性的索引是唯一的, 可以通过这种方法访问克罗诺斯(Saturn)顶点. 也就可以获得该顶点的属性map, 克罗诺斯顶点name是克罗诺斯, age是10000, type是巨人. 克罗诺斯的孙子是谁? 结果是海格力斯.
gremlin> saturn = g.V().has('name', 'saturn').next() ==>v[256] gremlin> g.V(saturn).valueMap() ==>[name:[saturn], age:[10000]] gremlin> g.V(saturn).in('father').in('father').values('name') ==>hercules
坐标属性也属于图的索引. 坐标是边的属性. 所以, JanusGraph可以把边放到索引中. 你可能会查询距离Athens(维度:37.97, 经度:23.72)50公里内发生的事情. 查出那个顶点是包含在其中的.
gremlin> g.E().has('place', geoWithin(Geoshape.circle(37.97, 23.72, 50))) ==>e[a9x-co8-9hx-39s][16424-battled->4240] ==>e[9vp-co8-9hx-9ns][16424-battled->12520] gremlin> g.E().has('place', geoWithin(Geoshape.circle(37.97, 23.72, 50))).as('source').inV().as('god2').select('source').outV().as('god1').select('god1', 'god2').by('name') ==>[god1:hercules, god2:hydra] ==>[god1:hercules, god2:nemean]
图索引是JanusGraph索引结构中的一种. JanusGraph要访问全部顶点或者全部边, 图的索引会自动匹配
JanusGraph中另一种索引被称为顶点中心索引. 顶点中心索引用来加速图的内部访问. 稍后做解释
3.3.1 访问图的例子
海格力斯是朱庇特和埃尔克莫尼的儿子, 拥有超过常人的力量. 海格力斯父亲是神,母亲是人类, 所以他是半人半神,
Juno是朱庇特的妻子, 对他的不忠极其气愤. 为了报复, 她蒙蔽了朱庇特, 并让朱庇特杀了他的妻子和孩子.为了补偿, 海格力斯被特尔非神谕安排服役于Eurystheus.
上一节, 克罗诺斯的孙子是海格力斯, 这可以使用循环, 从克罗诺斯沿着两次父亲的路径, 可以找到海格力斯
gremlin> hercules = g.V(saturn).repeat(__.in('father')).times(2).next() ==>v[1536]
为证明海格力斯是半人半神. 需要检查他的父母身世. 可以从海格力斯访问到他的父母节点. 可以找出父母的类型是神和人类.
gremlin> g.V(hercules).out('father', 'mother') ==>v[1024] ==>v[1792] gremlin> g.V(hercules).out('father', 'mother').values('name') ==>jupiter ==>alcmene gremlin> g.V(hercules).out('father', 'mother').label() ==>god ==>human gremlin> hercules.label() ==>demigod
例子展示了罗马诸神的基因关系. Property Graph Model已经足够处理事物的多个类型和关系. 在上一节, 海格力斯在Athens附近打了两次仗, 通过访问battled边可以找到这些事件.
gremlin> g.V(hercules).out('battled') ==>v[2304] ==>v[2560] ==>v[2816] gremlin> g.V(hercules).out('battled').valueMap() ==>[name:[nemean]] ==>[name:[hydra]] ==>[name:[cerberus]] gremlin> g.V(hercules).outE('battled').has('time', gt(1)).inV().values('name') ==>cerberus ==>hydra
battled边的time属性会被顶点中心索引管理. 对指定的边进行查找或过滤, 要比扫描全部的边再过滤要更快.JanusGraph可以自动使用顶点中心索引.
gremlin> g.V(hercules).outE('battled').has('time', gt(1)).inV().values('name').toString() ==>[GraphStep([v[24744]],vertex), VertexStep(OUT,[battled],edge), HasStep([time.gt(1)]), EdgeVertexStep(IN), PropertiesStep([name],value)]
3.3.2 更复杂的例子
普鲁托住在冥界. 他跟明海格力的联系是, 明海格力打过他的宠物.尽管这样, 明海格力是他的侄子, 普鲁托会怎样处理对他侄子的无礼.
Gremlin提供更多的例子. 每一个实例的解释
gremlin> pluto = g.V().has('name', 'pluto').next() ==>v[2048] gremlin> // who are pluto's cohabitants? gremlin> g.V(pluto).out('lives').in('lives').values('name') ==>pluto ==>cerberus gremlin> // pluto can't be his own cohabitant gremlin> g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name') ==>cerberus gremlin> g.V(pluto).as('x').out('lives').in('lives').where(neq('x')).values('name') ==>cerberus
3.3.2.2. 普鲁托的兄弟们
gremlin> // where do pluto's brothers live? gremlin> g.V(pluto).out('brother').out('lives').values('name') ==>sky ==>sea gremlin> // which brother lives in which place? gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god', 'place') ==>[god:v[1024], place:v[512]] ==>[god:v[1280], place:v[768]] gremlin> // what is the name of the brother and the name of the place? gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god', 'place').by('name') ==>[god:jupiter, place:sky] ==>[god:neptune, place:sea]
普鲁托不畏惧死亡, 所以他住在冥界. 相反, 他的兄弟们选择住在充满爱的地方.
gremlin> g.V(pluto).outE('lives').values('reason') ==>no fear of death gremlin> g.E().has('reason', textContains('loves')) ==>e[6xs-sg-m51-e8][1024-lives->512] ==>e[70g-zk-m51-lc][1280-lives->768] gremlin> g.E().has('reason', textContains('loves')).as('source').values('reason').as('reason').select('source').outV().values('name').as('god').select('source').inV().values('name').as('thing').select('god', 'reason', 'thing') ==>[god:neptune, reason:loves waves, thing:sea] ==>[god:jupiter, reason:loves fresh breezes, thing:sky]