【问题标题】:Neo4j 1.9.9 legacy index very slow after deletesNeo4j 1.9.9 旧版索引在删除后非常慢
【发布时间】:2015-03-03 21:20:18
【问题描述】:

使用 Neo4j 1.9.9。 我们正在运行的一些 Cypher 查询似乎异常缓慢。一些调查表明:

  • 在我的硬件 (MacBook Pro) 上删除 200k 个节点大约需要 2-3 秒,当我使用以下方法选择它们时:

    START n=node(*) DELETE n
    
  • 添加 WHERE 子句不会显着减慢速度

  • 如果节点是使用索引选择的,它具有相似的性能,例如

    START n=node:__types__(className="com.e2sd.domain.Comment") DELETE n
    
  • 除了,重复上一次测试时,速度会慢 20 倍或更多,实际时间从 80 秒到数百秒不等。更奇怪的是,我是在同一个 JVM 中重复测试还是启动一个新程序,或者清除数据库中的所有节点并验证它是否有零节点都没有关系。在测试的任何后续运行中,基于索引的删除都非常慢直到我用

    破坏了我的 neo4j 数据目录
     rm -R target/neo4j-test/
    

我将在这里给出一些示例 Scala 代码。我很乐意根据需要提供更多详细信息。

for (j <- 1 to 3) {
  log("Total nodes in database: " + inNeo4j( """ START n=node(*) RETURN COUNT(n) """).to(classOf[Int]).single)
  log("Start")
  inNeo4j(""" CREATE (x) WITH x FOREACH(i IN RANGE(1, 200000, 1) : CREATE ({__type__: "com.e2sd.domain.Comment"})) """)
  rebuildTypesIndex()
  log("Created lots of nodes")
  val x = inNeo4j(
    """
    START n=node:__types__(className="com.e2sd.domain.Comment")
    DELETE n
    RETURN COUNT(n)
    """).to(classOf[Int]).single
  log("Deleted x nodes: " + x)
}

// log is a convenience method that prints a string and the time since the last log
// inNeo4j is a convenience method to run a Cypher query



def rebuildTypesIndex(): Unit = {
  TransactionUtils.withTransaction(neo4jTemplate) {
    log.info("Rebuilding __types__ index...")
    val index = neo4jTemplate.getGraphDatabase.getIndex[Node]("__types__")
    for (node <- GlobalGraphOperations.at(neo4jTemplate.getGraphDatabaseService).getAllNodes.asScala) {
      index.remove(node)
      if (node.hasProperty("__type__")) {
        val typeProperty = node.getProperty("__type__")
        index.add(node, "className", typeProperty)
      }
    }
    log.info("Done")
  }
}

我们在这里使用嵌入了带有以下 Spring Data 配置的 Neo4j。

<bean id="graphDbFactory" class="org.neo4j.graphdb.factory.GraphDatabaseFactory"/>
<bean id="graphDatabaseService" scope="singleton" destroy-method="shutdown"
  factory-bean="graphDbFactory" factory-method="newEmbeddedDatabase">
  <constructor-arg value="target/neo4j-test"/>
</bean>
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="my.package.*"/>

为什么DELETE查询在描述的条件下很慢?

【问题讨论】:

  • 我认为你必须专门从遗留索引中删除条目,不确定删除节点是否足够。因此,当您第二次运行它时,您的索引中有 400k 条目,即使其中一半指向已删除的节点。通过这种方式,您的程序很慢,因为重复运行会扩展索引的大小。
  • 这是一个很好的假设——我没有想到删除节点会默默地在索引中留下挂起的引用,但考虑到其他有意义的行为!
  • 如果你提交了一个答案,我会测试这个假设,如果正确,我会奖励赏金。不过你得快点,它很快就会到期。
  • 在索引中有 2 个条目(其中一半指向已删除节点)会导致 20 倍减速,这似乎很奇怪。
  • 你的理论是正确的。如果您今天提交答案,我仍然可以奖励赏金。

标签: neo4j spring-data-neo4j


【解决方案1】:

您必须专门从旧索引中删除条目,删除节点不足以使其从旧索引中删除。因此,当您第二次运行它时,您的索引中有 400k 条目,即使其中一半指向已删除的节点。通过这种方式,您的程序会很慢,因为重复运行会扩展索引的大小。

我在编写 neo4j 空间扩展以批量加载 RTree 时遇到了这个问题。我必须使用必须从索引中显式删除的 Java API,与删除节点分开。很高兴我能帮上忙。

【讨论】:

  • 我使用 index.query( ":" ) 作为其他一些 StackOverflow 页面中的建议来获取索引中的所有节点,然后删除每个节点,然后继续添加每个节点具有返回索引类型的节点。
猜你喜欢
  • 1970-01-01
  • 2016-11-10
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多