无法创建复合索引,卡在“已安装”状态

17

我无法创建索引。我的 Gremlin 代码如下:

usernameProperty = mgmt.getPropertyKey('username')
usernameIndex = mgmt.buildIndex('byUsernameUnique', Vertex.class).addKey(usernameProperty).unique().buildCompositeIndex()
mgmt.setConsistency(usernameIndex, ConsistencyModifier.LOCK)
mgmt.commit()

我收到两个错误:

18:04:57 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - 将[1@0a00009d2537-ip-10-0-0-1572]从高速缓存中删除,但等待事务关闭的时间太长。 在以下内容上过期的事务提醒:[standardtitantx [0x6549ce71]] 18:04:57 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - 将[1@0a00009d2537-ip-10-0-0-1572]从高速缓存中删除,但等待事务关闭的时间太长。 在以下内容上过期的事务提醒:[standardtitantx [0x2a2815cc],standardtitantx [0x025dc2c0]]

索引状态卡在已安装

usernameIndex.getIndexStatus(usernameProperty)
==>INSTALLED

我读到说一个失败的实例可能会导致这个问题,但是运行实例的检查只显示了一个:

mgmt.getOpenInstances()
==>0a00009d3011-ip-10-0-0-1572(current)

我还尝试了发出REGISTER_INDEX操作,但是也出现了类似的错误消息并从事务缓存中删除:

mgmt.updateIndex(usernameIndex, SchemaAction.REGISTER_INDEX).get()
mgmt.commit()

我也尝试了多次重新启动服务器。

看起来注册过程只是超时了,导致从事务缓存中"逐出"。我等了48个小时,只是为了确保这不是一个缓慢的过程。正常的读取,写入和关联提交到Titan的操作似乎都能正常工作,我只是不能创建这个索引。我被卡住了,还有其他我可以尝试的东西吗?是否有一种方法可以延长事务的超时时间?

我正在使用DynamoDB后端运行Titan 1.0.0(使用AWS提供的CloudFormation模板进行设置)。

编辑: 这是完整的命令,我将它粘贴到Gremlin中,并添加了@M-T-A建议的awaitGraphStatus步骤:

mgmt = graph.openManagement();
usernameIndex = mgmt.getPropertyKey('usernameIndex');
mgmt.buildIndex('byUsername',Vertex.class).addKey(usernameIndex).unique().buildCompositeIndex();
// I have tried with and without a commit here: mgmt.commit();
mgmt.awaitGraphIndexStatus(graph, 'byUsername').status(SchemaStatus.REGISTERED).timeout(10, java.time.temporal.ChronoUnit.MINUTES).call();

这导致了以下错误:

java.lang.NullPointerException at com.thinkaurelius.titan.graphdb.database.management.GraphIndexStatusWatcher.call(GraphIndexStatusWatcher.java:52) at com.thinkaurelius.titan.graphdb.database.management.GraphIndexStatusWatcher.call(GraphIndexStatusWatcher.java:18) at java_util_concurrent_Callable$call.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:114) at groovysh_evaluate.run(groovysh_evaluate:3) at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:215) at org.codehaus.groovy.tools.shell.Interpreter.evaluate(Interpreter.groovy:69) at org.codehaus.groovy.tools.shell.Groovysh.execute(Groovysh.groovy:185) at org.codehaus.groovy.tools.shell.Shell.leftShift(Shell.groovy:119) at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:94)

我还需要注意的是,禁用和删除索引的例程也失败了。

mgmt = graph.openManagement()
theIndex = mgmt.getGraphIndex('byUsername')
mgmt.updateIndex(theIndex, SchemaAction.DISABLE_INDEX).get()
mgmt.commit()
mgmt.awaitGraphIndexStatus(graph, 'byUsername').status(SchemaStatus.DISABLED).timeout(10, java.time.temporal.ChronoUnit.MINUTES).call();
m = graph.openManagement()
i = m.getGraphIndex('byUsername')
m.updateIndex(i, SchemaAction.REMOVE_INDEX).get()
m.commit()

19:26:26 ERROR com.thinkaurelius.titan.graphdb.database.management.ManagementLogger - 将[1@ac1f3fa810472-ip-172-31-63-1681]从缓存中驱逐,但等待事务关闭的时间太长。在以下事务上出现过期事务警报:[standardtitantx [0x2314cd97],standardtitantx [0x39f8adc0],standardtitantx [0x09de1b85]]

编辑2: 尝试在同一事务中创建新属性键和索引是可行的!但这是否意味着我不能在现有属性键上创建索引??

graph.tx().rollback();
mgmt = graph.openManagement();
indexName = 'byUsernameTest2';
propertyKeyName = 'testPropertyName2';
propertyKey = mgmt.makePropertyKey(propertyKeyName).dataType(String.class).cardinality(Cardinality.SINGLE).make();
mgmt.buildIndex(indexName,Vertex.class).addKey(propertyKey).buildCompositeIndex();
mgmt.commit();
graph.tx().commit();
mgmt.awaitGraphIndexStatus(graph, indexName).status(SchemaStatus.REGISTERED).timeout(10, java.time.temporal.ChronoUnit.MINUTES).call();
mgmt.commit();

暂停一段时间后,结果为:

此管理系统实例已关闭

尝试获取新索引会导致:

