2017-02-13 56 views
1

我讀到使用Neo4j內部ID用於外部目的不是一個好習慣。Neo4j SDN4和內部Ids的正確用法

我想我在SDN4/Neo4j應用程序中犯了一個錯誤,因爲我在任何地方都使用內部標識符。在我的應用

每個SDN 4點實體有以下特性:

@GraphId 
private Long id; 

我用這個長值作爲我的web應用程序的URL的一部分。例如

/products/3245234 

其中3245234是此產品節點實體的內部Neo4j標識符。

從Neo4j的角度來看它是否安全 - 以這種方式使用內部ID?如果不是,請你舉個例子說明一個新的代理鍵可以解決這個問題。

回答

5

埃裏克在談到如何回收Neo4j內部ID的時候說的是正確的。

我們已經開始爲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]"); 

看你怎麼可以只通過在類的主ID?

例2:當你需要一個合成的ID

假設我們上面定義的用戶鳴叫。由於tweet沒有自然ID,我們給它一個。避免ID衝突的最好方法是使用類型4的UUID。幸運的是,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 ID的問題。 pro(或con)是ID的製造是通用的,由您的應用程序代碼獨一無二。

如果您希望讓數據庫始終生成UUID,那麼我還會推薦GraphAware https://github.com/graphaware/neo4j-uuid插件。

再次鳴叫庫可以利用這一點:

public interface TweetRepository extends CrudRepository<Tweet, UUID> { 

} 

現在你可以這樣做:

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

最後需要說明的;在撰寫本文時,SDN 5.0中可能更改爲@Indexed(unique=true,primary=true),簡稱爲@Id

+0

非常感謝您的詳細解答!關於Cypher查詢和「UUID」的一個後續問題。以前,作爲我的Cypher查詢的一個參數,我使用了'Ids(@GraphId)'和以下語句 - 例如{productIds}中的WHERE ID(p)'。現在,我不得不通過一個集合'UUID'。如何在Cypher中正確使用這些'UUID' - ID(p)IN {productUUIDs}'或simlpe'p IN {productUUs}}。另外,與'GraphId'和'@Index(unique = true,primary = true)private UUID uuid'之間的性能角度有什麼不同? – alexanoid

+0

您應該可以執行類似於'WHERE p.uuid IN {productUuids}'的地方,其中'productUuids'是字符串表示。我不確定目前是否支持存儲庫方法的參數轉換,但是我們將在下一個版本中進行。關於性能,如果你打開autoindexing或者你已經索引了標籤的uuid屬性,那麼它應該非常快,因爲查找是通過索引完成的。 – digx1

4

從應用程序視圖來看,使用Neo4j內部ID是安全的,因爲應用程序中的任何內容都不會因使用它而中斷。

也就是說,Neo4j內部ID是回收的,我的意思是如果一個節點或關係的內部ID爲12345,並且在某些時候節點或關係被刪除,那麼12345的ID就有資格被未來重用節點或關係。我相信明智的做法是假設新的可用ID將在未來的某個時間點被重用。這具有Neo4j內部ID不被認爲是「穩定」的負面影響,不應該在應用程序之外使用。

至於一個新的代理鍵的例子,我會指向你的GraphAware的neo4j-uuid項目https://github.com/graphaware/neo4j-uuid。這個Neo4j插件可用於在所有節點和關係上自動創建唯一且穩定的UUID,這些UUID不會也不能更改或更新。