neo4j是面向?qū)ο蠡趈ava的 ,被設(shè)計為一個建立在java之上、可以直接嵌入應(yīng)用的數(shù)據(jù)存儲。此后,其他語言和平臺的支持被引入,neo4j社區(qū)獲得持續(xù)增長,獲得了越來越多的技術(shù)支持者。目前已支持.net、ruby、python、node.js及php等。因此,不管是什么項目,沒有理由不引入neo4j。
本文重點(diǎn)介紹python,這門語言的哲學(xué)與java大大不同,同時展示py2neo庫如何被用來建立一個簡單的應(yīng)用程序。
一個快速的rest例子
首先來看些基本知識。如果沒有服務(wù)api,neo4j就不能支持其他語言。該接口提供一組基于json消息格式的restful web服務(wù)和一個全面的發(fā)現(xiàn)機(jī)制。使用中使用這個接口的最快和最容易的方法是通過使用curl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$ curl http: / / localhost: 7474 / db / data / { "extensions" : { }, "node" : "http://localhost:7474/db/data/node" , "node_index" : "http://localhost:7474/db/data/index/node" , "relationship_index" : "http://localhost:7474/db/data/index/relationship" , "extensions_info" : "http://localhost:7474/db/data/ext" , "relationship_types" : "http://localhost:7474/db/data/relationship/types" , "batch" : "http://localhost:7474/db/data/batch" , "cypher" : "http://localhost:7474/db/data/cypher" , "transaction" : "http://localhost:7474/db/data/transaction" , "neo4j_version" : "2.0.0-m03" } |
從這個端點(diǎn)返回json對象包含一組資源名稱和uri下可以找到的cypher端點(diǎn)。在消息載荷中接受傳送來的cyper請求并執(zhí)行這些查詢,在http響應(yīng)中返回結(jié)果。
正是這種rest api接口,使得現(xiàn)在已有的各種neo4j驅(qū)動得以建立。py2neo提供了這些rest資源的簡單封裝,這使python應(yīng)用程序開發(fā)者可以放心使用neo4j而不用考慮底層的客戶機(jī)-服務(wù)器協(xié)議。
一個簡單的應(yīng)用
為實(shí)際驗證py2neo,我們將著眼于建立一個簡單的用于存儲姓名和電子郵件地址的通訊錄管理系統(tǒng)。我們自然會使用節(jié)點(diǎn)來模擬每一個獨(dú)立實(shí)體,但它是要記住,neo4j沒有類型的概念。類型是從周圍的關(guān)系和屬性推斷來的。
下面的關(guān)系圖中人顯示為紅色、電子郵件地址節(jié)點(diǎn)顯示為藍(lán)色。這些當(dāng)然是純粹的邏輯演示節(jié)點(diǎn),但數(shù)據(jù)本身并沒有區(qū)別。
我們的應(yīng)用程序?qū)⑼瓿蓛蓚€功能:添加新的聯(lián)系人信息和檢索聯(lián)系人的完整列表。為此,我們將創(chuàng)建一個person類包裝py2neonodeobject,這使我們有一個底層處理的實(shí)現(xiàn)且留出用戶級的功能。上圖中的root節(jié)點(diǎn)是指上圖中一個固定的參考點(diǎn),我們沿著這個點(diǎn)開始。
讓我們直接看看代碼。下面是一個完整的小型應(yīng)用。這個程序允許添加新的名字與一個或者更多email地址相連接的以及提供了一個容易的方式來顯示這些連接信息的一個命令行工具。沒有參數(shù)的運(yùn)行是顯示使用模式,而且這個唯一的依賴只是需要一個本地未修改的neo4j實(shí)例(instance)而已。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function import sys from py2neo import neo4j, node, rel graph_db = neo4j.graphdatabaseservice() class person( object ): _root = graph_db.get_or_create_indexed_node( "reference" , "contacts" , "root" ) @classmethod def create( cls , name, * emails): person_node, _ = graph_db.create(node(name = name), rel( cls ._root, "person" , 0 )) for email in emails: graph_db.create(node(email = email), rel( cls ._root, "email" , 0 ), rel(person_node, "email" , 0 )) return person(person_node) @classmethod def get_all( cls ): return [person(person.end_node) for person in cls ._root.match( "person" )] def __init__( self , node): self ._node = node def __str__( self ): return self .name + "\n" + "\n" .join( " <{0}>" . format (email) for email in self .emails) @property def name( self ): return self ._node[ "name" ] @property def emails( self ): return [rel.end_node[ "email" ] for rel in self ._node.match( "email" )] if __name__ = = "__main__" : if len (sys.argv) < 2 : app = sys.argv[ 0 ] print ("usage: { 0 } add <name> <email> [<email>...]". format (app)) print (" { 0 } list ". format (app)) sys.exit() method = sys.argv[ 1 ] if method = = "add" : print (person.create( * sys.argv[ 2 :])) elif method = = "list" : for person in person.get_all(): print (person) else : print ("unknown command") |
在第09行上是第一行py2neo代碼,用來創(chuàng)建了一個graphdatabaseservice
對象。通過這個,我們就可以訪問使用neo4j server的大多數(shù)功能。可選一個uri傳遞到這個構(gòu)造器里,盡管如果什么都沒有提供,代而取之的是使用默認(rèn)的本地參數(shù)。也就是說下面兩行是完全相等的:
1
2
3
4
5
6
7
|
graph_db = neo4j.graphdatabaseservice() graph_db = neo4j.graphdatabaseservice (http: / / localhost: 7474 / db / data / ) |
第13行介紹了調(diào)用了get_or_create_indexed_node
,它提供一種在圖形里創(chuàng)建固定引用點(diǎn)的漂亮方式。傳統(tǒng)的neo4j索引允許節(jié)點(diǎn)和關(guān)系通過鍵值對訪問,而在這個代碼里我們使用了帶連接的關(guān)鍵字和root值的引用索引實(shí)例。在第一次執(zhí)行時,會創(chuàng)建一個新的節(jié)點(diǎn),而且在隨后的執(zhí)行中,這個節(jié)點(diǎn)(即root)會復(fù)用(reused)。
在第17行,我們看見了推薦的節(jié)點(diǎn)和關(guān)系抽象的標(biāo)記,以及接受和使用節(jié)點(diǎn)和關(guān)系抽象的create
方法。任意多的抽象都可以被傳遞到這個方法中,并且在單個批處理轉(zhuǎn)換中創(chuàng)建實(shí)體并以指定它們的順序作為一個列表返回。抽象節(jié)點(diǎn)用節(jié)點(diǎn)函數(shù)表示并帶有一些屬性,然而抽象關(guān)系使用rel
函數(shù)接受一個起始節(jié)點(diǎn),類型和終止節(jié)點(diǎn)。上下文中,其他節(jié)點(diǎn),關(guān)系起始和終止節(jié)點(diǎn)可能整合引用到在其他批處理中其他節(jié)點(diǎn)。在我們的例子中,我們把根節(jié)點(diǎn)連接到新創(chuàng)建的person節(jié)點(diǎn),否則就作為項目0(item 0)了。
這次我們在第24行和38行上以match方法形式和關(guān)系見面[@lesus 注: oschina代碼行數(shù)有問題。對應(yīng)于本文的第28和44行]。它試圖使用一個特殊的條件集合(set)標(biāo)識關(guān)系,然后使用列表(list)返回它們。這這些示例中,這個關(guān)系和person關(guān)系相匹配,從root節(jié)點(diǎn)和email關(guān)系開始到所給定的person節(jié)點(diǎn)。和cypher很相似,用來查詢包含match關(guān)鍵字的場景。
最后值得注意的一點(diǎn)是在上面的代碼中訪問節(jié)點(diǎn)屬性的方式只是其中一種簡單的方式。py2neo重寫了標(biāo)準(zhǔn)python的__getitem__和 __setitem__方法,通過方括號標(biāo)識來方便訪問任何屬性。這點(diǎn)在第34和38行上可以看到。[@lesus 注:對應(yīng)于本文的第39和44行]
小結(jié)
在那里(代碼行34和38)我們這樣做了,這顯示了它是如何快速簡易地在java環(huán)境之外拼湊出一個neo4j應(yīng)用程序,也顯示了py2neo是如何通過rest api來抽象出大多數(shù)沉重的負(fù)擔(dān)。這里的例子并沒有解決唯一性,盡管功能上提供了唯一索引和cypher create unique語句。django開發(fā)者可能也想要考慮一個層,如neomodel,它在py2neo頂層上表示了一個djangoesque orm-style 層。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對服務(wù)器之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
原文鏈接:https://blog.csdn.net/u010159842/article/details/78128823