Статьи

Расширение Neo4j

Одна из замечательных особенностей Neo4j заключается в том, насколько легко его расширить. Вы можете расширить Neo4j с помощью плагинов и неуправляемых расширений . Два замечательных примера плагинов — это плагин Gremlin (который позволяет использовать библиотеку Gremlin с Neo4j) и плагин Spatial (который позволяет выполнять пространственные операции, такие как поиск данных в указанных регионах или на заданном расстоянии от интересующей точки).

Плагины предназначены для расширения возможностей базы данных, узлов или связей. Неуправляемые расширения предназначены для того, чтобы вы могли делать все, что захотите. Эта великая сила приходит с большой ответственностью, поэтому будьте осторожны с тем, что вы делаете здесь. Дэвид Монтэг (David Montag) подготовил шаблон неуправляемого расширения, который мы могли бы использовать на github, поэтому давайте попробуем. Мы собираемся клонировать проект, скомпилировать его, загрузить Neo4j, настроить Neo4j для использования расширения, протестировать расширение и немного его настроить.

Начните с клонирования проекта:

git clone git://github.com/dmontag/neo4j-unmanaged-extension-template.git
cd neo4j-unmanaged-extension-template

Давайте добавим Neography в наш gemfile и установим его:

echo "gem 'neography' " > Gemfile
bundle install 

Тогда давайте продолжим и установим Neo4j. Для этого проекта я собираюсь использовать версию Neo4j 1.8 для предприятий:

echo "require 'neography/tasks'" > Rakefile
rake neo4j:install[enterprise,1.8]

Убедитесь, что вы уже не используете Neo4j, поскольку следующим шагом будет загрузка и создание шаблона неуправляемого расширения, включающего некоторые тесты, которые не пройдут, если у вас уже есть Neo4j, запущенный где-то.

mvn clean package

Это загрузит и сделает свое дело, если у вас не установлен Maven (введите mvn -version, чтобы увидеть, если вы это сделаете). Наконец вы должны увидеть:

...
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ unmanaged-extension-template ---
[INFO] Building jar: /Users/maxdemarzi/Projects/neo4j-unmanaged-extension-template/target/unmanaged-extension-template-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.153s
[INFO] Finished at: Tue Nov 13 22:16:40 CST 2012
[INFO] Final Memory: 27M/218M
[INFO] ------------------------------------------------------------------------

Теперь мы можем скопировать созданный jar-файл в каталог плагинов Neo4j:

cp target/unmanaged-extension-template-1.0.jar neo4j/plugins/

Прежде чем это сработает, нам нужно сообщить Neo4j о нашем новом неуправляемом расширении, добавив строку в файл neo4j-server.properties в каталоге neo4j / conf:

echo "org.neo4j.server.thirdparty_jaxrs_classes=org.neo4j.example.unmanagedextension=/example" >> neo4j/conf/neo4j-server.properties

Мы говорим Neo4j загрузить это неуправляемое расширение и сделать «/ пример» конечной точкой остальных API. Теперь мы можем запустить сервер Neo4j …

rake neo4j:start

… и проверить это с помощью curl:

curl http://localhost:7474/example/service/helloworld
Hello World!

или через консоль http в веб-администраторе:

Это работает потому, что файл jar содержит содержимое /src/main/java/org/neo4j/example/unmanagedextension/MyService.java, в котором вы найдете:

@Path("/service")
public class MyService {

    @GET
    @Path("/helloworld")
    public String helloWorld() {
        return "Hello World!";
    }

Этот очень простой метод просто возвращает строку с сервера всякий раз, когда мы ее вызываем. Давайте попробуем что-нибудь более полезное, например, прогрев кеша узлов и отношений. Нам нужно сначала создать некоторые узлы и отношения. Отредактируйте ваш Rakefile, чтобы он выглядел так:

require 'neography'
require 'neography/tasks'

namespace :neo4j do
  task :create do
    neo = Neography::Rest.new
    nodes = {}
    5.times do |x|
      5.times do |y|
       node = neo.create_node({:x => x.to_f, :y=> y.to_f}) 
       nodes["#{x}-#{y}"] = node["self"].split('/').last
      end
    end
    