mgmt = graph.openManagement();
index = mgmt.getGraphIndex('byUsernameTest2');
propkey = mgmt.getPropertyKey('testPropertyName2');
index.getIndexStatus(propkey);

==>已启用


1
为了获得更多的调试日志,请将以下内容添加到./conf/log4j-console.properties文件中: log4j.logger.com.thinkaurelius.titan.graphdb.database.management=DEBUG - Jason Plurad
你有一个大型数据集存储吗?你尝试过在一个几乎空的数据库上运行吗? - Kuzeko
2个回答

4
如果您正在运行多个Titan实例,则应注意它们需要协调才能使索引可用。
此外,事务管理存在各种微妙之处,以及在什么情况下会保留事务的开放状态。我认为Titan 1.0.0在这方面没有最新的TinkerPop。您是否尝试在启动后立即创建索引?
最后,索引创建过程取决于被索引的属性键是否已经被使用过。您是要索引新键还是现有键?

我在单个AWS t2.micro实例(Linux)上运行单个实例。是的,我尝试过重新启动服务器并立即创建索引,但没有成功。我尝试使用一些现有顶点进行索引,这些顶点使用属性键。我还删除了所有顶点并尝试创建索引。每次都得到相同的结果。 - Fook
1
就此而言,删除所有顶点不会影响重新索引的需要 - 决定是基于属性键是否在模式中,并且Titan中的模式是不可变的。我肯定会尝试通过在以前从未使用过的属性键上创建索引来复现(当然,您必须在同一管理事务中创建它们)。 - Benjamin Anderson
尝试了您的建议,但仍然失败。我尝试在同一事务中创建一个全新的属性键和该属性键上的索引。请参见我的编辑2。 - Fook
好的,这确实奏效了。我有一个工作的索引!那么为什么我不能在现有的属性键上创建索引呢?编辑2已更新。 - Fook
你应该能够在现有的属性键上创建索引,但正如另一个答案提到的那样,在索引可用之前,你需要启动重新索引。如果你仍然看到过期的事务警报,我建议你先尝试追踪这些警报。我不认为过期的事务清理逻辑会使索引“可重新索引”。 - Benjamin Anderson
“被驱逐”(Evicted)失效事务提示肯定是问题所在。这似乎会导致索引在创建过程中停滞在“已安装”状态。同一事务期间创建属性键时不会发生这种情况,只有在查找现有属性键时才会发生。因此,问题在于如何解决“被驱逐”问题,这就是我目前遇到的难题。 - Fook

4

您需要等待Titan和DynamoDB注册索引,可以通过以下方式实现:

ManagementSystem.awaitGraphIndexStatus(graph, propertyKeyIndexName)
                    .status(SchemaStatus.REGISTERED)
                    .timeout(10, java.time.temporal.ChronoUnit.MINUTES) // set timeout to 10 min
                    .call();

默认的超时时间通常不够长,你可以将它增加到10分钟,通常这对于Dynamo后端来说足够了。
只有当索引处于REGISTERED状态时,才能执行重新索引。重新索引完成后,需要等待直到ENABLED状态。通过重用上述代码示例并将状态更改为ENABLED即可实现。
欲了解更多信息,请参阅文档

编辑

让我分享一下在伯克利和Dynamo DB后端上始终有效的代码。
    graph.tx().rollback(); //Never create new indexes while a transaction is active
    TitanManagement mgmt=graph.openManagement();
    PropertyKey propertyKey=getOrCreatePropertyKeyIfNotExist(mgmt, propertyKeyName);
    String indexName = makePropertyKeyIndexName(propertyKey);

    if (mgmt.getGraphIndex(indexName)==null) { 
        mgmt.buildIndex(indexName, Vertex.class).addKey(propertyKey).buildCompositeIndex();
        mgmt.commit(); // you MUST commit mgmt
        graph.tx().commit(); // and commit the transaction too
        ManagementSystem.awaitGraphIndexStatus(graph, indexName).status(SchemaStatus.REGISTERED).call();
    }else { // already defined.
        mgmt.rollback();
        graph.tx().rollback();
    }

private static PropertyKey getOrCreatePropertyKeyIfNotExist(TitanManagement mgmt, String s) {
    PropertyKey key = mgmt.getPropertyKey(s);
    if (key != null)
        return key;
    else
        return mgmt.makePropertyKey(s).dataType(String.class).make();
}

private static String makePropertyKeyIndexName(PropertyKey pk) {
    return pk.name() + Tokens.INDEX_SUFFIX;
}

根据我看到的错误,似乎Titan无法获取索引,这意味着您正在等待甚至未定义的索引。请查看导致错误的行此处。确保将正确的索引名称传递给awaitGraphIndexStatus

在使用 Gremlin 控制台时,必须导入该类。我已经为您更新了答案。 - Mohamed Taher Alrefaie
添加这一步会导致java.lang.NullPointerException错误。我已经编辑了问题,包括我粘贴到Gremlin中的确切命令。 - Fook
有一些成功!请查看编辑2。只有在同一事务中创建属性键时,我才能使用您的代码创建索引。您能告诉我为什么无法在现有的属性键上创建索引吗? - Fook
不要使用 makePropertyKey,请使用一个名为 getOrCreatePropertyKey 的方法,或者使用我的例程来获取属性键。这样可以吗? - Mohamed Taher Alrefaie
@Fook 这个 方法 - Mohamed Taher Alrefaie
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接