原文作者:ITRoad
原文地址:原文鏈接
摘抄申明:我們不占有不侵權(quán)民轴,我們只是好文的搬運工!轉(zhuǎn)發(fā)請帶上原文申明。
Gremlin簡介
Gremlin是Apache TinkerPop 框架下的圖遍歷語言。Gremlin是一種函數(shù)式數(shù)據(jù)流語言须板,可以使得用戶使用簡潔的方式表述復(fù)雜的屬性圖(property graph)的遍歷或查詢。每個Gremlin遍歷由一系列步驟(可能存在嵌套)組成兢卵,每一步都在數(shù)據(jù)流(data stream)上執(zhí)行一個原子操作习瑰。
Gremlin包括三個基本的操作:
- map-step
對數(shù)據(jù)流中的對象進行轉(zhuǎn)換; - filter-step
對數(shù)據(jù)流中的對象就行過濾秽荤; - sideEffect-step
對數(shù)據(jù)流進行計算統(tǒng)計甜奄;
以下是Gremlin在一些場景中的具體應(yīng)用:
- 1.查找Gremlin朋友的朋友
g.V().has("name","gremlin").
out("knows").
out("knows").
values("name")
- 2.查找那些由兩個朋友共同創(chuàng)建的項目
g.V().match(
as("a").out("knows").as("b"),
as("a").out("created").as("c"),
as("b").out("created").as("c"),
as("c").in("created").count().is(2)).
select("c").by("name")
- 3.給出Gremlin的所有上司柠横,直至CEO
g.V().has("name","gremlin").
repeat(in("manages")).
until(has("title","ceo")).
path().by("name")
- 4.獲得Gremlin合作者的頭銜分布
g.V().has("name","gremlin").as("a").
out("created").in("created").
where(neq("a")).
groupCount().by("title")
- 5.獲取Gremlin購買產(chǎn)品的相關(guān)產(chǎn)品列表并排序
g.V().has("name","gremlin").
out("bought").aggregate("stash").
in("bought").out("bought").
where(not(within("stash"))).
groupCount().order(local).by(values,decr)
- 6.獲取排名前十的中心人物
g.V().hasLabel("person").
pageRank().
by("friendRank").
by(outE("knows")).
order().by("friendRank",decr).
limit(10)
OLTP 和 OLAP遍歷
一次編寫,到處運行
Gremlin遵循“一次編寫课兄,到處運行”的設(shè)計哲學(xué)牍氛。這意味著不僅所有的TinkerPop啟用的圖形系統(tǒng)都能執(zhí)行Gremlin遍歷,而且每個Gremlin遍歷都可以被評估為實時數(shù)據(jù)庫查詢或批處理查詢烟阐。(前者被稱為在線交易流程(OLTP)搬俊,后者被稱為在線分析流程(OLAP))。協(xié)調(diào)多種圖遍歷
這種普遍性是由Gremlin遍歷機實現(xiàn)的蜒茄。這種分布式唉擂、基于圖形的虛擬機了解如何協(xié)調(diào)多機器圖遍歷的執(zhí)行。好處是檀葛,用戶不需要學(xué)習數(shù)據(jù)庫查詢語言和域特定的BigData分析語言(例如Spark DSL玩祟,MapReduce等)。Gremlin是構(gòu)建基于圖的應(yīng)用程序所必要的屿聋,其余一切都交給Gremlin遍歷機處理空扎。
命令式和聲明式遍歷
Gremlin遍歷可以以命令式(程序式)方式,聲明性(描述性)方式編寫润讥,也可以包含命令性和聲明性的混合方式編寫转锈。
- 命令式編寫方式
獲得Gremlin合作者的上司名字分布:
g.V().has("name","gremlin").as("a").
out("created").in("created").
where(neq("a")).
in("manages").
groupCount().by("name")
一個命令式的Gremlin遍歷告訴運行器如何執(zhí)行遍歷中的每一步;然后楚殿,遍歷器分裂到所有的“Gremlin”的合作者(去除Gremlin自己)黑忱;下一步,遍歷器走到“Gremlin”合作者的上司(managers)勒魔,最終根據(jù)上司的名字進行統(tǒng)計分發(fā)。
之所以是命令式的Gremlin遍歷菇曲,就是它明確地冠绢、程序化地告訴遍歷器“去這里,然后去那里”常潮。
- 聲明式編寫方式
以下使用聲明式編寫方式實現(xiàn)了同樣的結(jié)果:
g.V().match(
as("a").has("name","gremlin"),
as("a").out("created").as("b"),
as("b").in("created").as("c"),
as("c").in("manages").as("d"),
where("a",neq("c"))).
select("d").
groupCount().by("name")
聲明式的Gremlin遍歷并不能告訴遍歷器執(zhí)行它們的步驟的順序弟胀,而是允許每個遍歷器從一個(可能嵌套的)模式的集合中選擇一個模式來執(zhí)行。
然而喊式,聲明遍歷具有額外的好處孵户,它不僅利用了編譯時查詢計劃器(如命令式遍歷),而且還是一個運行時查詢計劃器岔留,根據(jù)每個模式的歷史統(tǒng)計信息選擇下一個執(zhí)行哪個遍歷模式 - 有利于那些傾向于減少/過濾大多數(shù)數(shù)據(jù)的模式夏哭。
用戶可以選擇上述提出的方式編寫自己的遍歷語句。不管怎樣献联,用戶的遍歷語句都會根據(jù)具體的執(zhí)行引擎和遍歷策略traversal strategies被重寫竖配。Gremlin為用戶提供靈活性表達自己的查詢的何址;圖系統(tǒng)也針對具體啟用TinkerPop的數(shù)據(jù)系統(tǒng)進行有效地評估圖遍歷提供了靈活性。
無縫嵌入主語言
統(tǒng)一主開發(fā)語言和圖查詢語言
經(jīng)典數(shù)據(jù)庫查詢語言(如SQL)被認為與最終在生產(chǎn)環(huán)境中使用的編程語言截然不同进胯。因此用爪,經(jīng)典數(shù)據(jù)庫要求開發(fā)人員既要編寫主編程語言,還要編寫數(shù)據(jù)庫相應(yīng)的查詢語言胁镐。Gremlin統(tǒng)一了這個劃分偎血,因為遍歷可以用支持功能組合和嵌套(主要編程語言都支持)的任何編程語言編寫。因此盯漂,用戶的Gremlin遍歷可以使用應(yīng)用程序語言(主語言颇玷,Host language)編寫,并受益于主語言及其工具(例如類型檢查宠能,語法高亮亚隙,點完成等)所提供的優(yōu)點。目前存在各種Gremlin語言變體违崇,包括:Gremlin-Java阿弃,Gremlin-Groovy,Gremlin-Python羞延,Gremlin-Scala等渣淳。示例程序
比較以下兩種方式,高低立判:
public class GremlinTinkerPopExample {
public void run(String name, String property) {
Graph graph = GraphFactory.open(...);
GraphTraversalSource g = graph.traversal();
double avg = g.V().has("name",name).
out("knows").out("created").
values(property).mean().next();
System.out.println("Average rating: " + avg);
}
}
public class SqlJdbcExample {
public void run(String name, String property) {
Connection connection = DriverManager.getConnection(...)
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(
"SELECT AVG(pr." + property + ") as AVERAGE FROM PERSONS p1" +
"INNER JOIN KNOWS k ON k.person1 = p1.id " +
"INNER JOIN PERSONS p2 ON p2.id = k.person2 " +
"INNER JOIN CREATED c ON c.person = p2.id " +
"INNER JOIN PROJECTS pr ON pr.id = c.project " +
"WHERE p.name = '" + name + "');
System.out.println("Average rating: " + result.next().getDouble("AVERAGE")
}
}