sack(麻袋)
幫助人們更細緻有效地解決問題
在某些情況下,人們正在編寫使用路徑信息進行數據聚合的Gremlin遍歷。通常,人們將使用path()
然後再執行一些過濾以“減少”路徑中的數據獲得特定結果。
不幸的是,這是低效的,因爲路徑計算是昂貴的,且是不可以合併的,計算全部路徑再過濾相當耗資源和時間且笨拙。
原理
sack是相對於每個遍歷者的局部數據結構,與aggregate()/store()/group(x)/subgraph(x)...
全局數據結構不同。這意味着每個經過路徑的元素都配備了他自己的麻袋。
sack可以包含任何類型的數據結構:
- 原語:Int,Double,Long,Data...
- 集合:List,Set,Map
Sack的定義
此數據結構的定義應該放在遍歷對象之後:
gremlin>g.withSack(1.0). // Define a sack containing an initial double value
V().
...
gremlin>g.withSack([] as Set). // Define a sack containing an initial empty Set
V().
...
gremlin>g.withSack([1,2,3] as Set). // Define a sack containing a pre-initialized Set
V().
...
gremlin>g.withSack([] as List). // Define a sack containing an initial empty List
V().
...
gremlin>g.withSack([:]). // Define a sack containing an initial empty Map
V().
...
gremlin>g.withSack([:]. // Define a sack containing an initial empty Map
withDefault{key -> [] as List}). // with default values being an empty list
V().
...
該withSack()
Step的完整參數是 withSack(default_data_structure, split_operator, merge_operator)
split_operator:
當遍歷器面向分支並需要複製自身時,split運算符用於分割數據結構。示例:V().has("user","userId", "u861").out("rated")
。現在,從用戶頂點出現的遍歷與對不同電影的評級一樣多。因此,用戶頂點的sack結構得到重複merge_operator:
用於在所有遍歷器收斂到單個點時將不同的數據塊結構合併在一起。示例:g.V().hasLabel("movie").out("director").has("name", "Woody Allen")
。來自許多Movie頂點的遍歷正在收斂到單個Person頂點,即Woody Allen。頂點Woody Allen的麻袋是他電影中所有數據結構的合併。如果您沒有定義任何合併運算符,則無法合併
注意:對於原始數據類型,split operator == value copy。對於其他數據類型(如集合),如果未定義任何拆分運算符,則相同的對象引用將複製到所有分支遍歷器。因此,所有這些遍歷者將共享相同的數據結構。要非常小心
。。。
Sack().by()求正弦
gremlin> g.withSack(1).V(1).repeat(sack(sum).by(constant(1))).times(10).emit().sack().math('sin _')
==>0.9092974268256817
==>0.1411200080598672
==>-0.7568024953079282
==>-0.9589242746631385
==>-0.27941549819892586
==>0.6569865987187891
==>0.9893582466233818
==>0.4121184852417566
==>-0.5440211108893698
==>-0.9999902065507035
使用sack()進行復雜查詢
/**(43)
* 使用sack()進行復雜查詢示例
* */
//(1)
// 普通查詢
//Select all direct flights from SEA to SFO on 8/18/2017, departing time between 6:00 and 10:00 am
g.V().has('StationCode','SEA').
outE('routes').
has('LegEffectiveDate',lte(createDate(2017,8,18,0,0,0))).
has('LegDiscountinueDate',gte(createDate(2017,8,18,0,0,0))).
has('AircraftSTD',between(createTime(6,0,0),createTime(10,0,0))).
inV().
has('StationCode','SFO').path()
//(2)
// 使用sack
//Select all one-stop flights, with one hour connection time, from SFO to SDF on 8/18/2017, departing time between 6:00 and 10:00 am
g.withSack{[M:4472,C:getMaxConnectTime('US','US')]}{it.clone()}.
V().
has('StationCode','SFO').
outE('routes').
has('LegEffectiveDate',lte(createDate(2017,8,18,0,0,0))).
has('LegDiscountinueDate',gte(createDate(2017,8,18,0,0,0))).
has('FlyFri',true).
has('AircraftSTD',between(createTime(6,0,0),createTime(10,0,0))).
has('ToAirport',without('SDF')).
sack{m,e->m['M']=m['M']-e.value('FlightDistance');m['A1']=e.value('AircraftSTA');m}.
filter{it.sack()['M']>0}.
order().by('AircraftSTD',incr).
inV().
outE('routes').
has('LegEffectiveDate',lte(createDate(2017,8,18,0,0,0))).
has('LegDiscountinueDate',gte(createDate(2017,8,18,0,0,0))).
has('FlyFri',true).
has('ToAirport','SDF').
sack{m,e->m['M']=m['M']-e.value('FlightDistance');m['C']=m['C']-getConnectTime(m['A1'],e.value('AircraftSTD'));m}.
filter{it.sack()['M']>0 && it.sack()['C']>0 && it.get().value('AircraftSTD').after(addTime(it.sack()['A1'],0,60,0))}.
inV().
path().
filter{passCabotage([it.get()[0].value('CountryCode'),it.get()[2].value('CountryCode'),it.get()[4].value('CountryCode')])
and passNextDay(it.get()[1].value('AircraftSTD'),it.get()[1].value('AircraftSTA'))}
未完待續。。。