2015-03-03 3 views
5

Использование Neo4j 1.9.9. Некоторые запросы Cypher, с которыми мы работали, казались необоснованно медленными. Некоторые исследования показали, что:Neo4j 1.9.9 устаревший индекс очень медленный после удаления

  • Удалить 200k узлы занимает около 2-3 секунд на моем оборудовании (MacBook Pro), когда я выбираю их с помощью:

    START n=node(*) DELETE n 
    
  • Добавление ИНЕКЕ не существенно замедлить его

  • Если узлы были выбраны с использованием индекса, он имеет схожую производительность, например

    START n=node:__types__(className="com.e2sd.domain.Comment") DELETE n 
    
  • За исключением, что при повторении предыдущего теста, это 20x или более медленным, с фактическим временем колеблется от 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") 
    } 
} 

Мы используем встроенный Neo4j со следующей конфигурацией Spring Data.

<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 медленный в описанных условиях?

+0

Я думаю, что вам нужно специально удалить записи из устаревшего индекса, не уверенные, что удаления узла достаточно. Таким образом, когда вы запускаете его во второй раз, у вас есть 400k записей в вашем индексе, хотя половина из них указывает на удаленные узлы. Таким образом, ваша программа медленная, так как повторные прогоны расширяют размер индекса. –

+0

Это довольно хорошая гипотеза: мне не приходило в голову, что удаление узла тихо оставило бы висячие ссылки в индексе, но учитывая другое поведение, которое имеет смысл! –

+0

Если вы подадите ответ, я проверю эту гипотезу и принесу награду, если она будет исправлена. Вы должны спешить, но скоро это закончится. –

ответ

2

Вы должны специально удалить записи из устаревшего индекса, удаление узлов недостаточно, чтобы удалить его из устаревшего индекса. Таким образом, когда вы запускаете его во второй раз, у вас есть 400k записей в вашем индексе, хотя половина из них указывает на удаленные узлы. Таким образом, ваша программа медленная, так как повторные прогоны расширяют размер индекса.

У меня была эта проблема, когда я написал расширение для neo4j для объемной загрузки RTree. Я должен был использовать Java API, который вы должны явно удалить из индекса отдельно от удаления узла. Рад, что смог помочь.

+0

Я использовал index.query («*: *»), как предлагалось на некоторых других страницах StackOverflow, чтобы получить все узлы в индексе, а затем удалить их, а затем продолжить добавлением каждого узла с типом обратно в индекс. –

Смежные вопросы