遍历策略

一个TraversalStrategy分析一个遍历,如果遍历符合它的标准,可以相应地改变它。遍历策略在编译时被执行,并构成Gremlin遍历机的编译器的基础。有五类策略分列如下:

  • decoration: 在应用程序级别的特性可以嵌入到遍历逻辑中
  • optimization: 在TinkerPop3级别有更高效的方式来表达遍历
  • provider optimization: 在图的系统/语言/驱动程序级别上有一种更有效的方式来表示遍历
  • finalization: 执行遍历之前需要进行一些最终的调整/清理/分析
  • verification: 某些遍历对于应用程序或遍历引擎是不合法的

Note

explain()步骤向用户显示每个注册策略如何改变遍历。

如:gremlin> g.V().has('name','marko').explain()

元素ID策略

ElementIdStrategy提供对元素标识符的控制。一些Graph实现(如TinkerGraph)允许在创建元素时指定自定义标识符:

gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> v = g.addV().property(id,'42a').next()
==>v[42a]
gremlin> g.V('42a')
==>v[42a]
来源: http://tinkerpop.apache.org/docs/3.2.6/reference/#traversalstrategy

其他Graph实现(如Neo4j)会自动生成元素标识符,并且不能分配。作为一个帮手,可以使用ElementIdStrategy通过使用顶点和边索引来使标识符赋值成为可能。

如:

gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
==>neo4jgraph[Community [/tmp/neo4j]]
gremlin> strategy = ElementIdStrategy.build().create()
==>ElementIdStrategy
gremlin> g = graph.traversal().withStrategies(strategy)
==>graphtraversalsource[neo4jgraph[Community [/tmp/neo4j]], standard]
gremlin> g.addV().property(id, '42a').id()
==>42a

Note

用于存储分配的标识符的key应该在底层图形数据库中建立索引。如果没有建立索引,那么查找使用这些标识符的元素将执行线性扫描。

事件策略

EventStrategy的目的是在遍历内发生对底层Graph的更改时,将事件引发到一个或多个MutationListener对象。这种策略对记录更改,触发基于更改的某些操作或在遍历期间需要通知某些变异操作的任何应用程序非常有用。如果事务回滚,则重置事件队列。

以下事件引发MutationListener:

New vertex

New edge

Vertex property changed

Edge property changed

Vertex property removed

Edge property removed

Vertex removed

Edge removed

要开始处理来自Traversal的事件,首先要实现MutationListener接口。此实现的一个示例是ConsoleMutationListener,它将输出写入每个事件的控制台。示例如下:

gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> l = new ConsoleMutationListener(graph)
==>MutationListener[tinkergraph[vertices:6 edges:6]]
gremlin> strategy = EventStrategy.build().addListener(l).create()
==>EventStrategy
gremlin> g = graph.traversal().withStrategies(strategy)
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.addV().property('name','stephen')
Vertex [v[13]] added to graph [tinkergraph[vertices:7 edges:6]]
==>v[13]
gremlin> g.E().drop()
Edge [e[7][1-knows->2]] removed from graph [tinkergraph[vertices:7 edges:6]]
Edge [e[8][1-knows->4]] removed from graph [tinkergraph[vertices:7 edges:5]]
Edge [e[9][1-created->3]] removed from graph [tinkergraph[vertices:7 edges:4]]
Edge [e[10][4-created->5]] removed from graph [tinkergraph[vertices:7 edges:3]]
Edge [e[11][4-created->3]] removed from graph [tinkergraph[vertices:7 edges:2]]
Edge [e[12][6-created->3]] removed from graph [tinkergraph[vertices:7 edges:1]]

Note

EventStrategy并不意味着用于跟踪不同进程间的全局变化。换句话说,一个JVM进程中的突变不会作为不同JVM进程中的事件引发。

分区策略

PartitionStrategy将图的顶点和边分割成String命名的分区(如桶,子图等)。

PartitionStrategy中有三种主要配置:

  • 分区键(Partition Key) - 以字符串值的属性key来表示的分区。
  • 写分区(Write Partition) - 一个字符串,表示将来所有未来写入元素的分区。
  • 读分区(Read Partitions) - 一个字符串集合Set<String>表示可以读取的分区。

使用分区策略的一个例子:

gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> strategyA = PartitionStrategy.build().partitionKey("_partition").writePartition("a").readPartitions("a").create()
==>PartitionStrategy
gremlin> strategyB = PartitionStrategy.build().partitionKey("_partition").writePartition("b").readPartitions("b").create()
==>PartitionStrategy
gremlin> gA = graph.traversal().withStrategies(strategyA)
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> gA.addV() // this vertex has a property of {_partition:"a"}
==>v[13]
gremlin> gB = graph.traversal().withStrategies(strategyB)
==>graphtraversalsource[tinkergraph[vertices:7 edges:6], standard]
gremlin> gB.addV() // this vertex has a property of {_partition:"b"}
==>v[15]
gremlin> gA.V()
==>v[13]
gremlin> gB.V()
==>v[15]

通过将元素写入特定分区,然后限制读取分区,开发人员可以在单个地址空间内创建多个图形。此外,通过支持分区之间的引用,可以合并这些多个图(即连接分区)。

Note

如果Graph可以支持元属性,并且在构建PartitionStrategy时将includeMetaProperties值设置为true,则分区也可能扩展到VertexProperty元素。

只读策略

ReadOnlyStrategy 如其名称所示,如果Traversal内有任何改变的步骤,则应用此策略的遍历将抛出IllegalStateException。

子图策略

SubgraphStrategy类似于PartitionStrategy,因为它限制了某些顶点,边和顶点属性的遍历。

下例使用相同的查询对是否使用子图策略的两种情景进行查询,其中子图策略为:创建一个SubgraphStrategy,其中顶点属性不能有一个endTime属性。

gremlin> graph = TinkerFactory.createTheCrew()
==>tinkergraph[vertices:6 edges:14]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:14], standard]
gremlin> g.V().as('a').values('location').as('b'). //1\
select('a','b').by('name').by()
==>[a:marko,b:san diego]
==>[a:marko,b:santa cruz]
==>[a:marko,b:brussels]
==>[a:marko,b:santa fe]
==>[a:stephen,b:centreville]
==>[a:stephen,b:dulles]
==>[a:stephen,b:purcellville]
==>[a:matthias,b:bremen]
==>[a:matthias,b:baltimore]
==>[a:matthias,b:oakland]
==>[a:matthias,b:seattle]
==>[a:daniel,b:spremberg]
==>[a:daniel,b:kaiserslautern]
==>[a:daniel,b:aachen]
gremlin> g = g.withStrategies(SubgraphStrategy.build().vertexProperties(hasNot('endTime')).create()) //2\
==>graphtraversalsource[tinkergraph[vertices:6 edges:14], standard]
gremlin> g.V().as('a').values('location').as('b'). //3\
select('a','b').by('name').by()
==>[a:marko,b:santa fe]
==>[a:stephen,b:purcellville]
==>[a:matthias,b:seattle]
==>[a:daniel,b:aachen]
来源: http://tinkerpop.apache.org/docs/3.2.6/reference/#_subgraphstrategy

下面的示例使用所有三个过滤器:vertex,edge和vertex property。Vertices必须居住(location属性)在三个以上的地方或者没有居住信息,Edges必须标注为“develops”,VertexProperties必须是当前位置或没有位置(location)属性。

gremlin> graph = TinkerFactory.createTheCrew()
==>tinkergraph[vertices:6 edges:14]
gremlin> g = graph.traversal().withStrategies(SubgraphStrategy.build().
vertices(or(hasNot('location'),properties('location').count().is(gt(3)))).
edges(hasLabel('develops')).
vertexProperties(or(hasLabel(neq('location')),hasNot('endTime'))).create())
==>graphtraversalsource[tinkergraph[vertices:6 edges:14], standard]
gremlin> g.V().valueMap(true)
==>[name:[marko],label:person,location:[santa fe],id:1]
==>[name:[matthias],label:person,location:[seattle],id:8]
==>[name:[gremlin],label:software,id:10]
==>[name:[tinkergraph],label:software,id:11]
gremlin> g.E().valueMap(true)
==>[label:develops,id:13,since:2009]
==>[label:develops,id:14,since:2010]
==>[label:develops,id:21,since:2012]
gremlin> g.V().outE().inV().path().by('name').by(label).by('name')
==>[marko,develops,gremlin]
==>[marko,develops,tinkergraph]
==>[matthias,develops,gremlin]
gremlin>

