2017-02-13 13 views
1

Я читал, что использование внутренних идентификаторов Neo4j для внешних целей - не очень хорошая практика.Neo4j SDN4 и правильное использование внутренних идентификаторов

Я думаю, что допустил ошибку в своем приложении SDN4/Neo4j, потому что я использую внутренние идентификаторы везде.

Каждый SDN объект 4 узла в моем приложении есть следующее свойство:

@GraphId 
private Long id; 

я использую это длинное значение как часть моих URL-адресов веб-приложений .. например

/products/3245234 

где 3245234 является внутренним идентификатором Neo4j для этого объекта узла продукта.

Безопасно ли с точки зрения Neo4j - использовать внутренние идентификаторы таким образом? Если нет, не могли бы вы привести пример, как новые ключи суррогата могут решить эту проблему.

ответ

5

Что Эрик сказал правильно, когда дело доходит до того, что внутренние ID-устройства Neo4j могут быть переработаны.

Мы начали добавлять поддержку SDN, чтобы помочь разработчикам обойти это. Мы можем сделать это на нескольких примерах.

Пример 1: Если у вас есть естественный ID

Допустим, у нас есть объект домена User и однозначно идентифицировать полем называется email. Мы могли бы создать нашу модель так:

@NodeEntity 
public class User { 

    @GraphId 
    private Long id; 

    @Index(unique=true, primary=true) 
    private String email; 

    ... 

} 

Затем мы можем иметь хранилище создать как таковые:

public interface UserRepository extends CrudRepository<User, String> { 

} 

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

Теперь вы можете сделать что-то вроде:

User user = userRepository.findOne("[email protected]"); 

Посмотрите, как вы можете просто передать в основной идентификатор для класса?

Пример 2: Если вам нужен синтетический ID

Допустим, пользователь мы определили выше, имеет твитов. Поскольку нет никакого естественного идентификатора для твита, мы даем его. Лучший способ избежать столкновения с ID - использовать UUID типа 4. К счастью, Java поставляется с предварительной загрузкой UUID, и SDN поддерживает ее сохранение.

import org.neo4j.ogm.annotation.typeconversion.Convert; 
import org.neo4j.ogm.typeconversion.UuidStringConverter; 
import java.util.UUID; 

@NodeEntity 
public class Tweet { 

    @GraphId 
    private Long id; 

    @Convert(UuidStringConverter.class) 
    @Index(unique = true, primary = true) 
    private UUID uuid; 

    ... 

    public Tweet(String message) { 
     this.uuid = UUID.randomUUID(); 
     // other initialisation. 
    } 
} 

Итак, что мы имеем здесь UUID назначен любой созданный чирикать. Затем это можно сохранить в базе данных через конвертер. Удобная вещь в том, что для установки нет дополнительных библиотек. Также гарантируется (ну, по большей части!), Чтобы никогда не было проблем, с которыми сталкиваются внутренние идентификаторы Neo4j. Про (или con) - это идентификаторы, которые производятся, чтобы быть универсально уникальными по вашему приложению.

Если вы хотите, чтобы база данных всегда генерировала UUID, я также рекомендовал бы плагин GraphAware https://github.com/graphaware/neo4j-uuid.

Опять Tweet Repository может воспользоваться этим:

public interface TweetRepository extends CrudRepository<Tweet, UUID> { 

} 

Теперь вы можете сделать что-то вроде:

Tweet tweet = tweetRepository.findOne(UUID.fromString("0f6e7004-cefc-4397-b4d2-078c1370856a")); 

Заключительное примечание; на момент написания @Indexed(unique=true,primary=true) может быть изменен просто называться @Id в SDN 5.0.

+0

Благодарим за подробный ответ! Один последующий вопрос о запросе Cypher и 'UUID'. Раньше в качестве параметров для моего запроса Cypher я использовал 'Ids (@GraphId)' и следующие операторы - например, где 'WHERE ID (p) в {productIds}'. Прямо сейчас вместо внутренних идентификаторов мне нужно передать набор 'UUID'. Как правильно использовать эти 'UUID' в Cypher -' ID (p) IN {productUUIDs} 'или simlpe' p IN {productUUIDs} '. Кроме того, есть ли разница в производительности с точки зрения производительности между 'GraphId' и' @Index (unique = true, primary = true) private UUID uuid'? – alexanoid

+0

Вы должны иметь возможность сделать что-то вроде 'WHERE p.uuid IN {productUuids}', где 'productUuids' являются представлениями String. Я не уверен, что мы поддерживаем преобразование параметров методов репозитория на данный момент, но мы будем в следующем выпуске. Что касается производительности, если вы включаете autoindexing или вы уже проиндексировали свойство uuid этого ярлыка, тогда он должен быть очень быстрым, поскольку поиск выполняется с помощью индексов. – digx1

4

С точки зрения приложения, использование внутреннего идентификатора Neo4j безопасно, поскольку ничто в вашем приложении не будет разбито, используя их.

Оказалось, что внутренние идентификаторы Neo4j переработаны, и я имею в виду, что у узла или отношения есть внутренний идентификатор 12345, и в какой-то момент удаляется узел или связь, идентификатор 12345 становится пригодным для повторного использования в будущем узла или отношения. Я считаю разумным предположить, что новый доступный идентификатор будет повторно использоваться в какой-то момент в будущем. Это отрицательный побочный эффект от того, что внутренние идентификаторы Neo4j не считаются «стабильными» и не должны использоваться вне вашего приложения.

Что касается примера нового суррогатного ключа, я бы указал вам на проект neo4j-uuid GraphAware по адресу https://github.com/graphaware/neo4j-uuid. Этот плагин Neo4j можно использовать для автоматического создания уникального и стабильного UUID для всех узлов и отношений, которые не будут изменены и не будут изменены.