Статьи

Подробнее о Neo4j и импортере партии Майкла Голодера

В конце февраля мы взглянули на пакетный импортер Майкла Хангера . Это отличный инструмент для быстрой загрузки миллионов узлов и связей в Neo4j. Единственное, чего не хватало, это индексирования … Я говорю, потому что я только что отправил запрос на добавление, чтобы добавить эту функцию. Давайте рассмотрим, как это было сделано, чтобы вы получили представление о том, как выглядит API пакетного импорта Neo4j, и в следующей статье блога я покажу вам, как генерировать данные, чтобы использовать их в своих интересах.

Первым делом мне нужно было обновить файл pom.xml, включив в него последнюю версию Neo4j и зависимость от индекса Lucene.

<dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-kernel</artifactId>
            <version>1.8.M05</version>
        </dependency>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-lucene-index</artifactId>
            <version>1.8.M05</version>
        </dependency>

Функция пакетной вставки была перемещена в org.neo4j.unsafe, чтобы напомнить вам, что ее следует использовать только при первой загрузке.

import org.neo4j.unsafe.batchinsert.BatchInserter;
import org.neo4j.unsafe.batchinsert.BatchInserters;
import org.neo4j.unsafe.batchinsert.BatchInserterImpl;
import org.neo4j.unsafe.batchinsert.BatchInserterIndexProvider;
import org.neo4j.unsafe.batchinsert.BatchInserterIndex;
import org.neo4j.unsafe.batchinsert.LuceneBatchInserterIndexProvider;

Мы создаем LuceneBatchInserterIndexProvider с именем lucene из БД:

db = BatchInserters.inserter(graphDb.getAbsolutePath(), config);
lucene = new LuceneBatchInserterIndexProvider(db);

Давайте посмотрим на метод importNodeIndexes:

private void importNodeIndexes(File file, String indexName, String indexType) throws IOException {
    	BatchInserterIndex index;
    	if (indexType.equals("fulltext")) {
    		index = lucene.nodeIndex( indexName, stringMap( "type", "fulltext" ) );
    	} else {
    		index = lucene.nodeIndex( indexName, EXACT_CONFIG );
    	}
        
        BufferedReader bf = new BufferedReader(new FileReader(file));
        
        final Data data = new Data(bf.readLine(), "\t", 1);
        Object[] node = new Object[1];
        String line;
        report.reset();
        while ((line = bf.readLine()) != null) {        
            final Map<String, Object> properties = map(data.update(line, node));
            index.add(id(node[0]), properties);
            report.dots();
        }
                
        report.finishImport("Nodes into " + indexName + " Index");
    }

Мы передаем переменную indexType, чтобы решить, будет ли этот индекс точным или полнотекстовым. Мы создаем индекс с помощью lucene.nodeIndex. Затем мы читаем значения, которые нужно добавить в наш индекс, из переданного файла. Как только мы фиксируем ключ и значения из нашего файла, мы просто передаем их вместе с идентификатором нашего узла в метод add.

Давайте посмотрим на importRelationshipIndexes:

private void importRelationshipIndexes(File file, String indexName, String indexType) throws IOException {
    	BatchInserterIndex index;
    	if (indexType.equals("fulltext")) {
    		index = lucene.relationshipIndex( indexName, stringMap( "type", "fulltext" ) );
    	} else {
    		index = lucene.relationshipIndex( indexName, EXACT_CONFIG );
    	}

        BufferedReader bf = new BufferedReader(new FileReader(file));
        
        final Data data = new Data(bf.readLine(), "\t", 1);
        Object[] rel = new Object[1];
        String line;
        report.reset();
        while ((line = bf.readLine()) != null) {        
            final Map<String, Object> properties = map(data.update(line, rel));
            index.add(id(rel[0]), properties);
            report.dots();
        }
                
        report.finishImport("Relationships into " + indexName + " Index");

    }

Он практически идентичен, но мы создаем индексы отношений вместо индексов узлов. Наконец, нам нужно отключить Lucene, а также наш график.

    private void finish() {
        lucene.shutdown();
        db.shutdown();
        report.finish();
    }

Вы можете посмотреть полный исходный код по адресу https://github.com/maxdemarzi/batch-import .

Чтобы использовать его, мы добавим четыре аргумента для каждого индекса в командной строке:

Чтобы создать полнотекстовый индекс узлов с именем users, использующий node_index.csv:

node_index users fulltext nodes_index.csv 

Чтобы создать точный индекс отношений с именем работал, используя rels_index.csv:

rel_index worked exact rels_index.csv

Пример командной строки:

java -server -Xmx4G -jar ../batch-import/target/batch-import-jar-with-dependencies.jar neo4j/data/graph.db nodes.csv rels.csv node_index users fulltext nodes_index.csv rel_index worked exact rels_index.csv

Мы ожидаем, что node_index.csv будет выглядеть так:

id	name	language
1	Victor Richards	West Frisian
2	Virginia Shaw	Korean
3	Lois Simpson	Belarusian
4	Randy Bishop	Hiri Motu
5	Lori Mendoza	Tok Pisin

Мы ожидаем, что rels_index.csv будет выглядеть так:

id	property1	property2
0	cwqbnxrv	rpyqdwhk
1	qthnrret	tzjmmhta
2	dtztaqpy	pbmcdqyc

Столбцы id ссылаются на идентификатор узла или отношения. Заголовки — это ключи индекса, а значения в каждой строке — это то, что будет добавлено в индекс для этого ключа.

Следуйте за мной в Твиттере на @maxdemarzi, и вы узнаете, когда будет опубликовано следующее сообщение в блоге, которое использует эти функции.