Titan cassandra不会为自定义gremlin步骤使用已定义的索引

时间:2014-11-05 21:33:50

标签: indexing cassandra gremlin titan

我们在下面的代码块中使用titan cassandra定义了5个索引

 def mgmt = g.managementSystem;
 try {
     if (!mgmt.containsGraphIndex("byId")) {
         def key = mgmt.makePropertyKey('__id').dataType(String.class).make()
         mgmt.buildIndex("byId",Vertex.class).addKey(key).buildCompositeIndex()
     }
     if (!mgmt.containsGraphIndex("byType")) {
          def key = mgmt.makePropertyKey('__type').dataType(String.class).make()
         mgmt.buildIndex("byType",Vertex.class).addKey(key).buildCompositeIndex()
     }
     if (!mgmt.containsGraphIndex("lastName")) {
         def key = mgmt.makePropertyKey('lastName').dataType(String.class).make()
         mgmt.buildIndex('lastName',Vertex.class).addKey(key).buildMixedIndex(INDEX_NAME)
     }
     if (!mgmt.containsGraphIndex("firstName")) {
         def key = mgmt.makePropertyKey('firstName').dataType(String.class).make()
         mgmt.buildIndex('firstName',Vertex.class).addKey(key).buildMixedIndex(INDEX_NAME)
     }
     if (!mgmt.containsGraphIndex("vin")) {
         def key = mgmt.makePropertyKey('vin').dataType(String.class).make()
         mgmt.buildIndex('vin',Vertex.class).addKey(key).buildMixedIndex(INDEX_NAME)
     }
     mgmt.commit()
 } catch (Exception e) {
     System.err.println("An error occurred initializing indices")
     e.printStackTrace()
 }
然后我们执行以下查询

g.V.has('__id','49fb8bae5f994cf5825b849a5dd9b49a')

这会产生一个警告,通知我们:

"查询需要迭代所有顶点[{}]。为了获得更好的性能,请使用索引"

我很困惑,因为根据文档,这些索引设置正确,但由于某种原因,泰坦没有使用它们。

索引是在图表中的任何数据之前创建的,因此不需要重新编制索引。非常感谢任何帮助。

更新 - 我设法将其分解为一个非常简单的测试。在我们的代码中,我们开发了一个用于所述查询的自定义gremlin步骤

Gremlin.defineStep('hasId', [Vertex,Pipe], { String id ->
    _().has('__id', id)
})

然后从我们的代码中调用

g.V.hasId(id)

当我们使用自定义gremlin步骤时,查询不会使用索引,但在使用vanilla gremlin调用时,会使用索引。

在这篇文章中看起来有点奇怪 https://groups.google.com/forum/#!topic/aureliusgraphs/6DqMG13_4EQ

1 个答案:

答案 0 :(得分:1)

我希望检查是否存在属性键,这意味着您将支票调整为:

if (!mgmt.containsRelationType("__id")) {

我在Titan Gremlin控制台中试用了你的代码,我没有看到问题:

gremlin> g  = TitanFactory.open("conf/titan-cassandra.properties")
==>titangraph[cassandrathrift:[127.0.0.1]]
gremlin> mgmt = g.managementSystem
==>com.thinkaurelius.titan.graphdb.database.management.ManagementSystem@2227a6c1
gremlin> key = mgmt.makePropertyKey('__id').dataType(String.class).make()
==>__id
gremlin> mgmt.buildIndex("byId",Vertex.class).addKey(key).buildCompositeIndex()
==>com.thinkaurelius.titan.graphdb.database.management.TitanGraphIndexWrapper@6d4c273c
gremlin> mgmt.commit()
==>null
gremlin> mgmt = g.managementSystem
==>com.thinkaurelius.titan.graphdb.database.management.ManagementSystem@79d743e6
gremlin> mgmt.containsGraphIndex("byId")
==>true
gremlin> mgmt.rollback()
==>null
gremlin> v = g.addVertex()
==>v[256]
gremlin> v.setProperty("__id","123")
==>null
gremlin> g.commit()
==>null
gremlin> g.V
12:56:45 WARN  com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx  - Query requires iterating over all vertices [()]. For better performance, use indexes
==>v[256]
gremlin> g.V("__id","123")
==>v[256]
gremlin> g.V.has("__id","123")
==>v[256]

注意我没有得到任何关于“...使用索引”的丑陋信息。也许你可以在这里尝试我的例子,看看在回到你的代码之前它是否符合预期。

更新:回答上面关于自定义步骤的更新问题。正如您发现的帖子所指出的那样,Titan的查询优化器似乎无法对此进行排序。我认为在这个例子中很容易理解为什么:

gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> Gremlin.defineStep('hasName', [Vertex,Pipe], { n -> _().has('name',n) })
==>null
gremlin> g.V.hasName('marko')
==>v[1]
gremlin> g.V.hasName('marko').toString()
==>[GremlinStartPipe, GraphQueryPipe(vertex), [GremlinStartPipe, PropertyFilterPipe(name,EQUAL,marko)]]

“已编译”的Gremlin看起来像上面的最后一行。请注意,自定义步骤将编译为具有新GremlinStartPipe的“内部”管道。在没有自定义步骤的情况下将其与之相比:

gremlin> g.V.has('name','marko').toString()
==>[GremlinStartPipe, GraphQueryPipe(has,vertex), IdentityPipe]

Titan可以使用嵌入式has优化“GraphQueryPipe”,但似乎自定义步骤的签名不是这种情况。我认为解决方法(至少在这个特定情况下是编写一个返回管道的函数。

gremlin> def hasName(g,n){g.V.has('name',n)}  
==>true
gremlin> hasName(g,'marko')
==>v[1]
gremlin> hasName(g,'marko').toString()
==>[GremlinStartPipe, GraphQueryPipe(has,vertex), IdentityPipe]

将'g'传递给有点臭的人。也许编写你的DSL,以便'g'被包装在一个类中,然后让你做:

with(g).hasName('marko')

最后的想法是使用Groovy元编程工具:

gremlin> Graph.metaClass.hasName = { n -> delegate.V.has('name',n) }
==>groovysh_evaluate$_run_closure1@600b9d27
gremlin> g.hasName("marko").toString()                              
==>[GremlinStartPipe, GraphQueryPipe(has,vertex), IdentityPipe]
gremlin> g.hasName("marko")                                         
==>v[1]