TinkerPop中的遍历:图的遍历策略的更多相关文章

  1. TinkerPop中的遍历:图的遍历步骤(3/3)

    48 Project Step project() 步骤(map)将当前对象投射到由提供的标签键入的Map<String,Object>中. gremlin> g.V().out(' ...

  2. TinkerPop中的遍历:图的遍历步骤(1/3)

    图遍历步骤(Graph Traversal Steps) 在最一般的层次上,Traversal<S,E>实现了Iterator,S代表起点,E代表结束.遍历由四个主要组成部分组成: Ste ...

  3. 树的三种DFS策略(前序、中序、后序)遍历

    之前刷leetcode的时候,知道求排列组合都需要深度优先搜索(DFS), 那么前序.中序.后序遍历是什么鬼,一直傻傻的分不清楚.直到后来才知道,原来它们只是DFS的三种不同策略. N = Node( ...

  4. 图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)

    图的遍历的定义: 从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次.(连通图与非连通图) 深度优先遍历(DFS): 1.访问指定的起始顶点: 2.若当前访问的顶点的邻接顶点有未被访问的,则 ...

  5. Java中关于HashMap的元素遍历的顺序问题

    Java中关于HashMap的元素遍历的顺序问题 今天在使用如下的方式遍历HashMap里面的元素时 1 for (Entry<String, String> entry : hashMa ...

  6. C++编程练习(9)----“图的存储结构以及图的遍历“(邻接矩阵、深度优先遍历、广度优先遍历)

    图的存储结构 1)邻接矩阵 用两个数组来表示图,一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中边或弧的信息. 2)邻接表 3)十字链表 4)邻接多重表 5)边集数组 本文只用代码实现用 ...

  7. Kruskal和prime算法的类实现,图的遍历BFS算法。

    一.图的遍历 #include<iostream> #include<queue> #include<vector> using namespace std; in ...

  8. 图的遍历——DFS(矩形空间)

    首先,这里的图不是指的我们一般所说的图结构,而是大小为M*N的矩形区域(也可以看成是一个矩阵).而关于矩形区域的遍历问题经常出现,如“寻找矩阵中的路径”.“找到矩形区域的某个特殊点”等等之类的题目,在 ...

  9. 图的遍历——DFS和BFS模板(一般的图)

    关于图的遍历,通常有深度优先搜索(DFS)和广度优先搜索(BFS),本文结合一般的图结构(邻接矩阵和邻接表),给出两种遍历算法的模板 1.深度优先搜索(DFS) #include<iostrea ...

随机推荐

  1. Linux下anaconda的安装

    http://peteryuan.net/use-anaconda/ http://www.jianshu.com/p/03d757283339

  2. python+rabbitmq实现分布式

    #master # -*- coding: utf-8 -*-import sys#reload(sys)sys.setdefaultencoding("utf-8") impor ...

  3. deque容器

    一.deque容器基本概念 deque是“double-ended queue”的缩写,和vector一样,deque也支持随机存取.vector是单向开口的连续性空间,deque则是一种双向开口的连 ...

  4. docker容器的服务发现:consul

    官网:https://www.consul.io 官网文档:https://www.consul.io/docs简介 consul是一个服务发现的组件,在docker世界中他比较流行,主要是consu ...

  5. snmpwalk用法

    snmpwalk语法:snmpwalk 交换机或路由器IP地址 -c SNMP读密码 -v 1或2(代表SNMP版本) OID(对象标示符) 用法举例:1.snmpwalk -c public -v ...

  6. UEditor富文本编辑器的使用 http://fex.baidu.com/ueditor/

    [转] http://fex.baidu.com/ueditor/ UEditor 介绍 UEditor 是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体 ...

  7. Java基础--对象克隆

    对象拷贝用于在内存中复制对象,无需构造器便可创建对象. 需要注意的是 1.clone方法提供的只是简单的值拷贝和地址拷贝,若类中包含HashMap等类型时,需要手工编写拷贝过程 2.如果父类没有提供正 ...

  8. codeforce -39E-What Has Dirichlet Got to Do with That?(博弈+dfs)

    You all know the Dirichlet principle, the point of which is that if n boxes have no less than n + 1  ...

  9. top命令 Linux查看CPU和内存使用情况,cpu监控之一

    一.top命令 top命令是一个功能十分强大的监控系统的工具,对于系统管理员而言尤其重要.但是,它的缺点是会消耗很多系统资源. 在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分 ...

  10. mysql查询最近30天、7天、每天、昨天、上个月的记录

      一些变量说明: add_time为插入的时间 to_days是sql函数,返回的是个天数 data_sub(date,INTERVAL expr type)给指定的日期减去多少天 data()函数 ...