    4.times do |x|
      4.times do |y|
       neo.create_relationship("next_to", 
                               nodes["#{x}-#{y}"], 
                               nodes["#{x+1}-#{y}"], 
                               {:time => (1 + rand(4)).to_f }) 
       neo.create_relationship("next_to", 
                               nodes["#{x}-#{y}"], 
                               nodes["#{x}-#{y+1}"], 
                               {:time => (1 + rand(4)).to_f }) 
      end
      neo.create_relationship("next_to", 
                              nodes["#{x}-4"], 
                              nodes["#{x+1}-4"], 
                              {:time => (1 + rand(4)).to_f }) 
      neo.create_relationship("next_to", 
                              nodes["4-#{x}"], 
                              nodes["4-#{x+1}"], 
                              {:time => (1 + rand(4)).to_f }) 
    end
        
  end
end

Затем запустите:

rake neo4j:create

… чтобы создать свой график. Я объясню, почему мы создали этот конкретный график в последующем сообщении в блоге, а пока вернемся к нашему файлу MyService.java. Мы будем использовать инструмент GlobalGraphOperations и добавим следующее:

import org.neo4j.tooling.GlobalGraphOperations;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;

    @GET
    @Path("/warmup")
    public String warmUp(@Context GraphDatabaseService db) {
		Node start;
		for ( Node n : GlobalGraphOperations.at( db ).getAllNodes() ) {
		   n.getPropertyKeys();
		   for ( Relationship relationship : n.getRelationships() ) {
              start = relationship.getStartNode();
           }
        }
        for ( Relationship r : GlobalGraphOperations.at( db ).getAllRelationships() ) {
          r.getPropertyKeys();
          start = r.getStartNode();
        }
    return "Warmed up and ready to go!";
    }

Приведенный выше код сначала проходит через каждый узел, вызывает его свойства, а затем вызывает отношения, которые имеет этот узел. Затем код перебирает все отношения, вызывает их свойства, затем вызывает узлы, которые он соединяет. Вышеприведенная последовательность эффективно согревает ваши кеши. Если ваш график помещается в память, это заполняет базу данных. Если ваш график не помещается в памяти, возможно, вы хотите указать определенный набор узлов или отношений для разогрева. В любом случае вы, вероятно, не хотите запускать это снова и снова или предоставлять его своим конечным пользователям. Помните, что я сказал об ответственности за то, что вы делаете здесь.

Вам придется остановить Neo4j, перекомпилировать его, скопировать новый файл JAR поверх существующего, перезапустить Neo4j и запустить команду.

rake neo4j:stop
mvn clean package
cp target/unmanaged-extension-template-1.0.jar neo4j/plugins/
rake neo4j:start
curl http://localhost:7474/example/service/warmup

Если все прошло хорошо, вы должны увидеть:

Warmed up and ready to go!

… И посмотрите на ваш кэш узлов и отношений на странице информации о сервере веб-администрирования Neo4j:

Если вы не видите их, вы, вероятно, используете версию для сообщества вместо корпоративной версии. Если все числа равны нулю, значит, что-то пошло не так. Пересмотрите свои шаги и дайте мне знать, если какая-то часть этого сбивает с толку, чтобы я мог лучше объяснить это. Вы можете увидеть мою копию MyService.java на github .

Кстати, если вам нужен только тёплый кеш, вы можете сделать то же самое с Cypher, используя:

START n=node(*) 
MATCH n -[r?]-> () 
RETURN count(n.property_i_do_not_have?)+count(r.property_i_do_not_have?)

Знаете ли вы, что « Cypher » — это термин, используемый для описания фристайла в группе?

Ну, теперь ты знаешь. Оставайтесь с нами для второй части этой серии.